[vim/vim] Make it possible to force generic sh syntax highlighting (Issue #17084)

16 views
Skip to first unread message

David Mandelberg

unread,
Apr 8, 2025, 3:23:19 PM4/8/25
to vim/vim, Subscribed

Is your feature request about something that is currently impossible or hard to do? Please describe the problem.

I'm trying to edit https://github.com/git/git/blob/9d22ac51228304102deb62f30c3ecba6377e1237/contrib/completion/git-prompt.sh which is a shell script designed to run under multiple posix-like shells. (See the comment Compatibility with other shells (beyond bash/zsh) for details.)

When I first open it, vim detects it as zsh, which isn't quite right, but is understandable given that the first line includes the word zsh.

If I run let b:is_posix = 1 | setf sh, it then switches to bash syntax highlighting and echo b:is_bash shows 1.

It looks like the syntax code always uses a more specific shell if it finds it on the first line:

https://github.com/vim/vim/blob/520a2c7852e1f8798fa1cfbe7a7579982145daa1/runtime/syntax/sh.vim#L25-L31

In most cases that's probably reasonable, but in this case I don't want bash or any other more specific shell's syntax highlighting, since the script is designed to run under a wider range of shells.

Describe the solution you'd like

The simplest option I can think of is a new variable b:sh_no_detection or similar that disables all attempts to detect what type of shell script it is. Then I could run let b:sh_no_detection = 1 | let b:is_sh = 1 | setf sh to get generic sh highlighting.

Describe alternatives you've considered

Maybe it would be possible to improve automatic detection for git-prompt.sh and similar scripts, but I'm not sure how easy that would be.

Additional context

N/A


Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/17084@github.com>

dseomn created an issue (vim/vim#17084)

Is your feature request about something that is currently impossible or hard to do? Please describe the problem.

I'm trying to edit https://github.com/git/git/blob/9d22ac51228304102deb62f30c3ecba6377e1237/contrib/completion/git-prompt.sh which is a shell script designed to run under multiple posix-like shells. (See the comment Compatibility with other shells (beyond bash/zsh) for details.)

When I first open it, vim detects it as zsh, which isn't quite right, but is understandable given that the first line includes the word zsh.

If I run let b:is_posix = 1 | setf sh, it then switches to bash syntax highlighting and echo b:is_bash shows 1.

It looks like the syntax code always uses a more specific shell if it finds it on the first line:

https://github.com/vim/vim/blob/520a2c7852e1f8798fa1cfbe7a7579982145daa1/runtime/syntax/sh.vim#L25-L31

In most cases that's probably reasonable, but in this case I don't want bash or any other more specific shell's syntax highlighting, since the script is designed to run under a wider range of shells.

Describe the solution you'd like

The simplest option I can think of is a new variable b:sh_no_detection or similar that disables all attempts to detect what type of shell script it is. Then I could run let b:sh_no_detection = 1 | let b:is_sh = 1 | setf sh to get generic sh highlighting.

Describe alternatives you've considered

Maybe it would be possible to improve automatic detection for git-prompt.sh and similar scripts, but I'm not sure how easy that would be.

Additional context

N/A


Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/17084@github.com>

Aliaksei Budavei

unread,
Apr 8, 2025, 5:59:36 PM4/8/25
to vim/vim, Subscribed

A name in a shebang line ought to checked, not a name in
a line:

diff --git a/runtime/autoload/dist/ft.vim b/runtime/autoload/dist/ft.vim
index a74030522..0e54906b3 100644
--- a/runtime/autoload/dist/ft.vim
+++ b/runtime/autoload/dist/ft.vim
@@ -875,16 +875,16 @@ export def SetFileTypeSH(name: string, setft = true): string
   if setft && expand("<amatch>") =~ g:ft_ignore_pat
     return ''
   endif
-  if name =~ '\<csh\>'
+  if name =~ '^csh$' || name =~ '^#!.\{-2,}\<csh\>'
     # Some .sh scripts contain #!/bin/csh.
     return SetFileTypeShell("csh", setft)
-  elseif name =~ '\<tcsh\>'
+  elseif name =~ '^tcsh$' || name =~ '^#!.\{-2,}\<tcsh\>'
     # Some .sh scripts contain #!/bin/tcsh.
     return SetFileTypeShell("tcsh", setft)
-  elseif name =~ '\<zsh\>'
+  elseif name =~ '^zsh$' || name =~ '^#!.\{-2,}\<zsh\>'
     # Some .sh scripts contain #!/bin/zsh.
     return SetFileTypeShell("zsh", setft)
-  elseif name =~ '\<ksh\>'
+  elseif name =~ '^ksh$' || name =~ '^#!.\{-2,}\<ksh\>'
     b:is_kornshell = 1
     if exists("b:is_bash")
       unlet b:is_bash
@@ -892,7 +892,8 @@ export def SetFileTypeSH(name: string, setft = true): string
     if exists("b:is_sh")
       unlet b:is_sh
     endif
-  elseif exists("g:bash_is_sh") || name =~ '\<bash\>' || name =~ '\<bash2\>'
+  elseif exists("g:bash_is_sh") || name =~ '^bash2\=$' ||
+	  \ name =~ '^#!.\{-2,}\<bash2\=\>'
     b:is_bash = 1
     if exists("b:is_kornshell")
       unlet b:is_kornshell
@@ -900,7 +901,7 @@ export def SetFileTypeSH(name: string, setft = true): string
     if exists("b:is_sh")
       unlet b:is_sh
     endif
-  elseif name =~ '\<sh\>' || name =~ '\<dash\>'
+  elseif name =~ '^\%(da\)sh$' || name =~ '^#!.\{-2,}\<\%(da\)sh\>'
     # Ubuntu links "sh" to "dash", thus it is expected to work the same way
     b:is_sh = 1
     if exists("b:is_kornshell")
diff --git a/runtime/syntax/sh.vim b/runtime/syntax/sh.vim
index 298198274..ddf1015fb 100644
--- a/runtime/syntax/sh.vim
+++ b/runtime/syntax/sh.vim
@@ -23,11 +23,13 @@ endif
 let b:is_sh = 1
 
 " If the shell script itself specifies which shell to use, use it
-if getline(1) =~ '\<ksh\>'
+let s:shebang = getline(1)
+
+if s:shebang =~ '^#!.\{-2,}\<ksh\>'
  let b:is_kornshell = 1
-elseif getline(1) =~ '\<bash\>'
+elseif s:shebang =~ '^#!.\{-2,}\<bash\>'
  let b:is_bash      = 1
-elseif getline(1) =~ '\<dash\>'
+elseif s:shebang =~ '^#!.\{-2,}\<dash\>'
  let b:is_dash      = 1
 " handling /bin/sh with is_kornshell/is_sh {{{1
 " b:is_sh will be set when "#! /bin/sh" is found;
@@ -70,6 +72,8 @@ elseif !exists("b:is_kornshell") && !exists("b:is_bash") && !exists("b:is_posix"
  endif
 endif
 
+unlet s:shebang
+
 " if b:is_dash, set b:is_posix too
 if exists("b:is_dash")
  let b:is_posix= 1

And g:is_posix defined:

VIMRUNTIME=runtime vim --cmd 'let g:is_posix = 1' /tmp/git-prompt.sh


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/17084/2787753142@github.com>

zzzyxwvut left a comment (vim/vim#17084)

A name in a shebang line ought to checked, not a name in
a line:

diff --git a/runtime/autoload/dist/ft.vim b/runtime/autoload/dist/ft.vim
index a74030522..0e54906b3 100644
--- a/runtime/autoload/dist/ft.vim
+++ b/runtime/autoload/dist/ft.vim
@@ -875,16 +875,16 @@ export def SetFileTypeSH(name: string, setft = true): string
   if setft && expand("<amatch>") =~ g:ft_ignore_pat
     return ''
   endif
-  if name =~ '\<csh\>'
+  if name =~ '^csh$' || name =~ '^#!.\{-2,}\<csh\>'
     # Some .sh scripts contain #!/bin/csh.
     return SetFileTypeShell("csh", setft)
-  elseif name =~ '\<tcsh\>'
+  elseif name =~ '^tcsh$' || name =~ '^#!.\{-2,}\<tcsh\>'
     # Some .sh scripts contain #!/bin/tcsh.
     return SetFileTypeShell("tcsh", setft)
-  elseif name =~ '\<zsh\>'
+  elseif name =~ '^zsh$' || name =~ '^#!.\{-2,}\<zsh\>'
     # Some .sh scripts contain #!/bin/zsh.
     return SetFileTypeShell("zsh", setft)
-  elseif name =~ '\<ksh\>'
+  elseif name =~ '^ksh$' || name =~ '^#!.\{-2,}\<ksh\>'
     b:is_kornshell = 1
     if exists("b:is_bash")
       unlet b:is_bash
@@ -892,7 +892,8 @@ export def SetFileTypeSH(name: string, setft = true): string
     if exists("b:is_sh")
       unlet b:is_sh
     endif
-  elseif exists("g:bash_is_sh") || name =~ '\<bash\>' || name =~ '\<bash2\>'
+  elseif exists("g:bash_is_sh") || name =~ '^bash2\=$' ||
+	  \ name =~ '^#!.\{-2,}\<bash2\=\>'
     b:is_bash = 1
     if exists("b:is_kornshell")
       unlet b:is_kornshell
@@ -900,7 +901,7 @@ export def SetFileTypeSH(name: string, setft = true): string
     if exists("b:is_sh")
       unlet b:is_sh
     endif
-  elseif name =~ '\<sh\>' || name =~ '\<dash\>'
+  elseif name =~ '^\%(da\)sh$' || name =~ '^#!.\{-2,}\<\%(da\)sh\>'
     # Ubuntu links "sh" to "dash", thus it is expected to work the same way
     b:is_sh = 1
     if exists("b:is_kornshell")
diff --git a/runtime/syntax/sh.vim b/runtime/syntax/sh.vim
index 298198274..ddf1015fb 100644
--- a/runtime/syntax/sh.vim
+++ b/runtime/syntax/sh.vim
@@ -23,11 +23,13 @@ endif
 let b:is_sh = 1
 
 " If the shell script itself specifies which shell to use, use it
-if getline(1) =~ '\<ksh\>'
+let s:shebang = getline(1)
+
+if s:shebang =~ '^#!.\{-2,}\<ksh\>'
  let b:is_kornshell = 1
-elseif getline(1) =~ '\<bash\>'
+elseif s:shebang =~ '^#!.\{-2,}\<bash\>'
  let b:is_bash      = 1
-elseif getline(1) =~ '\<dash\>'
+elseif s:shebang =~ '^#!.\{-2,}\<dash\>'
  let b:is_dash      = 1
 " handling /bin/sh with is_kornshell/is_sh {{{1
 " b:is_sh will be set when "#! /bin/sh" is found;
@@ -70,6 +72,8 @@ elseif !exists("b:is_kornshell") && !exists("b:is_bash") && !exists("b:is_posix"
  endif
 endif
 
+unlet s:shebang
+
 " if b:is_dash, set b:is_posix too
 if exists("b:is_dash")
  let b:is_posix= 1

And g:is_posix defined:

VIMRUNTIME=runtime vim --cmd 'let g:is_posix = 1' /tmp/git-prompt.sh


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/17084/2787753142@github.com>

David Mandelberg

unread,
Apr 8, 2025, 7:30:23 PM4/8/25
to vim/vim, Subscribed

Any particular reason for the requirement for 2+ characters before the shell in ^#!.\{-2,}? I'm pretty sure I've seen pseudo-shebang lines like #!bash or #! bash before. I think they were meant specifically for editors that try to guess the filetype, though I never really looked into it.

https://codesearch.debian.net/search?q=%5CA%23%21+%3Fbash&literal=0 has some examples. Some of those have extra options like #!bash -x so maybe bash or something else parses that?


Reply to this email directly, view it on GitHub.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/17084/2787861550@github.com>

dseomn left a comment (vim/vim#17084)

Any particular reason for the requirement for 2+ characters before the shell in ^#!.\{-2,}? I'm pretty sure I've seen pseudo-shebang lines like #!bash or #! bash before. I think they were meant specifically for editors that try to guess the filetype, though I never really looked into it.

https://codesearch.debian.net/search?q=%5CA%23%21+%3Fbash&literal=0 has some examples. Some of those have extra options like #!bash -x so maybe bash or something else parses that?


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/17084/2787861550@github.com>

Christian Brabandt

unread,
Apr 9, 2025, 1:13:56 PM4/9/25
to vim/vim, Subscribed

I'm pretty sure I've seen pseudo-shebang lines like #!bash or #! bash before. I think they were meant specifically for editors that try to guess the filetype, though I never really looked into it.

That looks like bad style however. I would always expect a path here (whether an absolute path for the shell or using the env trick) and it seems the kernel also expects a full path


Reply to this email directly, view it on GitHub.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/17084/2790425183@github.com>

chrisbra left a comment (vim/vim#17084)

I'm pretty sure I've seen pseudo-shebang lines like #!bash or #! bash before. I think they were meant specifically for editors that try to guess the filetype, though I never really looked into it.

That looks like bad style however. I would always expect a path here (whether an absolute path for the shell or using the env trick) and it seems the kernel also expects a full path


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/17084/2790425183@github.com>

Aliaksei Budavei

unread,
Apr 9, 2025, 2:05:45 PM4/9/25
to vim/vim, Subscribed

I had in mind #!./sh etc. But I agree that #!sh should be
recognisable for the cases when a script is meant to be
sourced rather than executed, and it is desirable to have
a shebang line for file detection and syntax highlighting.

The use of ^csh$ etc. is done to satisfy all current call
sites for SetFileTypeSH() without changing its signature:

https://github.com/vim/vim/blob/96a0b2a6d5107580398435e263bd529d4ba3df49/runtime/autoload/dist/script.vim#L69-L70

https://github.com/vim/vim/blob/96a0b2a6d5107580398435e263bd529d4ba3df49/runtime/filetype.vim#L2328-L2333

https://github.com/vim/vim/blob/96a0b2a6d5107580398435e263bd529d4ba3df49/runtime/filetype.vim#L2337-L2343

https://github.com/vim/vim/blob/96a0b2a6d5107580398435e263bd529d4ba3df49/runtime/filetype.vim#L3258-L3261


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/17084/2790537567@github.com>

zzzyxwvut left a comment (vim/vim#17084)

I had in mind #!./sh etc. But I agree that #!sh should be
recognisable for the cases when a script is meant to be
sourced rather than executed, and it is desirable to have
a shebang line for file detection and syntax highlighting.

The use of ^csh$ etc. is done to satisfy all current call
sites for SetFileTypeSH() without changing its signature:

https://github.com/vim/vim/blob/96a0b2a6d5107580398435e263bd529d4ba3df49/runtime/autoload/dist/script.vim#L69-L70

https://github.com/vim/vim/blob/96a0b2a6d5107580398435e263bd529d4ba3df49/runtime/filetype.vim#L2328-L2333

https://github.com/vim/vim/blob/96a0b2a6d5107580398435e263bd529d4ba3df49/runtime/filetype.vim#L2337-L2343

https://github.com/vim/vim/blob/96a0b2a6d5107580398435e263bd529d4ba3df49/runtime/filetype.vim#L3258-L3261


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/17084/2790537567@github.com>

Christian Brabandt

unread,
Apr 10, 2025, 3:51:47 PM4/10/25
to vim/vim, Subscribed

Alright, thanks. Let me include it then


Reply to this email directly, view it on GitHub.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/17084/2795012464@github.com>

chrisbra left a comment (vim/vim#17084)

Alright, thanks. Let me include it then


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/17084/2795012464@github.com>

Christian Brabandt

unread,
Apr 10, 2025, 3:57:19 PM4/10/25
to vim/vim, Subscribed

included as of 5c84d12


Reply to this email directly, view it on GitHub.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/17084/2795023153@github.com>

chrisbra left a comment (vim/vim#17084)

included as of 5c84d12


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/17084/2795023153@github.com>

Christian Brabandt

unread,
Apr 10, 2025, 3:57:21 PM4/10/25
to vim/vim, Subscribed

Closed #17084 as completed.


Reply to this email directly, view it on GitHub.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issue/17084/issue_event/17212771495@github.com>

Reply all
Reply to author
Forward
0 new messages