2222" 2026 Jan 15 highlight command switches that contain a digit
2323" 2026 Feb 11 improve support for KornShell function names and variables
2424" 2026 Feb 15 improve comment handling #19414
25+ " 2026 Mar 23 improve matching of function definitions #19638
2526" }}}
2627" Version: 208
2728" Former URL: http://www.drchip.org/astronaut/vim/index.html#SYNTAX_SH
@@ -261,7 +262,7 @@ syn cluster shErrorList contains=shDoError,shIfError,shInError,shCaseError,shEsa
261262if exists (" b:is_kornshell" ) || exists (" b:is_bash" )
262263 syn cluster ErrorList add =shDTestError
263264endif
264- syn cluster shArithParenList contains =shArithmetic,shArithParen,shCaseEsac,shComment,shDeref,shDerefVarArray,shDo,shDerefSimple,shEcho,shEscape,shExpr,shNumber,shOperator,shPosnParm,shExSingleQuote,shExDoubleQuote,shHereString,shRedir,shSingleQuote,shDoubleQuote,shStatement,shVariable,shAlias,shTest,shCtrlSeq,shSpecial,shParen,bashSpecialVariables,bashStatement,shIf,shFor,shFunctionKey,shFunctionOne,shFunctionTwo,shNamespaceOne
265+ syn cluster shArithParenList contains =shArithmetic,shArithParen,shCaseEsac,shComment,shDeref,shDerefVarArray,shDo,shDerefSimple,shEcho,shEscape,shExpr,shNumber,shOperator,shPosnParm,shExSingleQuote,shExDoubleQuote,shHereString,shRedir,shSingleQuote,shDoubleQuote,shStatement,shVariable,shAlias,shTest,shCtrlSeq,shSpecial,shParen,bashSpecialVariables,bashStatement,shIf,shFor
265266syn cluster shArithList contains =@shArithParenList,shParenError
266267syn cluster shBracketExprList contains =shCharClassOther,shCharClass,shCollSymb,shEqClass
267268syn cluster shCaseEsacList contains =shCaseStart,shCaseLabel,shCase,shCaseBar,shCaseIn,shComment,shDeref,shDerefSimple,shCaseCommandSub,shCaseExSingleQuote,shCaseSingleQuote,shCaseDoubleQuote,shCtrlSeq,@shErrorList,shStringSpecial,shCaseRange
@@ -278,7 +279,16 @@ syn cluster shDerefVarList contains=shDerefOffset,shDerefOp,shDerefVarArray,shDe
278279syn cluster shEchoList contains =shArithmetic,shBracketExpr,shCommandSub,shCommandSubBQ,shDerefVarArray,shSubshare,shValsub,shDeref,shDerefSimple,shEscape,shExSingleQuote,shExDoubleQuote,shSingleQuote,shDoubleQuote,shCtrlSeq,shEchoQuote
279280syn cluster shExprList1 contains =shBracketExpr,shNumber,shOperator,shExSingleQuote,shExDoubleQuote,shSingleQuote,shDoubleQuote,shExpr,shDblBrace,shDeref,shDerefSimple,shCtrlSeq
280281syn cluster shExprList2 contains =@shExprList1,@shCaseList,shTest
281- syn cluster shFunctionList contains =shBracketExpr,@shCommandSubList,shCaseEsac,shColon,shComment,shDo,shEcho,shExpr,shFor,shHereDoc,shIf,shOption,shHereString,shRedir,shSetList,shSource,shStatement,shVariable,shOperator,shCtrlSeq
282+ syn cluster shFunctionCmds contains =shFor,shCaseEsac,shIf,shRepeat,shDblBrace,shDblParen
283+ if exists (" b:is_ksh88" ) || exists (" b:is_mksh" )
284+ " Offer "shFunctionCmds" as is.
285+ elseif exists (" b:is_kornshell" ) || exists (" b:is_bash" )
286+ syn cluster shFunctionCmds add =shForPP
287+ else
288+ syn cluster shFunctionCmds remove =shDblBrace,shDblParen
289+ endif
290+ syn cluster shFunctionDefList contains =shDoError,shIfError,shFunctionKey,shFunctionOne,shFunctionThree,shFunctionCmdOne
291+ syn cluster shFunctionList contains =shBracketExpr,@shCommandSubList,shCaseEsac,shColon,shComment,shDo,shEcho,shExpr,shFor,shHereDoc,shIf,shOption,shHereString,shRedir,shSetList,shSource,shStatement,shVariable,shOperator,shCtrlSeq,@shFunctionDefList
282292if exists (" b:is_kornshell" ) || exists (" b:is_bash" )
283293 syn cluster shFunctionList add =shRepeat,shDblBrace,shDblParen,shForPP
284294 syn cluster shDerefList add =shCommandSubList,shEchoDeref
@@ -287,7 +297,7 @@ syn cluster shHereBeginList contains=@shCommandSubList
287297syn cluster shHereList contains =shBeginHere,shHerePayload
288298syn cluster shHereListDQ contains =shBeginHere,@shDblQuoteList,shHerePayload
289299syn cluster shIdList contains =shArithmetic,shCommandSub,shCommandSubBQ,shDerefVarArray,shSubshare,shValsub,shWrapLineOperator,shSetOption,shComment,shDeref,shDerefSimple,shHereString,shNumber,shOperator,shRedir,shExSingleQuote,shExDoubleQuote,shSingleQuote,shDoubleQuote,shExpr,shCtrlSeq,shStringSpecial,shAtExpr
290- syn cluster shIfList contains =@shLoopList,shDblBrace,shDblParen,shFunctionKey,shFunctionOne,shFunctionTwo,shNamespaceOne
300+ syn cluster shIfList contains =@shLoopList,shDblBrace,shDblParen,@shFunctionDefList
291301syn cluster shLoopList contains =@shCaseList,@shErrorList,shCaseEsac,shConditional,shDblBrace,shExpr,shFor,shIf,shOption,shSet,shTest,shTestOpr,shTouch
292302if exists (" b:is_kornshell" ) || exists (" b:is_bash" )
293303 syn cluster shLoopList add =shForPP,shDblParen
@@ -647,39 +657,49 @@ endif
647657
648658" Functions: {{{1
649659if ! exists (" b:is_posix" )
650- syn keyword shFunctionKey function skipwhite skipnl nextgroup =shFunctionTwo
660+ syn keyword shFunctionKey function skipwhite skipnl nextgroup =shDoError,shIfError, shFunctionTwo,shFunctionFour,shFunctionCmdTwo
651661endif
652662
653663if exists (" b:is_bash" )
654664 syn keyword shFunctionKey coproc
655- ShFoldFunctions syn region shFunctionOne matchgroup= shFunction start = " ^\s *[A-Za-z_0-9:][-a-zA-Z_0-9:]*\s *()\_ s*{" end = " }" contains= @s hFunctionList skipwhite skipnl nextgroup= shFunctionStart,shQuickComment
656- ShFoldFunctions syn region shFunctionTwo matchgroup= shFunction start = " \% (do\)\@ !\&\< [A-Za-z_0-9:][-a-zA-Z_0-9:]*\>\s *\% (()\)\=\_ s*{" end = " }" contains= shFunctionKey,@s hFunctionList contained skipwhite skipnl nextgroup= shFunctionStart,shQuickComment
657- ShFoldFunctions syn region shFunctionThree matchgroup= shFunction start = " ^\s *[A-Za-z_0-9:][-a-zA-Z_0-9:]*\s *()\_ s*(" end = " )" contains= @s hFunctionList skipwhite skipnl nextgroup= shFunctionStart,shQuickComment
658- ShFoldFunctions syn region shFunctionFour matchgroup= shFunction start = " \% (do\)\@ !\&\< [A-Za-z_0-9:][-a-zA-Z_0-9:]*\>\s *\% (()\)\=\_ s*)" end = " )" contains= shFunctionKey,@s hFunctionList contained skipwhite skipnl nextgroup= shFunctionStart,shQuickComment
665+ syn match shFunctionCmdOne " ^\s *\z s\% (\<\k\+\| [^()<>|&$;\t ]\+\)\+\s *()\z e\_ s*\% (\% (for\| case\| select\| if\| while\| until\)\>\|\[\[\s\| ((\) " skipwhite skipnl nextgroup =@shFunctionCmds
666+ syn match shFunctionCmdTwo " \% (\<\k\+\>\| [^()<>|&$;\t ]\+\)\+\z e\s *\% (()\z e\)\=\_ s*\% (\<\% (for\| case\| select\| if\| while\| until\)\>\|\[\[\s\| ((\) " contained skipwhite skipnl nextgroup =@shFunctionCmds
667+ ShFoldFunctions syn region shFunctionOne matchgroup= shFunction start = " ^\s *\z s\% (\<\k\+\|[^()<> |&$;\t ]\+\)\+\s *()\_ s*{" end = " }" contains= @s hFunctionList skipwhite skipnl nextgroup= shQuickComment
668+ ShFoldFunctions syn region shFunctionTwo matchgroup= shFunction start = " \% (\<\k\+\|[^()<> |&$;\t ]\+\)\+\s *\% (()\)\=\_ s*{" end = " }" contains= shFunctionKey,@s hFunctionList contained skipwhite skipnl nextgroup= shQuickComment
669+ ShFoldFunctions syn region shFunctionThree matchgroup= shFunction start = " ^\s *\z s\% (\<\k\+\|[^()<> |&$;\t ]\+\)\+\s *()\_ s*((\@ !" end = " )" contains= @s hFunctionList skipwhite skipnl nextgroup= shQuickComment
670+ ShFoldFunctions syn region shFunctionFour matchgroup= shFunction start = " \% (\<\k\+\|[^()<> |&$;\t ]\+\)\+\s *\% (\% (()\)\=\)\@ >\_ s*((\@ !" end = " )" contains= shFunctionKey,@s hFunctionList contained skipwhite skipnl nextgroup= shQuickComment
659671elseif exists (" b:is_ksh88" )
660672 " AT&T ksh88
661- ShFoldFunctions syn region shFunctionOne matchgroup = shFunction start = " ^\s *[A-Za-z_][A-Za-z_0-9] *\s *()\_ s*{ " end = " } " contains = @s hFunctionList skipwhite skipnl nextgroup= shFunctionStart,shQuickComment
662- ShFoldFunctions syn region shFunctionTwo matchgroup= shFunction start = " \% (do \)\@ ! \&\< [A-Za-z_][A-Za-z_0-9]* \>\ _ s*{" end = " }" contains= shFunctionKey, @s hFunctionList contained skipwhite skipnl nextgroup= shFunctionStart, shQuickComment
663- ShFoldFunctions syn region shFunctionThree matchgroup= shFunction start = " ^ \s *[A-Za-z_][A-Za-z_0-9]* \s *() \ _ s*( " end = " ) " contains= @s hFunctionList skipwhite skipnl nextgroup= shFunctionStart, shQuickComment
664- ShFoldFunctions syn region shFunctionFour matchgroup= shFunction start = " \% (do \)\@ ! \&\< [A-Za-z_][A-Za-z_0-9]* \>\ _ s*(" end = " )" contains= shFunctionKey, @s hFunctionList contained skipwhite skipnl nextgroup= shFunctionStart, shQuickComment
673+ syn match shFunctionCmdOne " ^\s *\z s \h\w *\s *()\z e \ _ s*\% ( \% (for \| case \| select \| if \| while \| until \)\>\|\[\[\s\| (( \) " skipwhite skipnl nextgroup =@shFunctionCmds
674+ ShFoldFunctions syn region shFunctionOne matchgroup= shFunction start = " ^ \s * \z s \h\w * \s *() \ _ s*{" end = " }" contains= @s hFunctionList skipwhite skipnl nextgroup= shQuickComment
675+ ShFoldFunctions syn region shFunctionTwo matchgroup= shFunction start = " \<\h\w * \>\ _ s*{ " end = " } " contains= shFunctionKey, @s hFunctionList contained skipwhite skipnl nextgroup= shQuickComment
676+ ShFoldFunctions syn region shFunctionThree matchgroup= shFunction start = " ^ \s * \z s \h\w * \s *() \ _ s*(( \@ ! " end = " )" contains= @s hFunctionList skipwhite skipnl nextgroup= shQuickComment
665677elseif exists (" b:is_mksh" )
666678 " MirBSD ksh is the wild west of absurd and abstruse function names...
667- ShFoldFunctions syn region shFunctionOne matchgroup = shFunction start = " ^\s *[-A-Za-z_@!+.%,0-9:]*[-A-Za-z_.%,0-9:]\s *()\_ s*{ " end = " } " contains = @s hFunctionList skipwhite skipnl nextgroup= shFunctionStart,shQuickComment
668- ShFoldFunctions syn region shFunctionTwo matchgroup= shFunction start = " \% (do \)\@ ! \&\< [-A-Za-z_@!+.%,0-9:]*[-A-Za-z_.%,0-9:]\>\s * \% (() \)\=\ _ s*{" end = " }" contains= shFunctionKey, @s hFunctionList contained skipwhite skipnl nextgroup= shFunctionStart, shQuickComment
669- ShFoldFunctions syn region shFunctionThree matchgroup= shFunction start = " ^ \s *[-A-Za-z_ @!+.%,0-9:] *[-A-Za-z_.%,0-9:]\s *() \ _ s*( " end = " ) " contains= @s hFunctionList skipwhite skipnl nextgroup= shFunctionStart, shQuickComment
670- ShFoldFunctions syn region shFunctionFour matchgroup= shFunction start = " \% (do \)\@ ! \&\< [-A-Za-z_@!+.%,0-9:]*[-A-Za-z_.%,0-9:]\>\s * \% (() \)\=\ _ s*(" end = " )" contains= shFunctionKey, @s hFunctionList contained skipwhite skipnl nextgroup= shFunctionStart, shQuickComment
679+ syn match shFunctionCmdOne " ^\s *\z s [-A-Za-z_@!+.%,0-9:]*[-A-Za-z_.%,0-9:]\s *()\z e \ _ s*\% ( \% (for \| case \| select \| if \| while \| until \)\>\|\[\[\s\| (( \) " skipwhite skipnl nextgroup =@shFunctionCmds
680+ ShFoldFunctions syn region shFunctionOne matchgroup= shFunction start = " ^ \s * \z s [-A-Za-z_@!+.%,0-9:]*[-A-Za-z_.%,0-9:]\s *() \ _ s*{" end = " }" contains= @s hFunctionList skipwhite skipnl nextgroup= shQuickComment
681+ ShFoldFunctions syn region shFunctionTwo matchgroup= shFunction start = " \% ([ @!+.%,:-] \+\|\<\w\+\) *[-A-Za-z_.%,0-9:]\s *\% (() \)\=\ _ s*{ " end = " } " contains= shFunctionKey, @s hFunctionList contained skipwhite skipnl nextgroup= shQuickComment
682+ ShFoldFunctions syn region shFunctionThree matchgroup= shFunction start = " ^ \s * \z s [-A-Za-z_@!+.%,0-9:]*[-A-Za-z_.%,0-9:]\s *() \ _ s*(( \@ ! " end = " )" contains= @s hFunctionList skipwhite skipnl nextgroup= shQuickComment
671683elseif exists (" b:is_kornshell" )
672684 " ksh93
673- ShFoldFunctions syn region shFunctionOne matchgroup = shFunction start = " ^\s *[A-Za-z_.][A-Za-z_.0-9]*\s *()\_ s*{ " end = " } " contains = @s hFunctionList skipwhite skipnl nextgroup= shFunctionStart,shQuickComment
674- ShFoldFunctions syn region shFunctionTwo matchgroup= shFunction start = " \% (do \)\@ ! \&\< [A-Za-z_.][A-Za-z_.0-9]*\> \_ s*{" end = " }" contains= shFunctionKey, @s hFunctionList contained skipwhite skipnl nextgroup= shFunctionStart, shQuickComment
675- ShFoldFunctions syn region shFunctionThree matchgroup= shFunction start = " ^ \s *[A-Za-z_.] [A-Za-z_.0-9]*\s *() \ _ s*( " end = " ) " contains= @s hFunctionList skipwhite skipnl nextgroup= shFunctionStart, shQuickComment
676- ShFoldFunctions syn region shFunctionFour matchgroup= shFunction start = " \% (do \)\@ ! \&\< [A-Za-z_.][A-Za-z_.0-9]*\> \_ s*(" end = " )" contains= shFunctionKey, @s hFunctionList contained skipwhite skipnl nextgroup= shFunctionStart, shQuickComment
677- ShFoldFunctions syn region shNamespaceOne matchgroup= shFunction start = " \% (do \)\@ ! \&\ <\h\w *\>\_ s*{" end = " }" contains= shFunctionKey,@s hFunctionList contained skipwhite skipnl nextgroup= shFunctionStart, shQuickComment
685+ syn match shFunctionCmdOne " ^\s *\z s [A-Za-z_.][A-Za-z_.0-9]*\s *()\z e \ _ s*\% ( \% (for \| case \| select \| if \| while \| until \)\>\|\[\[\s\| (( \) " skipwhite skipnl nextgroup =@shFunctionCmds
686+ ShFoldFunctions syn region shFunctionOne matchgroup= shFunction start = " ^ \s * \z s [A-Za-z_.][A-Za-z_.0-9]*\s *() \_ s*{" end = " }" contains= @s hFunctionList skipwhite skipnl nextgroup= shQuickComment
687+ ShFoldFunctions syn region shFunctionTwo matchgroup= shFunction start = " \% ( \.\|\<\h\+\) [A-Za-z_.0-9]*\_ s*{ " end = " } " contains= shFunctionKey, @s hFunctionList contained skipwhite skipnl nextgroup= shQuickComment
688+ ShFoldFunctions syn region shFunctionThree matchgroup= shFunction start = " ^ \s * \z s [A-Za-z_.][A-Za-z_.0-9]*\s *() \_ s*(( \@ ! " end = " )" contains= @s hFunctionList skipwhite skipnl nextgroup= shQuickComment
689+ ShFoldFunctions syn region shNamespaceOne matchgroup= shFunction start = " \<\h\w *\>\_ s*{" end = " }" contains= shFunctionKey,@s hFunctionList contained skipwhite skipnl nextgroup= shQuickComment
678690else
679- ShFoldFunctions syn region shFunctionOne matchgroup= shFunction start = " ^\s *\h\w *\s *()\_ s*{" end = " }" contains= @s hFunctionList skipwhite skipnl nextgroup= shFunctionStart,shQuickComment
680- ShFoldFunctions syn region shFunctionTwo matchgroup= shFunction start = " \% (do\)\@ !\&\<\h\w *\>\s *\% (()\)\=\_ s*{" end = " }" contains= shFunctionKey,@s hFunctionList contained skipwhite skipnl nextgroup= shFunctionStart,shQuickComment
681- ShFoldFunctions syn region shFunctionThree matchgroup= shFunction start = " ^\s *\h\w *\s *()\_ s*(" end = " )" contains= @s hFunctionList skipwhite skipnl nextgroup= shFunctionStart,shQuickComment
682- ShFoldFunctions syn region shFunctionFour matchgroup= shFunction start = " \% (do\)\@ !\&\<\h\w *\>\s *\% (()\)\=\_ s*(" end = " )" contains= shFunctionKey,@s hFunctionList contained skipwhite skipnl nextgroup= shFunctionStart,shQuickComment
691+ syn match shFunctionCmdOne " ^\s *\z s\h\w *\s *()\z e\_ s*\% (for\| case\| if\| while\| until\)\> " skipwhite skipnl nextgroup =@shFunctionCmds
692+ syn match shFunctionCmdTwo " \<\h\w *\s *()\z e\_ s*\% (for\| case\| if\| while\| until\)\> " contained skipwhite skipnl nextgroup =@shFunctionCmds
693+ ShFoldFunctions syn region shFunctionOne matchgroup= shFunction start = " ^\s *\z s\h\w *\s *()\_ s*{" end = " }" contains= @s hFunctionList skipwhite skipnl nextgroup= shQuickComment
694+ ShFoldFunctions syn region shFunctionTwo matchgroup= shFunction start = " \<\h\w *\>\s *()\_ s*{" end = " }" contains= shFunctionKey,@s hFunctionList contained skipwhite skipnl nextgroup= shQuickComment
695+ ShFoldFunctions syn region shFunctionThree matchgroup= shFunction start = " ^\s *\z s\h\w *\s *()\_ s*(" end = " )" contains= @s hFunctionList skipwhite skipnl nextgroup= shQuickComment
696+ ShFoldFunctions syn region shFunctionFour matchgroup= shFunction start = " \<\h\w *\>\s *()\_ s*(" end = " )" contains= shFunctionKey,@s hFunctionList contained skipwhite skipnl nextgroup= shQuickComment
697+ endif
698+
699+ if ! exists (" g:sh_no_error" )
700+ syn match shDoError " \< do\% (ne\)\=\s *()"
701+ syn match shIfError " \< then\s *()"
702+ syn match shIfError " \< else\s *()"
683703endif
684704
685705" Parameter Dereferencing: {{{1
@@ -883,6 +903,8 @@ if !exists("skip_sh_syntax_inits")
883903 hi def link shEchoQuote shString
884904 hi def link shForPP shLoop
885905 hi def link shFunction Function
906+ hi def link shFunctionCmdOne shFunction
907+ hi def link shFunctionCmdTwo shFunction
886908 hi def link shEmbeddedEcho shString
887909 hi def link shEscape shCommandSub
888910 hi def link shExDoubleQuote shDoubleQuote
0 commit comments