1" Vim syntax file 2" Language: shell (sh) Korn shell (ksh) bash (sh) 3" Maintainer: Dr. Charles E. Campbell, Jr. <[email protected]> 4" Previous Maintainer: Lennart Schultz <[email protected]> 5" Last Change: Mar 19, 2012 6" Version: 122 7" URL: http://mysite.verizon.net/astronaut/vim/index.html#vimlinks_syntax 8" For options and settings, please use: :help ft-sh-syntax 9" This file includes many ideas from ?ric Brunet ([email protected]) 10 11" For version 5.x: Clear all syntax items {{{1 12" For version 6.x: Quit when a syntax file was already loaded 13if version < 600 14 syntax clear 15elseif exists("b:current_syntax") 16 finish 17endif 18 19" AFAICT "." should be considered part of the iskeyword. Using iskeywords in 20" syntax is dicey, so the following code permits the user to prevent/override 21" its setting. 22if exists("g:sh_isk") " override support 23 exe "setlocal isk=".g:sh_isk 24elseif !exists("g:sh_noisk") " prevent modification support 25 setlocal isk+=. 26endif 27 28" trying to answer the question: which shell is /bin/sh, really? 29if !exists("g:is_kornshell") && !exists("g:is_bash") && !exists("g:is_posix") && !exists("g:is_sh") 30 if executable("/bin/sh") 31 if resolve("/bin/sh") =~ 'bash$' 32 let g:is_bash= 1 33 elseif resolve("/bin/sh") =~ 'ksh$' 34 let g:is_ksh = 1 35 endif 36 elseif executable("/usr/bin/sh") 37 if resolve("/usr/bin//sh") =~ 'bash$' 38 let g:is_bash= 1 39 elseif resolve("/usr/bin//sh") =~ 'ksh$' 40 let g:is_ksh = 1 41 endif 42 endif 43endif 44 45" handling /bin/sh with is_kornshell/is_sh {{{1 46" b:is_sh is set when "#! /bin/sh" is found; 47" However, it often is just a masquerade by bash (typically Linux) 48" or kornshell (typically workstations with Posix "sh"). 49" So, when the user sets "g:is_bash", "g:is_kornshell", 50" or "g:is_posix", a b:is_sh is converted into b:is_bash/b:is_kornshell, 51" respectively. 52if !exists("b:is_kornshell") && !exists("b:is_bash") 53 if exists("g:is_posix") && !exists("g:is_kornshell") 54 let g:is_kornshell= g:is_posix 55 endif 56 if exists("g:is_kornshell") 57 let b:is_kornshell= 1 58 if exists("b:is_sh") 59 unlet b:is_sh 60 endif 61 elseif exists("g:is_bash") 62 let b:is_bash= 1 63 if exists("b:is_sh") 64 unlet b:is_sh 65 endif 66 else 67 let b:is_sh= 1 68 endif 69endif 70 71" set up default g:sh_fold_enabled {{{1 72if !exists("g:sh_fold_enabled") 73 let g:sh_fold_enabled= 0 74elseif g:sh_fold_enabled != 0 && !has("folding") 75 let g:sh_fold_enabled= 0 76 echomsg "Ignoring g:sh_fold_enabled=".g:sh_fold_enabled."; need to re-compile vim for +fold support" 77endif 78if !exists("s:sh_fold_functions") 79 let s:sh_fold_functions = 1 80endif 81if !exists("s:sh_fold_heredoc") 82 let s:sh_fold_heredoc = 2 83endif 84if !exists("s:sh_fold_ifdofor") 85 let s:sh_fold_ifdofor = 4 86endif 87if g:sh_fold_enabled && &fdm == "manual" 88 setlocal fdm=syntax 89endif 90 91" sh syntax is case sensitive {{{1 92syn case match 93 94" Clusters: contains=@... clusters {{{1 95"================================== 96syn cluster shErrorList contains=shDoError,shIfError,shInError,shCaseError,shEsacError,shCurlyError,shParenError,shTestError,shOK 97if exists("b:is_kornshell") 98 syn cluster ErrorList add=shDTestError 99endif 100syn cluster shArithParenList contains=shArithmetic,shCaseEsac,shDeref,shDerefSimple,shEcho,shEscape,shNumber,shOperator,shPosnParm,shExSingleQuote,shExDoubleQuote,shRedir,shSingleQuote,shDoubleQuote,shStatement,shVariable,shAlias,shTest,shCtrlSeq,shSpecial,shParen,bashSpecialVariables,bashStatement 101syn cluster shArithList contains=@shArithParenList,shParenError 102syn cluster shCaseEsacList contains=shCaseStart,shCase,shCaseBar,shCaseIn,shComment,shDeref,shDerefSimple,shCaseCommandSub,shCaseExSingleQuote,shCaseSingleQuote,shCaseDoubleQuote,shCtrlSeq,@shErrorList,shStringSpecial,shCaseRange 103syn cluster shCaseList contains=@shCommandSubList,shCaseEsac,shColon,shCommandSub,shComment,shDo,shEcho,shExpr,shFor,shHereDoc,shIf,shRedir,shSetList,shSource,shStatement,shVariable,shCtrlSeq 104"syn cluster shColonList contains=@shCaseList 105syn cluster shCommandSubList contains=shArithmetic,shDeref,shDerefSimple,shEscape,shNumber,shOperator,shPosnParm,shExSingleQuote,shSingleQuote,shExDoubleQuote,shDoubleQuote,shStatement,shVariable,shSubSh,shAlias,shTest,shCtrlSeq,shSpecial 106syn cluster shCurlyList contains=shNumber,shComma,shDeref,shDerefSimple,shDerefSpecial 107syn cluster shDblQuoteList contains=shCommandSub,shDeref,shDerefSimple,shPosnParm,shCtrlSeq,shSpecial 108syn cluster shDerefList contains=shDeref,shDerefSimple,shDerefVar,shDerefSpecial,shDerefWordError,shDerefPPS 109syn cluster shDerefVarList contains=shDerefOp,shDerefVarArray,shDerefOpError 110syn cluster shEchoList contains=shArithmetic,shCommandSub,shDeref,shDerefSimple,shExpr,shExSingleQuote,shExDoubleQuote,shSingleQuote,shDoubleQuote,shCtrlSeq,shEchoQuote 111syn cluster shExprList1 contains=shCharClass,shNumber,shOperator,shExSingleQuote,shExDoubleQuote,shSingleQuote,shDoubleQuote,shExpr,shDblBrace,shDeref,shDerefSimple,shCtrlSeq 112syn cluster shExprList2 contains=@shExprList1,@shCaseList,shTest 113syn cluster shFunctionList contains=@shCommandSubList,shCaseEsac,shColon,shCommandSub,shComment,shDo,shEcho,shExpr,shFor,shHereDoc,shIf,shOption,shRedir,shSetList,shSource,shStatement,shVariable,shOperator,shCtrlSeq 114if exists("b:is_kornshell") || exists("b:is_bash") 115 syn cluster shFunctionList add=shRepeat 116 syn cluster shFunctionList add=shDblBrace,shDblParen 117endif 118syn cluster shHereBeginList contains=@shCommandSubList 119syn cluster shHereList contains=shBeginHere,shHerePayload 120syn cluster shHereListDQ contains=shBeginHere,@shDblQuoteList,shHerePayload 121syn cluster shIdList contains=shCommandSub,shWrapLineOperator,shSetOption,shDeref,shDerefSimple,shRedir,shExSingleQuote,shExDoubleQuote,shSingleQuote,shDoubleQuote,shExpr,shCtrlSeq,shStringSpecial 122syn cluster shIfList contains=@shLoopList,shDblBrace,shDblParen,shFunctionKey,shFunctionOne,shFunctionTwo 123syn cluster shLoopList contains=@shCaseList,shTestOpr,shExpr,shDblBrace,shConditional,shCaseEsac,shTest,@shErrorList,shSet,shOption 124syn cluster shSubShList contains=@shCommandSubList,shCaseEsac,shColon,shCommandSub,shComment,shDo,shEcho,shExpr,shFor,shIf,shRedir,shSetList,shSource,shStatement,shVariable,shCtrlSeq,shOperator 125syn cluster shTestList contains=shCharClass,shComment,shCommandSub,shDeref,shDerefSimple,shExDoubleQuote,shDoubleQuote,shExpr,shNumber,shOperator,shExSingleQuote,shSingleQuote,shTestOpr,shTest,shCtrlSeq 126" Echo: {{{1 127" ==== 128" This one is needed INSIDE a CommandSub, so that `echo bla` be correct 129syn region shEcho matchgroup=shStatement start="\<echo\>" skip="\\$" matchgroup=shEchoDelim end="$" matchgroup=NONE end="[<>;&|()]"me=e-1 end="\d[<>]"me=e-2 end="\s#"me=e-2 contains=@shEchoList skipwhite nextgroup=shQuickComment 130syn region shEcho matchgroup=shStatement start="\<print\>" skip="\\$" matchgroup=shEchoDelim end="$" matchgroup=NONE end="[<>;&|()]"me=e-1 end="\d[<>]"me=e-2 end="\s#"me=e-2 contains=@shEchoList skipwhite nextgroup=shQuickComment 131syn match shEchoQuote contained '\%(\\\\\)*\\["`'()]' 132 133" This must be after the strings, so that ... \" will be correct 134syn region shEmbeddedEcho contained matchgroup=shStatement start="\<print\>" skip="\\$" matchgroup=shEchoDelim end="$" matchgroup=NONE end="[<>;&|`)]"me=e-1 end="\d[<>]"me=e-2 end="\s#"me=e-2 contains=shNumber,shExSingleQuote,shSingleQuote,shDeref,shDerefSimple,shSpecialVar,shOperator,shExDoubleQuote,shDoubleQuote,shCharClass,shCtrlSeq 135 136" Alias: {{{1 137" ===== 138if exists("b:is_kornshell") || exists("b:is_bash") 139 syn match shStatement "\<alias\>" 140 syn region shAlias matchgroup=shStatement start="\<alias\>\s\+\(\h[-._[:alnum:]]\+\)\@=" skip="\\$" end="\>\|`" 141 syn region shAlias matchgroup=shStatement start="\<alias\>\s\+\(\h[-._[:alnum:]]\+=\)\@=" skip="\\$" end="=" 142endif 143 144" Error Codes: {{{1 145" ============ 146if !exists("g:sh_no_error") 147 syn match shDoError "\<done\>" 148 syn match shIfError "\<fi\>" 149 syn match shInError "\<in\>" 150 syn match shCaseError ";;" 151 syn match shEsacError "\<esac\>" 152 syn match shCurlyError "}" 153 syn match shParenError ")" 154 syn match shOK '\.\(done\|fi\|in\|esac\)' 155 if exists("b:is_kornshell") 156 syn match shDTestError "]]" 157 endif 158 syn match shTestError "]" 159endif 160 161" Options: {{{1 162" ==================== 163syn match shOption "\s\zs[-+][-_a-zA-Z0-9]\+\>" 164syn match shOption "\s\zs--[^ \t$`'"|]\+" 165 166" File Redirection Highlighted As Operators: {{{1 167"=========================================== 168syn match shRedir "\d\=>\(&[-0-9]\)\=" 169syn match shRedir "\d\=>>-\=" 170syn match shRedir "\d\=<\(&[-0-9]\)\=" 171syn match shRedir "\d<<-\=" 172 173" Operators: {{{1 174" ========== 175syn match shOperator "<<\|>>" contained 176syn match shOperator "[!&;|]" contained 177syn match shOperator "\[[[^:]\|\]]" contained 178syn match shOperator "!\==" skipwhite nextgroup=shPattern 179syn match shPattern "\<\S\+\())\)\@=" contained contains=shExSingleQuote,shSingleQuote,shExDoubleQuote,shDoubleQuote,shDeref 180 181" Subshells: {{{1 182" ========== 183syn region shExpr transparent matchgroup=shExprRegion start="{" end="}" contains=@shExprList2 nextgroup=shMoreSpecial 184syn region shSubSh transparent matchgroup=shSubShRegion start="[^(]\zs(" end=")" contains=@shSubShList nextgroup=shMoreSpecial 185 186" Tests: {{{1 187"======= 188syn region shExpr matchgroup=shRange start="\[" skip=+\\\\\|\\$\|\[+ end="\]" contains=@shTestList,shSpecial 189syn region shTest transparent matchgroup=shStatement start="\<test\s" skip=+\\\\\|\\$+ matchgroup=NONE end="[;&|]"me=e-1 end="$" contains=@shExprList1 190syn match shTestOpr contained "<=\|>=\|!=\|==\|-.\>\|-\(nt\|ot\|ef\|eq\|ne\|lt\|le\|gt\|ge\)\>\|[!<>]" 191syn match shTestOpr contained '=' skipwhite nextgroup=shTestDoubleQuote,shTestSingleQuote,shTestPattern 192syn match shTestPattern contained '\w\+' 193syn match shTestDoubleQuote contained '\%(\%(\\\\\)*\\\)\@<!"[^"]*"' 194syn match shTestSingleQuote contained '\\.' 195syn match shTestSingleQuote contained "'[^']*'" 196if exists("b:is_kornshell") || exists("b:is_bash") 197 syn region shDblBrace matchgroup=Delimiter start="\[\[" skip=+\\\\\|\\$+ end="\]\]" contains=@shTestList 198 syn region shDblParen matchgroup=Delimiter start="((" skip=+\\\\\|\\$+ end="))" contains=@shTestList 199endif 200 201" Character Class In Range: {{{1 202" ========================= 203syn match shCharClass contained "\[:\(backspace\|escape\|return\|xdigit\|alnum\|alpha\|blank\|cntrl\|digit\|graph\|lower\|print\|punct\|space\|upper\|tab\):\]" 204 205" Loops: do, if, while, until {{{1 206" ====== 207if (g:sh_fold_enabled % (s:sh_fold_ifdofor * 2))/s:sh_fold_ifdofor 208 syn region shDo fold transparent matchgroup=shConditional start="\<do\>" matchgroup=shConditional end="\<done\>" contains=@shLoopList 209 syn region shIf fold transparent matchgroup=shConditional start="\<if\_s" matchgroup=shConditional skip=+-fi\>+ end="\<;\_s*then\>" end="\<fi\>" contains=@shIfList 210 syn region shFor fold matchgroup=shLoop start="\<for\_s" end="\<in\_s" end="\<do\>"me=e-2 contains=@shLoopList,shDblParen skipwhite nextgroup=shCurlyIn 211else 212 syn region shDo transparent matchgroup=shConditional start="\<do\>" matchgroup=shConditional end="\<done\>" contains=@shLoopList 213 syn region shIf transparent matchgroup=shConditional start="\<if\_s" matchgroup=shConditional skip=+-fi\>+ end="\<;\_s*then\>" end="\<fi\>" contains=@shIfList 214 syn region shFor matchgroup=shLoop start="\<for\_s" end="\<in\>" end="\<do\>"me=e-2 contains=@shLoopList,shDblParen skipwhite nextgroup=shCurlyIn 215endif 216if exists("b:is_kornshell") || exists("b:is_bash") 217 syn cluster shCaseList add=shRepeat 218 syn cluster shFunctionList add=shRepeat 219 syn region shRepeat matchgroup=shLoop start="\<while\_s" end="\<in\_s" end="\<do\>"me=e-2 contains=@shLoopList,shDblParen,shDblBrace 220 syn region shRepeat matchgroup=shLoop start="\<until\_s" end="\<in\_s" end="\<do\>"me=e-2 contains=@shLoopList,shDblParen,shDblBrace 221 syn region shCaseEsac matchgroup=shConditional start="\<select\s" matchgroup=shConditional end="\<in\>" end="\<do\>" contains=@shLoopList 222else 223 syn region shRepeat matchgroup=shLoop start="\<while\_s" end="\<do\>"me=e-2 contains=@shLoopList 224 syn region shRepeat matchgroup=shLoop start="\<until\_s" end="\<do\>"me=e-2 contains=@shLoopList 225endif 226syn region shCurlyIn contained matchgroup=Delimiter start="{" end="}" contains=@shCurlyList 227syn match shComma contained "," 228 229" Case: case...esac {{{1 230" ==== 231syn match shCaseBar contained skipwhite "\(^\|[^\\]\)\(\\\\\)*\zs|" nextgroup=shCase,shCaseStart,shCaseBar,shComment,shCaseExSingleQuote,shCaseSingleQuote,shCaseDoubleQuote 232syn match shCaseStart contained skipwhite skipnl "(" nextgroup=shCase,shCaseBar 233if (g:sh_fold_enabled % (s:sh_fold_ifdofor * 2))/s:sh_fold_ifdofor 234 syn region shCase fold contained skipwhite skipnl matchgroup=shSnglCase start="\%(\\.\|[^#$()'" \t]\)\{-}\zs)" end=";;" end="esac"me=s-1 contains=@shCaseList nextgroup=shCaseStart,shCase,shComment 235 syn region shCaseEsac fold matchgroup=shConditional start="\<case\>" end="\<esac\>" contains=@shCaseEsacList 236else 237 syn region shCase contained skipwhite skipnl matchgroup=shSnglCase start="\%(\\.\|[^#$()'" \t]\)\{-}\zs)" end=";;" end="esac"me=s-1 contains=@shCaseList nextgroup=shCaseStart,shCase,shComment 238 syn region shCaseEsac matchgroup=shConditional start="\<case\>" end="\<esac\>" contains=@shCaseEsacList 239endif 240syn keyword shCaseIn contained skipwhite skipnl in nextgroup=shCase,shCaseStart,shCaseBar,shComment,shCaseExSingleQuote,shCaseSingleQuote,shCaseDoubleQuote 241if exists("b:is_bash") 242 syn region shCaseExSingleQuote matchgroup=shQuote start=+\$'+ skip=+\\\\\|\\.+ end=+'+ contains=shStringSpecial,shSpecial skipwhite skipnl nextgroup=shCaseBar contained 243elseif !exists("g:sh_no_error") 244 syn region shCaseExSingleQuote matchgroup=Error start=+\$'+ skip=+\\\\\|\\.+ end=+'+ contains=shStringSpecial skipwhite skipnl nextgroup=shCaseBar contained 245endif 246syn region shCaseSingleQuote matchgroup=shQuote start=+'+ end=+'+ contains=shStringSpecial skipwhite skipnl nextgroup=shCaseBar contained 247syn region shCaseDoubleQuote matchgroup=shQuote start=+"+ skip=+\\\\\|\\.+ end=+"+ contains=@shDblQuoteList,shStringSpecial skipwhite skipnl nextgroup=shCaseBar contained 248syn region shCaseCommandSub start=+`+ skip=+\\\\\|\\.+ end=+`+ contains=@shCommandSubList skipwhite skipnl nextgroup=shCaseBar contained 249syn region shCaseRange matchgroup=Delimiter start=+\[+ skip=+\\\\+ end=+]+ contained 250 251" Misc: {{{1 252"====== 253syn match shWrapLineOperator "\\$" 254syn region shCommandSub start="`" skip="\\\\\|\\." end="`" contains=@shCommandSubList 255syn match shEscape contained '\\.' contains=@shCommandSubList 256 257" $() and $(()): {{{1 258" $(..) is not supported by sh (Bourne shell). However, apparently 259" some systems (HP?) have as their /bin/sh a (link to) Korn shell 260" (ie. Posix compliant shell). /bin/ksh should work for those 261" systems too, however, so the following syntax will flag $(..) as 262" an Error under /bin/sh. By consensus of vimdev'ers! 263if exists("b:is_kornshell") || exists("b:is_bash") 264 syn region shCommandSub matchgroup=shCmdSubRegion start="\$(" skip='\\\\\|\\.' end=")" contains=@shCommandSubList 265 syn region shArithmetic matchgroup=shArithRegion start="\$((" skip='\\\\\|\\.' end="))" contains=@shArithList 266 syn region shArithmetic matchgroup=shArithRegion start="\$\[" skip='\\\\\|\\.' end="\]" contains=@shArithList 267 syn match shSkipInitWS contained "^\s\+" 268elseif !exists("g:sh_no_error") 269 syn region shCommandSub matchgroup=Error start="\$(" end=")" contains=@shCommandSubList 270endif 271 272if exists("b:is_bash") 273 syn cluster shCommandSubList add=bashSpecialVariables,bashStatement 274 syn cluster shCaseList add=bashAdminStatement,bashStatement 275 syn keyword bashSpecialVariables contained auto_resume BASH BASH_ALIASES BASH_ALIASES BASH_ARGC BASH_ARGC BASH_ARGV BASH_ARGV BASH_CMDS BASH_CMDS BASH_COMMAND BASH_COMMAND BASH_ENV BASH_EXECUTION_STRING BASH_EXECUTION_STRING BASH_LINENO BASH_LINENO BASHOPTS BASHOPTS BASHPID BASHPID BASH_REMATCH BASH_REMATCH BASH_SOURCE BASH_SOURCE BASH_SUBSHELL BASH_SUBSHELL BASH_VERSINFO BASH_VERSION BASH_XTRACEFD BASH_XTRACEFD CDPATH COLUMNS COLUMNS COMP_CWORD COMP_CWORD COMP_KEY COMP_KEY COMP_LINE COMP_LINE COMP_POINT COMP_POINT COMPREPLY COMPREPLY COMP_TYPE COMP_TYPE COMP_WORDBREAKS COMP_WORDBREAKS COMP_WORDS COMP_WORDS COPROC COPROC DIRSTACK EMACS EMACS ENV ENV EUID FCEDIT FIGNORE FUNCNAME FUNCNAME FUNCNEST FUNCNEST GLOBIGNORE GROUPS histchars HISTCMD HISTCONTROL HISTFILE HISTFILESIZE HISTIGNORE HISTSIZE HISTTIMEFORMAT HISTTIMEFORMAT HOME HOSTFILE HOSTNAME HOSTTYPE IFS IGNOREEOF INPUTRC LANG LC_ALL LC_COLLATE LC_CTYPE LC_CTYPE LC_MESSAGES LC_NUMERIC LC_NUMERIC LINENO LINES LINES MACHTYPE MAIL MAILCHECK MAILPATH MAPFILE MAPFILE OLDPWD OPTARG OPTERR OPTIND OSTYPE PATH PIPESTATUS POSIXLY_CORRECT POSIXLY_CORRECT PPID PROMPT_COMMAND PS1 PS2 PS3 PS4 PWD RANDOM READLINE_LINE READLINE_LINE READLINE_POINT READLINE_POINT REPLY SECONDS SHELL SHELL SHELLOPTS SHLVL TIMEFORMAT TIMEOUT TMPDIR TMPDIR UID 276 syn keyword bashStatement chmod clear complete du egrep expr fgrep find gnufind gnugrep grep install less ls mkdir mv rm rmdir rpm sed sleep sort strip tail touch 277 syn keyword bashAdminStatement daemon killall killproc nice reload restart start status stop 278endif 279 280if exists("b:is_kornshell") 281 syn cluster shCommandSubList add=kshSpecialVariables,kshStatement 282 syn cluster shCaseList add=kshStatement 283 syn keyword kshSpecialVariables contained CDPATH COLUMNS EDITOR ENV ERRNO FCEDIT FPATH HISTFILE HISTSIZE HOME IFS LINENO LINES MAIL MAILCHECK MAILPATH OLDPWD OPTARG OPTIND PATH PPID PS1 PS2 PS3 PS4 PWD RANDOM REPLY SECONDS SHELL TMOUT VISUAL 284 syn keyword kshStatement cat chmod clear cp du egrep expr fgrep find grep install killall less ls mkdir mv nice printenv rm rmdir sed sort strip stty tail touch tput 285endif 286 287syn match shSource "^\.\s" 288syn match shSource "\s\.\s" 289"syn region shColon start="^\s*:" end="$" end="\s#"me=e-2 contains=@shColonList 290"syn region shColon start="^\s*\zs:" end="$" end="\s#"me=e-2 291syn match shColon '^\s*\zs:' 292 293" String And Character Constants: {{{1 294"================================ 295syn match shNumber "-\=\<\d\+\>#\=" 296syn match shCtrlSeq "\\\d\d\d\|\\[abcfnrtv0]" contained 297if exists("b:is_bash") 298 syn match shSpecial "\\\o\o\o\|\\x\x\x\|\\c[^"]\|\\[abefnrtv]" contained 299endif 300if exists("b:is_bash") 301 syn region shExSingleQuote matchgroup=shQuote start=+\$'+ skip=+\\\\\|\\.+ end=+'+ contains=shStringSpecial,shSpecial 302 syn region shExDoubleQuote matchgroup=shQuote start=+\$"+ skip=+\\\\\|\\.\|\\"+ end=+"+ contains=@shDblQuoteList,shStringSpecial,shSpecial 303elseif !exists("g:sh_no_error") 304 syn region shExSingleQuote matchGroup=Error start=+\$'+ skip=+\\\\\|\\.+ end=+'+ contains=shStringSpecial 305 syn region shExDoubleQuote matchGroup=Error start=+\$"+ skip=+\\\\\|\\.+ end=+"+ contains=shStringSpecial 306endif 307syn region shSingleQuote matchgroup=shQuote start=+'+ end=+'+ contains=@Spell 308syn region shDoubleQuote matchgroup=shQuote start=+\%(\%(\\\\\)*\\\)\@<!"+ skip=+\\"+ end=+"+ contains=@shDblQuoteList,shStringSpecial,@Spell 309"syn region shDoubleQuote matchgroup=shQuote start=+"+ skip=+\\"+ end=+"+ contains=@shDblQuoteList,shStringSpecial,@Spell 310syn match shStringSpecial "[^[:print:] \t]" contained 311syn match shStringSpecial "\%(\\\\\)*\\[\\"'`$()#]" 312syn match shSpecial "[^\\]\zs\%(\\\\\)*\\[\\"'`$()#]" nextgroup=shMoreSpecial 313syn match shSpecial "^\%(\\\\\)*\\[\\"'`$()#]" 314syn match shMoreSpecial "\%(\\\\\)*\\[\\"'`$()#]" nextgroup=shMoreSpecial contained 315 316" Comments: {{{1 317"========== 318syn cluster shCommentGroup contains=shTodo,@Spell 319syn keyword shTodo contained COMBAK FIXME TODO XXX 320syn match shComment "^\s*\zs#.*$" contains=@shCommentGroup 321syn match shComment "\s\zs#.*$" contains=@shCommentGroup 322syn match shQuickComment contained "#.*$" 323 324" Here Documents: {{{1 325" ========================================= 326if version < 600 327 syn region shHereDoc matchgroup=shRedir start="<<\s*\**END[a-zA-Z_0-9]*\**" matchgroup=shRedir end="^END[a-zA-Z_0-9]*$" contains=@shDblQuoteList 328 syn region shHereDoc matchgroup=shRedir start="<<-\s*\**END[a-zA-Z_0-9]*\**" matchgroup=shRedir end="^\s*END[a-zA-Z_0-9]*$" contains=@shDblQuoteList 329 syn region shHereDoc matchgroup=shRedir start="<<\s*\**EOF\**" matchgroup=shRedir end="^EOF$" contains=@shDblQuoteList 330 syn region shHereDoc matchgroup=shRedir start="<<-\s*\**EOF\**" matchgroup=shRedir end="^\s*EOF$" contains=@shDblQuoteList 331 syn region shHereDoc matchgroup=shRedir start="<<\s*\**\.\**" matchgroup=shRedir end="^\.$" contains=@shDblQuoteList 332 syn region shHereDoc matchgroup=shRedir start="<<-\s*\**\.\**" matchgroup=shRedir end="^\s*\.$" contains=@shDblQuoteList 333 334elseif (g:sh_fold_enabled % (s:sh_fold_heredoc * 2))/s:sh_fold_heredoc 335 syn region shHereDoc matchgroup=shRedir fold start="<<\s*\z(\S*\)" matchgroup=shRedir end="^\z1\s*$" contains=@shDblQuoteList 336 syn region shHereDoc matchgroup=shRedir fold start="<<\s*\"\z(\S*\)\"" matchgroup=shRedir end="^\z1\s*$" 337 syn region shHereDoc matchgroup=shRedir fold start="<<\s*'\z(\S*\)'" matchgroup=shRedir end="^\z1\s*$" 338 syn region shHereDoc matchgroup=shRedir fold start="<<-\s*\z(\S*\)" matchgroup=shRedir end="^\s*\z1\s*$" contains=@shDblQuoteList 339 syn region shHereDoc matchgroup=shRedir fold start="<<-\s*\"\z(\S*\)\"" matchgroup=shRedir end="^\s*\z1\s*$" 340 syn region shHereDoc matchgroup=shRedir fold start="<<-\s*'\z(\S*\)'" matchgroup=shRedir end="^\s*\z1\s*$" 341 syn region shHereDoc matchgroup=shRedir fold start="<<\s*\\\_$\_s*\z(\S*\)" matchgroup=shRedir end="^\z1\s*$" 342 syn region shHereDoc matchgroup=shRedir fold start="<<\s*\\\_$\_s*\"\z(\S*\)\"" matchgroup=shRedir end="^\z1\s*$" 343 syn region shHereDoc matchgroup=shRedir fold start="<<-\s*\\\_$\_s*'\z(\S*\)'" matchgroup=shRedir end="^\s*\z1\s*$" 344 syn region shHereDoc matchgroup=shRedir fold start="<<-\s*\\\_$\_s*\z(\S*\)" matchgroup=shRedir end="^\s*\z1\s*$" 345 syn region shHereDoc matchgroup=shRedir fold start="<<-\s*\\\_$\_s*\"\z(\S*\)\"" matchgroup=shRedir end="^\s*\z1\s*$" 346 syn region shHereDoc matchgroup=shRedir fold start="<<\s*\\\_$\_s*'\z(\S*\)'" matchgroup=shRedir end="^\z1\s*$" 347 syn region shHereDoc matchgroup=shRedir fold start="<<\\\z(\S*\)" matchgroup=shRedir end="^\z1\s*$" 348 349else 350 syn region shHereDoc matchgroup=shRedir start="<<\s*\\\=\z(\S*\)" matchgroup=shRedir end="^\z1\s*$" contains=@shDblQuoteList 351 syn region shHereDoc matchgroup=shRedir start="<<\s*\"\z(\S*\)\"" matchgroup=shRedir end="^\z1\s*$" 352 syn region shHereDoc matchgroup=shRedir start="<<-\s*\z(\S*\)" matchgroup=shRedir end="^\s*\z1\s*$" contains=@shDblQuoteList 353 syn region shHereDoc matchgroup=shRedir start="<<-\s*'\z(\S*\)'" matchgroup=shRedir end="^\s*\z1\s*$" 354 syn region shHereDoc matchgroup=shRedir start="<<\s*'\z(\S*\)'" matchgroup=shRedir end="^\z1\s*$" 355 syn region shHereDoc matchgroup=shRedir start="<<-\s*\"\z(\S*\)\"" matchgroup=shRedir end="^\s*\z1\s*$" 356 syn region shHereDoc matchgroup=shRedir start="<<\s*\\\_$\_s*\z(\S*\)" matchgroup=shRedir end="^\z1\s*$" 357 syn region shHereDoc matchgroup=shRedir start="<<-\s*\\\_$\_s*\z(\S*\)" matchgroup=shRedir end="^\s*\z1\s*$" 358 syn region shHereDoc matchgroup=shRedir start="<<-\s*\\\_$\_s*'\z(\S*\)'" matchgroup=shRedir end="^\s*\z1\s*$" 359 syn region shHereDoc matchgroup=shRedir start="<<\s*\\\_$\_s*'\z(\S*\)'" matchgroup=shRedir end="^\z1\s*$" 360 syn region shHereDoc matchgroup=shRedir start="<<\s*\\\_$\_s*\"\z(\S*\)\"" matchgroup=shRedir end="^\z1\s*$" 361 syn region shHereDoc matchgroup=shRedir start="<<-\s*\\\_$\_s*\"\z(\S*\)\"" matchgroup=shRedir end="^\s*\z1\s*$" 362 syn region shHereDoc matchgroup=shRedir start="<<\\\z(\S*\)" matchgroup=shRedir end="^\z1\s*$" 363endif 364 365" Here Strings: {{{1 366" ============= 367" available for: bash; ksh (really should be ksh93 only) but not if its a posix 368if exists("b:is_bash") || (exists("b:is_kornshell") && !exists("g:is_posix")) 369 syn match shRedir "<<<" 370endif 371 372" Identifiers: {{{1 373"============= 374syn match shSetOption "\s\zs[-+][a-zA-Z0-9]\+\>" contained 375syn match shVariable "\<\([bwglsav]:\)\=[a-zA-Z0-9.!@_%+,]*\ze=" nextgroup=shSetIdentifier 376syn match shSetIdentifier "=" contained nextgroup=shPattern,shDeref,shDerefSimple,shDoubleQuote,shExDoubleQuote,shSingleQuote,shExSingleQuote 377if exists("b:is_bash") 378 syn region shSetList oneline matchgroup=shSet start="\<\(declare\|typeset\|local\|export\|unset\)\>\ze[^/]" end="$" matchgroup=shSetListDelim end="\ze[}|);&]" matchgroup=NONE end="\ze\s\+#\|=" contains=@shIdList 379 syn region shSetList oneline matchgroup=shSet start="\<set\>\ze[^/]" end="\ze[;|)]\|$" matchgroup=shSetListDelim end="\ze[}|);&]" matchgroup=NONE end="\ze\s\+[#=]" contains=@shIdList 380elseif exists("b:is_kornshell") 381 syn region shSetList oneline matchgroup=shSet start="\<\(typeset\|export\|unset\)\>\ze[^/]" end="$" matchgroup=shSetListDelim end="\ze[}|);&]" matchgroup=NONE end="\ze\s\+[#=]" contains=@shIdList 382 syn region shSetList oneline matchgroup=shSet start="\<set\>\ze[^/]" end="$" matchgroup=shSetListDelim end="\ze[}|);&]" matchgroup=NONE end="\ze\s\+[#=]" contains=@shIdList 383else 384 syn region shSetList oneline matchgroup=shSet start="\<\(set\|export\|unset\)\>\ze[^/]" end="$" matchgroup=shSetListDelim end="\ze[}|);&]" matchgroup=NONE end="\ze\s\+[#=]" contains=@shIdList 385endif 386 387" Functions: {{{1 388if !exists("g:is_posix") 389 syn keyword shFunctionKey function skipwhite skipnl nextgroup=shFunctionTwo 390endif 391 392if exists("b:is_bash") 393 if (g:sh_fold_enabled % (s:sh_fold_functions * 2))/s:sh_fold_functions 394 syn region shFunctionOne fold matchgroup=shFunction start="^\s*\h[-a-zA-Z_0-9]*\s*()\_s*{" end="}" contains=@shFunctionList skipwhite skipnl nextgroup=shFunctionStart,shQuickComment 395 syn region shFunctionTwo fold matchgroup=shFunction start="\h[-a-zA-Z_0-9]*\s*\%(()\)\=\_s*{" end="}" contains=shFunctionKey,@shFunctionList contained skipwhite skipnl nextgroup=shFunctionStart,shQuickComment 396 else 397 syn region shFunctionOne matchgroup=shFunction start="^\s*\h[-a-zA-Z_0-9]*\s*()\_s*{" end="}" contains=@shFunctionList 398 syn region shFunctionTwo matchgroup=shFunction start="\h[-a-zA-Z_0-9]*\s*\%(()\)\=\_s*{" end="}" contains=shFunctionKey,@shFunctionList contained 399 endif 400else 401 if (g:sh_fold_enabled % (s:sh_fold_functions * 2))/s:sh_fold_functions 402 syn region shFunctionOne fold matchgroup=shFunction start="^\s*\h\w*\s*()\_s*{" end="}" contains=@shFunctionList skipwhite skipnl nextgroup=shFunctionStart,shQuickComment 403 syn region shFunctionTwo fold matchgroup=shFunction start="\h\w*\s*\%(()\)\=\_s*{" end="}" contains=shFunctionKey,@shFunctionList contained skipwhite skipnl nextgroup=shFunctionStart,shQuickComment 404 else 405 syn region shFunctionOne matchgroup=shFunction start="^\s*\h\w*\s*()\_s*{" end="}" contains=@shFunctionList 406 syn region shFunctionTwo matchgroup=shFunction start="\h\w*\s*\%(()\)\=\_s*{" end="}" contains=shFunctionKey,@shFunctionList contained 407 endif 408endif 409 410" Parameter Dereferencing: {{{1 411" ======================== 412syn match shDerefSimple "\$\%(\h\w*\|\d\)" 413syn region shDeref matchgroup=PreProc start="\${" end="}" contains=@shDerefList,shDerefVarArray 414if !exists("g:sh_no_error") 415 syn match shDerefWordError "[^}$[]" contained 416endif 417syn match shDerefSimple "\$[-#*@!?]" 418syn match shDerefSimple "\$\$" 419if exists("b:is_bash") || exists("b:is_kornshell") 420 syn region shDeref matchgroup=PreProc start="\${##\=" end="}" contains=@shDerefList 421 syn region shDeref matchgroup=PreProc start="\${\$\$" end="}" contains=@shDerefList 422endif 423 424" bash: ${!prefix*} and ${#parameter}: {{{1 425" ==================================== 426if exists("b:is_bash") 427 syn region shDeref matchgroup=PreProc start="\${!" end="\*\=}" contains=@shDerefList,shDerefOp 428 syn match shDerefVar contained "{\@<=!\w\+" nextgroup=@shDerefVarList 429endif 430 431syn match shDerefSpecial contained "{\@<=[-*@?0]" nextgroup=shDerefOp,shDerefOpError 432syn match shDerefSpecial contained "\({[#!]\)\@<=[[:alnum:]*@_]\+" nextgroup=@shDerefVarList,shDerefOp 433syn match shDerefVar contained "{\@<=\w\+" nextgroup=@shDerefVarList 434 435" sh ksh bash : ${var[... ]...} array reference: {{{1 436syn region shDerefVarArray contained matchgroup=shDeref start="\[" end="]" contains=@shCommandSubList nextgroup=shDerefOp,shDerefOpError 437 438" Special ${parameter OPERATOR word} handling: {{{1 439" sh ksh bash : ${parameter:-word} word is default value 440" sh ksh bash : ${parameter:=word} assign word as default value 441" sh ksh bash : ${parameter:?word} display word if parameter is null 442" sh ksh bash : ${parameter:+word} use word if parameter is not null, otherwise nothing 443" ksh bash : ${parameter#pattern} remove small left pattern 444" ksh bash : ${parameter##pattern} remove large left pattern 445" ksh bash : ${parameter%pattern} remove small right pattern 446" ksh bash : ${parameter%%pattern} remove large right pattern 447" bash : ${parameter^pattern} Case modification 448" bash : ${parameter^^pattern} Case modification 449" bash : ${parameter,pattern} Case modification 450" bash : ${parameter,,pattern} Case modification 451syn cluster shDerefPatternList contains=shDerefPattern,shDerefString 452if !exists("g:sh_no_error") 453 syn match shDerefOpError contained ":[[:punct:]]" 454endif 455syn match shDerefOp contained ":\=[-=?]" nextgroup=@shDerefPatternList 456syn match shDerefOp contained ":\=+" nextgroup=@shDerefPatternList 457if exists("b:is_bash") || exists("b:is_kornshell") 458 syn match shDerefOp contained "#\{1,2}" nextgroup=@shDerefPatternList 459 syn match shDerefOp contained "%\{1,2}" nextgroup=@shDerefPatternList 460 syn match shDerefPattern contained "[^{}]\+" contains=shDeref,shDerefSimple,shDerefPattern,shDerefString,shCommandSub,shDerefEscape nextgroup=shDerefPattern 461 syn region shDerefPattern contained start="{" end="}" contains=shDeref,shDerefSimple,shDerefString,shCommandSub nextgroup=shDerefPattern 462 syn match shDerefEscape contained '\%(\\\\\)*\\.' 463endif 464if exists("b:is_bash") 465 syn match shDerefOp contained "[,^]\{1,2}" nextgroup=@shDerefPatternList 466endif 467syn region shDerefString contained matchgroup=shDerefDelim start=+\%(\\\)\@<!'+ end=+'+ contains=shStringSpecial 468syn region shDerefString contained matchgroup=shDerefDelim start=+\%(\\\)\@<!"+ skip=+\\"+ end=+"+ contains=@shDblQuoteList,shStringSpecial 469syn match shDerefString contained "\\["']" nextgroup=shDerefPattern 470 471if exists("b:is_bash") 472 " bash : ${parameter:offset} 473 " bash : ${parameter:offset:length} 474 syn region shDerefOp contained start=":[$[:alnum:]_]"me=e-1 end=":"me=e-1 end="}"me=e-1 contains=@shCommandSubList nextgroup=shDerefPOL 475 syn match shDerefPOL contained ":[^}]\+" contains=@shCommandSubList 476 477 " bash : ${parameter//pattern/string} 478 " bash : ${parameter//pattern} 479 syn match shDerefPPS contained '/\{1,2}' nextgroup=shDerefPPSleft 480 syn region shDerefPPSleft contained start='.' skip=@\%(\\\)\/@ matchgroup=shDerefOp end='/' end='\ze}' nextgroup=shDerefPPSright contains=@shCommandSubList 481 syn region shDerefPPSright contained start='.' end='\ze}' contains=@shCommandSubList 482endif 483 484" Arithmetic Parenthesized Expressions: {{{1 485syn region shParen matchgroup=shArithRegion start='(\%(\ze[^(]\|$\)' end=')' contains=@shArithParenList 486 487" Useful sh Keywords: {{{1 488" =================== 489syn keyword shStatement break cd chdir continue eval exec exit kill newgrp pwd read readonly return shift test trap ulimit umask wait 490syn keyword shConditional contained elif else then 491if !exists("g:sh_no_error") 492 syn keyword shCondError elif else then 493endif 494 495" Useful ksh Keywords: {{{1 496" ==================== 497if exists("b:is_kornshell") || exists("b:is_bash") 498 syn keyword shStatement autoload bg false fc fg functions getopts hash history integer jobs let nohup printf r stop suspend times true type unalias whence 499 if exists("g:is_posix") 500 syn keyword shStatement command 501 else 502 syn keyword shStatement time 503 endif 504 505" Useful bash Keywords: {{{1 506" ===================== 507 if exists("b:is_bash") 508 syn keyword shStatement bind builtin dirs disown enable help local logout popd pushd shopt source 509 else 510 syn keyword shStatement login newgrp 511 endif 512endif 513 514" Synchronization: {{{1 515" ================ 516if !exists("sh_minlines") 517 let sh_minlines = 200 518endif 519if !exists("sh_maxlines") 520 let sh_maxlines = 2 * sh_minlines 521endif 522exec "syn sync minlines=" . sh_minlines . " maxlines=" . sh_maxlines 523syn sync match shCaseEsacSync grouphere shCaseEsac "\<case\>" 524syn sync match shCaseEsacSync groupthere shCaseEsac "\<esac\>" 525syn sync match shDoSync grouphere shDo "\<do\>" 526syn sync match shDoSync groupthere shDo "\<done\>" 527syn sync match shForSync grouphere shFor "\<for\>" 528syn sync match shForSync groupthere shFor "\<in\>" 529syn sync match shIfSync grouphere shIf "\<if\>" 530syn sync match shIfSync groupthere shIf "\<fi\>" 531syn sync match shUntilSync grouphere shRepeat "\<until\>" 532syn sync match shWhileSync grouphere shRepeat "\<while\>" 533 534" Default Highlighting: {{{1 535" ===================== 536hi def link shArithRegion shShellVariables 537hi def link shBeginHere shRedir 538hi def link shCaseBar shConditional 539hi def link shCaseCommandSub shCommandSub 540hi def link shCaseDoubleQuote shDoubleQuote 541hi def link shCaseIn shConditional 542hi def link shQuote shOperator 543hi def link shCaseSingleQuote shSingleQuote 544hi def link shCaseStart shConditional 545hi def link shCmdSubRegion shShellVariables 546hi def link shColon shComment 547hi def link shDerefOp shOperator 548hi def link shDerefPOL shDerefOp 549hi def link shDerefPPS shDerefOp 550hi def link shDeref shShellVariables 551hi def link shDerefDelim shOperator 552hi def link shDerefSimple shDeref 553hi def link shDerefSpecial shDeref 554hi def link shDerefString shDoubleQuote 555hi def link shDerefVar shDeref 556hi def link shDoubleQuote shString 557hi def link shEcho shString 558hi def link shEchoDelim shOperator 559hi def link shEchoQuote shString 560hi def link shEmbeddedEcho shString 561hi def link shEscape shCommandSub 562hi def link shExDoubleQuote shDoubleQuote 563hi def link shExSingleQuote shSingleQuote 564hi def link shFunction Function 565hi def link shHereDoc shString 566hi def link shHerePayload shHereDoc 567hi def link shLoop shStatement 568hi def link shMoreSpecial shSpecial 569hi def link shOption shCommandSub 570hi def link shPattern shString 571hi def link shParen shArithmetic 572hi def link shPosnParm shShellVariables 573hi def link shQuickComment shComment 574hi def link shRange shOperator 575hi def link shRedir shOperator 576hi def link shSetListDelim shOperator 577hi def link shSetOption shOption 578hi def link shSingleQuote shString 579hi def link shSource shOperator 580hi def link shStringSpecial shSpecial 581hi def link shSubShRegion shOperator 582hi def link shTestOpr shConditional 583hi def link shTestPattern shString 584hi def link shTestDoubleQuote shString 585hi def link shTestSingleQuote shString 586hi def link shVariable shSetList 587hi def link shWrapLineOperator shOperator 588 589if exists("b:is_bash") 590 hi def link bashAdminStatement shStatement 591 hi def link bashSpecialVariables shShellVariables 592 hi def link bashStatement shStatement 593 hi def link shFunctionParen Delimiter 594 hi def link shFunctionDelim Delimiter 595endif 596if exists("b:is_kornshell") 597 hi def link kshSpecialVariables shShellVariables 598 hi def link kshStatement shStatement 599 hi def link shFunctionParen Delimiter 600endif 601 602if !exists("g:sh_no_error") 603 hi def link shCaseError Error 604 hi def link shCondError Error 605 hi def link shCurlyError Error 606 hi def link shDerefError Error 607 hi def link shDerefOpError Error 608 hi def link shDerefWordError Error 609 hi def link shDoError Error 610 hi def link shEsacError Error 611 hi def link shIfError Error 612 hi def link shInError Error 613 hi def link shParenError Error 614 hi def link shTestError Error 615 if exists("b:is_kornshell") 616 hi def link shDTestError Error 617 endif 618endif 619 620hi def link shArithmetic Special 621hi def link shCharClass Identifier 622hi def link shSnglCase Statement 623hi def link shCommandSub Special 624hi def link shComment Comment 625hi def link shConditional Conditional 626hi def link shCtrlSeq Special 627hi def link shExprRegion Delimiter 628hi def link shFunctionKey Function 629hi def link shFunctionName Function 630hi def link shNumber Number 631hi def link shOperator Operator 632hi def link shRepeat Repeat 633hi def link shSet Statement 634hi def link shSetList Identifier 635hi def link shShellVariables PreProc 636hi def link shSpecial Special 637hi def link shStatement Statement 638hi def link shString String 639hi def link shTodo Todo 640hi def link shAlias Identifier 641 642" Set Current Syntax: {{{1 643" =================== 644if exists("b:is_bash") 645 let b:current_syntax = "bash" 646elseif exists("b:is_kornshell") 647 let b:current_syntax = "ksh" 648else 649 let b:current_syntax = "sh" 650endif 651 652" vim: ts=16 fdm=marker 653