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