xref: /vim-8.2.3635/runtime/syntax/sh.vim (revision 113cb513)
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:		Oct 26, 2021
6" Version:		199
7" URL:		http://www.drchip.org/astronaut/vim/index.html#SYNTAX_SH
8" For options and settings, please use:      :help ft-sh-syntax
9" This file includes many ideas from Eric Brunet ([email protected]) and heredoc fixes from Felipe Contreras
10
11" quit when a syntax file was already loaded {{{1
12if exists("b:current_syntax")
13  finish
14endif
15
16" If the shell script itself specifies which shell to use, use it
17if getline(1) =~ '\<ksh\>'
18 let b:is_kornshell = 1
19elseif getline(1) =~ '\<bash\>'
20 let b:is_bash      = 1
21elseif getline(1) =~ '\<dash\>'
22 let b:is_dash      = 1
23elseif !exists("g:is_kornshell") && !exists("g:is_bash") && !exists("g:is_posix") && !exists("g:is_sh") && !exists("g:is_dash")
24 " user did not specify which shell to use, and
25 " the script itself does not specify which shell to use. FYI: /bin/sh is ambiguous.
26 " Assuming /bin/sh is executable, and if its a link, find out what it links to.
27 let s:shell = ""
28 if executable("/bin/sh")
29  let s:shell = resolve("/bin/sh")
30 elseif executable("/usr/bin/sh")
31  let s:shell = resolve("/usr/bin/sh")
32 endif
33 if     s:shell =~ '\<ksh\>'
34  let b:is_kornshell= 1
35 elseif s:shell =~ '\<bash\>'
36  let b:is_bash = 1
37 elseif s:shell =~ '\<dash\>'
38  let b:is_dash = 1
39 endif
40 unlet s:shell
41endif
42
43" handling /bin/sh with is_kornshell/is_sh {{{1
44" b:is_sh will be set when "#! /bin/sh" is found;
45" However, it often is just a masquerade by bash (typically Linux)
46" or kornshell (typically workstations with Posix "sh").
47" So, when the user sets "g:is_bash", "g:is_kornshell",
48" or "g:is_posix", a b:is_sh is converted into b:is_bash/b:is_kornshell,
49" respectively.
50if !exists("b:is_kornshell") && !exists("b:is_bash") && !exists("b:is_dash")
51  if exists("g:is_posix") && !exists("g:is_kornshell")
52   let g:is_kornshell= g:is_posix
53  endif
54  if exists("g:is_kornshell")
55    let b:is_kornshell= 1
56    if exists("b:is_sh")
57      unlet b:is_sh
58    endif
59  elseif exists("g:is_bash")
60    let b:is_bash= 1
61    if exists("b:is_sh")
62      unlet b:is_sh
63    endif
64  elseif exists("g:is_dash")
65    let b:is_dash= 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" if b:is_dash, set b:is_posix too
75if exists("b:is_dash")
76 let b:is_posix= 1
77endif
78
79" set up default g:sh_fold_enabled {{{1
80" ================================
81if !exists("g:sh_fold_enabled")
82 let g:sh_fold_enabled= 0
83elseif g:sh_fold_enabled != 0 && !has("folding")
84 let g:sh_fold_enabled= 0
85 echomsg "Ignoring g:sh_fold_enabled=".g:sh_fold_enabled."; need to re-compile vim for +fold support"
86endif
87if !exists("s:sh_fold_functions")
88 let s:sh_fold_functions= and(g:sh_fold_enabled,1)
89endif
90if !exists("s:sh_fold_heredoc")
91 let s:sh_fold_heredoc  = and(g:sh_fold_enabled,2)
92endif
93if !exists("s:sh_fold_ifdofor")
94 let s:sh_fold_ifdofor  = and(g:sh_fold_enabled,4)
95endif
96if g:sh_fold_enabled && &fdm == "manual"
97 " Given that	the	user provided g:sh_fold_enabled
98 " 	AND	g:sh_fold_enabled is manual (usual default)
99 " 	implies	a desire for syntax-based folding
100 setl fdm=syntax
101endif
102
103" set up the syntax-highlighting for iskeyword
104if (v:version == 704 && has("patch-7.4.1142")) || v:version > 704
105 if !exists("g:sh_syntax_isk") || (exists("g:sh_syntax_isk") && g:sh_syntax_isk)
106  if exists("b:is_bash")
107   exe "syn iskeyword ".&iskeyword.",-,:"
108  else
109   exe "syn iskeyword ".&iskeyword.",-"
110  endif
111 endif
112endif
113
114" Set up folding commands for shell {{{1
115" =================================
116if s:sh_fold_functions
117 com! -nargs=* ShFoldFunctions <args> fold
118else
119 com! -nargs=* ShFoldFunctions <args>
120endif
121if s:sh_fold_heredoc
122 com! -nargs=* ShFoldHereDoc <args> fold
123else
124 com! -nargs=* ShFoldHereDoc <args>
125endif
126if s:sh_fold_ifdofor
127 com! -nargs=* ShFoldIfDoFor <args> fold
128else
129 com! -nargs=* ShFoldIfDoFor <args>
130endif
131
132" sh syntax is case sensitive {{{1
133syn case match
134
135" Clusters: contains=@... clusters {{{1
136"==================================
137syn cluster shErrorList	contains=shDoError,shIfError,shInError,shCaseError,shEsacError,shCurlyError,shParenError,shTestError,shOK
138if exists("b:is_kornshell") || exists("b:is_bash")
139 syn cluster ErrorList add=shDTestError
140endif
141syn cluster shArithParenList	contains=shArithmetic,shCaseEsac,shComment,shDeref,shDo,shDerefSimple,shEcho,shEscape,shNumber,shOperator,shPosnParm,shExSingleQuote,shExDoubleQuote,shHereString,shRedir,shSingleQuote,shDoubleQuote,shStatement,shVariable,shAlias,shTest,shCtrlSeq,shSpecial,shParen,bashSpecialVariables,bashStatement,shIf,shFor,shFunctionKey,shFunctionOne,shFunctionTwo
142syn cluster shArithList	contains=@shArithParenList,shParenError
143syn cluster shCaseEsacList	contains=shCaseStart,shCaseLabel,shCase,shCaseBar,shCaseIn,shComment,shDeref,shDerefSimple,shCaseCommandSub,shCaseExSingleQuote,shCaseSingleQuote,shCaseDoubleQuote,shCtrlSeq,@shErrorList,shStringSpecial,shCaseRange
144syn cluster shCaseList	contains=@shCommandSubList,shCaseEsac,shColon,shCommandSub,shCommandSubBQ,shComment,shDo,shEcho,shExpr,shFor,shHereDoc,shIf,shHereString,shRedir,shSetList,shSource,shStatement,shVariable,shCtrlSeq
145if exists("b:is_kornshell") || exists("b:is_bash")
146 syn cluster shCaseList	add=shForPP
147endif
148syn cluster shCommandSubList	contains=shAlias,shArithmetic,shCmdParenRegion,shCommandSub,shComment,shCtrlSeq,shDeref,shDerefSimple,shDoubleQuote,shEcho,shEscape,shExDoubleQuote,shExpr,shExSingleQuote,shHereDoc,shNumber,shOperator,shOption,shPosnParm,shHereString,shRedir,shSingleQuote,shSpecial,shStatement,shSubSh,shTest,shVariable
149syn cluster shCurlyList	contains=shNumber,shComma,shDeref,shDerefSimple,shDerefSpecial
150" COMBAK: removing shEscape from shDblQuoteList fails ksh04:43
151syn cluster shDblQuoteList	contains=shArithmetic,shCommandSub,shCommandSubBQ,shDeref,shDerefSimple,shPosnParm,shCtrlSeq,shSpecial,shSpecialDQ
152syn cluster shDerefList	contains=shDeref,shDerefSimple,shDerefVar,shDerefSpecial,shDerefWordError,shDerefPSR,shDerefPPS
153syn cluster shDerefVarList	contains=shDerefOffset,shDerefOp,shDerefVarArray,shDerefOpError
154syn cluster shEchoList	contains=shArithmetic,shCommandSub,shCommandSubBQ,shDeref,shDerefSimple,shEscape,shExSingleQuote,shExDoubleQuote,shSingleQuote,shDoubleQuote,shCtrlSeq,shEchoQuote
155syn cluster shExprList1	contains=shCharClass,shNumber,shOperator,shExSingleQuote,shExDoubleQuote,shSingleQuote,shDoubleQuote,shExpr,shDblBrace,shDeref,shDerefSimple,shCtrlSeq
156syn cluster shExprList2	contains=@shExprList1,@shCaseList,shTest
157syn cluster shFunctionList	contains=@shCommandSubList,shCaseEsac,shColon,shComment,shDo,shEcho,shExpr,shFor,shHereDoc,shIf,shOption,shHereString,shRedir,shSetList,shSource,shStatement,shVariable,shOperator,shCtrlSeq
158if exists("b:is_kornshell") || exists("b:is_bash")
159 syn cluster shFunctionList	add=shRepeat,shDblBrace,shDblParen,shForPP
160endif
161syn cluster shHereBeginList	contains=@shCommandSubList
162syn cluster shHereList	contains=shBeginHere,shHerePayload
163syn cluster shHereListDQ	contains=shBeginHere,@shDblQuoteList,shHerePayload
164syn cluster shIdList	contains=shCommandSub,shCommandSubBQ,shWrapLineOperator,shSetOption,shComment,shDeref,shDerefSimple,shHereString,shNumber,shOperator,shRedir,shExSingleQuote,shExDoubleQuote,shSingleQuote,shDoubleQuote,shExpr,shCtrlSeq,shStringSpecial,shAtExpr
165syn cluster shIfList	contains=@shLoopList,shDblBrace,shDblParen,shFunctionKey,shFunctionOne,shFunctionTwo
166syn cluster shLoopList	contains=@shCaseList,@shErrorList,shCaseEsac,shConditional,shDblBrace,shExpr,shFor,shIf,shOption,shSet,shTest,shTestOpr,shTouch
167if exists("b:is_kornshell") || exists("b:is_bash")
168 syn cluster shLoopoList	add=shForPP
169endif
170syn cluster shPPSLeftList	contains=shAlias,shArithmetic,shCmdParenRegion,shCommandSub,shCtrlSeq,shDeref,shDerefSimple,shDoubleQuote,shEcho,shEscape,shExDoubleQuote,shExpr,shExSingleQuote,shHereDoc,shNumber,shOperator,shOption,shPosnParm,shHereString,shRedir,shSingleQuote,shSpecial,shStatement,shSubSh,shTest,shVariable
171syn cluster shPPSRightList	contains=shComment,shDeref,shDerefSimple,shEscape,shPosnParm
172syn cluster shSubShList	contains=@shCommandSubList,shCommandSubBQ,shCaseEsac,shColon,shCommandSub,shComment,shDo,shEcho,shExpr,shFor,shIf,shHereString,shRedir,shSetList,shSource,shStatement,shVariable,shCtrlSeq,shOperator
173syn cluster shTestList	contains=shArithmetic,shCharClass,shCommandSub,shCommandSubBQ,shCtrlSeq,shDeref,shDerefSimple,shDoubleQuote,shSpecialDQ,shExDoubleQuote,shExpr,shExSingleQuote,shNumber,shOperator,shSingleQuote,shTest,shTestOpr
174syn cluster shNoZSList	contains=shSpecialNoZS
175syn cluster shForList	contains=shTestOpr,shNumber,shDerefSimple,shDeref,shCommandSub,shCommandSubBQ,shArithmetic
176
177" Echo: {{{1
178" ====
179" This one is needed INSIDE a CommandSub, so that `echo bla` be correct
180syn region shEcho matchgroup=shStatement start="\<echo\>"  skip="\\$" matchgroup=shEchoDelim end="$" matchgroup=NONE end="[<>;&|()`]"me=e-1 end="\d[<>]"me=e-2 end="#"me=e-1 contains=@shEchoList skipwhite nextgroup=shQuickComment
181syn region shEcho matchgroup=shStatement start="\<print\>" skip="\\$" matchgroup=shEchoDelim end="$" matchgroup=NONE end="[<>;&|()`]"me=e-1 end="\d[<>]"me=e-2 end="#"me=e-1 contains=@shEchoList skipwhite nextgroup=shQuickComment
182syn match  shEchoQuote contained	'\%(\\\\\)*\\["`'()]'
183
184" This must be after the strings, so that ... \" will be correct
185syn 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
186
187" Alias: {{{1
188" =====
189if exists("b:is_kornshell") || exists("b:is_bash") || exists("b:is_posix")
190 syn match shStatement "\<alias\>"
191 syn region shAlias matchgroup=shStatement start="\<alias\>\s\+\(\h[-._[:alnum:]]\+\)\@="  skip="\\$" end="\>\|`"
192 syn region shAlias matchgroup=shStatement start="\<alias\>\s\+\(\h[-._[:alnum:]]\+=\)\@=" skip="\\$" end="="
193
194 " Touch: {{{1
195 " =====
196 syn match shTouch	'\<touch\>[^;#]*'	skipwhite nextgroup=shComment contains=shTouchCmd,shDoubleQuote,shSingleQuote,shDeref,shDerefSimple
197 syn match shTouchCmd	'\<touch\>'		contained
198endif
199
200" Error Codes: {{{1
201" ============
202if !exists("g:sh_no_error")
203 syn match   shDoError "\<done\>"
204 syn match   shIfError "\<fi\>"
205 syn match   shInError "\<in\>"
206 syn match   shCaseError ";;"
207 syn match   shEsacError "\<esac\>"
208 syn match   shCurlyError "}"
209 syn match   shParenError ")"
210 syn match   shOK	'\.\(done\|fi\|in\|esac\)'
211 if exists("b:is_kornshell") || exists("b:is_bash")
212  syn match     shDTestError "]]"
213 endif
214 syn match     shTestError "]"
215endif
216
217" Options: {{{1
218" ====================
219syn match   shOption	"\s\zs[-+][-_a-zA-Z#@]\+"
220syn match   shOption	"\s\zs--[^ \t$=`'"|);]\+"
221
222" File Redirection Highlighted As Operators: {{{1
223"===========================================
224syn match      shRedir	"\d\=>\(&[-0-9]\)\="
225syn match      shRedir	"\d\=>>-\="
226syn match      shRedir	"\d\=<\(&[-0-9]\)\="
227syn match      shRedir	"\d<<-\="
228
229" Operators: {{{1
230" ==========
231syn match   shOperator	"<<\|>>"		contained
232syn match   shOperator	"[!&;|]"		contained
233syn match   shOperator	"\[[[^:]\|\]]"		contained
234syn match   shOperator	"[-=/*+%]\=="		skipwhite nextgroup=shPattern
235syn match   shPattern	"\<\S\+\())\)\@="	contained contains=shExSingleQuote,shSingleQuote,shExDoubleQuote,shDoubleQuote,shDeref
236
237" Subshells: {{{1
238" ==========
239syn region shExpr  transparent matchgroup=shExprRegion  start="{" end="}"		contains=@shExprList2 nextgroup=shSpecialNxt
240syn region shSubSh transparent matchgroup=shSubShRegion start="[^(]\zs(" end=")"	contains=@shSubShList nextgroup=shSpecialNxt
241
242" Tests: {{{1
243"=======
244syn region shExpr	matchgroup=shRange start="\[" skip=+\\\\\|\\$\|\[+ end="\]" contains=@shTestList,shSpecial
245syn region shTest	transparent matchgroup=shStatement start="\<test\s" skip=+\\\\\|\\$+ matchgroup=NONE end="[;&|]"me=e-1 end="$" contains=@shExprList1
246syn region shNoQuote	start='\S'	skip='\%(\\\\\)*\\.'	end='\ze\s' end="\ze['"]"	contained contains=shDerefSimple,shDeref
247syn match  shAstQuote	contained	'\*\ze"'	nextgroup=shString
248syn match  shTestOpr	contained	'[^-+/%]\zs=' skipwhite nextgroup=shTestDoubleQuote,shTestSingleQuote,shTestPattern
249syn match  shTestOpr	contained	"<=\|>=\|!=\|==\|=\~\|-.\>\|-\(nt\|ot\|ef\|eq\|ne\|lt\|le\|gt\|ge\)\>\|[!<>]"
250syn match  shTestPattern	contained	'\w\+'
251syn region shTestDoubleQuote	contained	start='\%(\%(\\\\\)*\\\)\@<!"' skip=+\\\\\|\\"+ end='"'	contains=shDeref,shDerefSimple,shDerefSpecial
252syn match  shTestSingleQuote	contained	'\\.'	nextgroup=shTestSingleQuote
253syn match  shTestSingleQuote	contained	"'[^']*'"
254if exists("b:is_kornshell") || exists("b:is_bash")
255 syn region  shDblBrace matchgroup=Delimiter start="\[\["	skip=+\%(\\\\\)*\\$+ end="\]\]"	contains=@shTestList,shAstQuote,shNoQuote,shComment
256 syn region  shDblParen matchgroup=Delimiter start="(("	skip=+\%(\\\\\)*\\$+ end="))"	contains=@shTestList,shComment
257endif
258
259" Character Class In Range: {{{1
260" =========================
261syn match   shCharClass	contained	"\[:\(backspace\|escape\|return\|xdigit\|alnum\|alpha\|blank\|cntrl\|digit\|graph\|lower\|print\|punct\|space\|upper\|tab\):\]"
262
263" Loops: do, if, while, until {{{1
264" ======
265ShFoldIfDoFor syn region shDo	transparent	matchgroup=shConditional start="\<do\>" matchgroup=shConditional end="\<done\>"			contains=@shLoopList
266ShFoldIfDoFor syn region shIf	transparent	matchgroup=shConditional start="\<if\_s" matchgroup=shConditional skip=+-fi\>+ end="\<;\_s*then\>" end="\<fi\>"	contains=@shIfList
267ShFoldIfDoFor syn region shFor		matchgroup=shLoop start="\<for\ze\_s\s*\%(((\)\@!" end="\<in\>" end="\<do\>"me=e-2			contains=@shLoopList,shDblParen skipwhite nextgroup=shCurlyIn
268if exists("b:is_kornshell") || exists("b:is_bash")
269 ShFoldIfDoFor syn region shForPP	matchgroup=shLoop start='\<for\>\_s*((' end='))' contains=@shForList
270endif
271
272if exists("b:is_kornshell") || exists("b:is_bash") || exists("b:is_posix")
273 syn cluster shCaseList	add=shRepeat
274 syn cluster shFunctionList	add=shRepeat
275 syn region shRepeat   matchgroup=shLoop   start="\<while\_s" end="\<do\>"me=e-2	contains=@shLoopList,shDblParen,shDblBrace
276 syn region shRepeat   matchgroup=shLoop   start="\<until\_s" end="\<do\>"me=e-2	contains=@shLoopList,shDblParen,shDblBrace
277 if !exists("b:is_posix")
278  syn region shCaseEsac matchgroup=shConditional start="\<select\s" matchgroup=shConditional end="\<in\>" end="\<do\>" contains=@shLoopList
279 endif
280else
281 syn region shRepeat   matchgroup=shLoop   start="\<while\_s" end="\<do\>"me=e-2		contains=@shLoopList
282 syn region shRepeat   matchgroup=shLoop   start="\<until\_s" end="\<do\>"me=e-2		contains=@shLoopList
283endif
284syn region shCurlyIn   contained	matchgroup=Delimiter start="{" end="}" contains=@shCurlyList
285syn match  shComma     contained	","
286
287" Case: case...esac {{{1
288" ====
289syn match shCaseBar	contained skipwhite "\(^\|[^\\]\)\(\\\\\)*\zs|"		nextgroup=shCase,shCaseStart,shCaseBar,shComment,shCaseExSingleQuote,shCaseSingleQuote,shCaseDoubleQuote
290syn match shCaseStart	contained skipwhite skipnl "("			nextgroup=shCase,shCaseBar
291syn match shCaseLabel	contained skipwhite	"\%(\\.\|[-a-zA-Z0-9_*.]\)\+"	contains=shCharClass
292if exists("b:is_bash")
293 ShFoldIfDoFor syn region	shCase	contained skipwhite skipnl matchgroup=shSnglCase start="\%(\\.\|[^#$()'" \t]\)\{-}\zs)"  end=";;" end=";&" end=";;&" end="esac"me=s-1	contains=@shCaseList	nextgroup=shCaseStart,shCase,shComment
294else
295 ShFoldIfDoFor syn region	shCase	contained skipwhite skipnl matchgroup=shSnglCase start="\%(\\.\|[^#$()'" \t]\)\{-}\zs)"  end=";;" end="esac"me=s-1		contains=@shCaseList	nextgroup=shCaseStart,shCase,shComment
296endif
297ShFoldIfDoFor syn region	shCaseEsac	matchgroup=shConditional start="\<case\>" end="\<esac\>"	contains=@shCaseEsacList
298
299syn keyword shCaseIn	contained skipwhite skipnl in			nextgroup=shCase,shCaseStart,shCaseBar,shComment,shCaseExSingleQuote,shCaseSingleQuote,shCaseDoubleQuote
300if exists("b:is_bash")
301 syn region  shCaseExSingleQuote	matchgroup=shQuote start=+\$'+ skip=+\\\\\|\\.+ end=+'+	contains=shStringSpecial,shSpecial	skipwhite skipnl nextgroup=shCaseBar	contained
302elseif !exists("g:sh_no_error")
303 syn region  shCaseExSingleQuote	matchgroup=Error start=+\$'+ skip=+\\\\\|\\.+ end=+'+	contains=shStringSpecial	skipwhite skipnl nextgroup=shCaseBar	contained
304endif
305syn region  shCaseSingleQuote	matchgroup=shQuote start=+'+ end=+'+		contains=shStringSpecial		skipwhite skipnl nextgroup=shCaseBar	contained
306syn region  shCaseDoubleQuote	matchgroup=shQuote start=+"+ skip=+\\\\\|\\.+ end=+"+	contains=@shDblQuoteList,shStringSpecial	skipwhite skipnl nextgroup=shCaseBar	contained
307syn region  shCaseCommandSub	start=+`+ skip=+\\\\\|\\.+ end=+`+		contains=@shCommandSubList		skipwhite skipnl nextgroup=shCaseBar	contained
308if exists("b:is_bash")
309 syn region  shCaseRange	matchgroup=Delimiter start=+\[+ skip=+\\\\+ end=+\]+	contained	contains=shCharClass
310 syn match   shCharClass	'\[:\%(alnum\|alpha\|ascii\|blank\|cntrl\|digit\|graph\|lower\|print\|punct\|space\|upper\|word\|or\|xdigit\):\]'			contained
311else
312 syn region  shCaseRange	matchgroup=Delimiter start=+\[+ skip=+\\\\+ end=+\]+	contained
313endif
314" Misc: {{{1
315"======
316syn match   shWrapLineOperator "\\$"
317syn region  shCommandSubBQ   	start="`" skip="\\\\\|\\." end="`"	contains=shBQComment,@shCommandSubList
318"COMBAK: see ksh13:50
319"syn match   shEscape	contained	'\%(^\)\@!\%(\\\\\)*\\.'	nextgroup=shSingleQuote,shDoubleQuote,shComment
320"COMBAK: see sh11:27
321syn match   shEscape	contained	'\%(^\)\@!\%(\\\\\)*\\.'	nextgroup=shComment
322"COMBAK: see ksh13:53
323"syn match   shEscape	contained	'\%(^\)\@!\%(\\\\\)*\\.'
324
325" $() and $(()): {{{1
326" $(..) is not supported by sh (Bourne shell).  However, apparently
327" some systems (HP?) have as their /bin/sh a (link to) Korn shell
328" (ie. Posix compliant shell).  /bin/ksh should work for those
329" systems too, however, so the following syntax will flag $(..) as
330" an Error under /bin/sh.  By consensus of vimdev'ers!
331if exists("b:is_kornshell") || exists("b:is_bash") || exists("b:is_posix")
332 syn region shCommandSub matchgroup=shCmdSubRegion start="\$("  skip='\\\\\|\\.' end=")"  contains=@shCommandSubList
333 syn region shArithmetic matchgroup=shArithRegion  start="\$((" skip='\\\\\|\\.' end="))" contains=@shArithList
334 syn region shArithmetic matchgroup=shArithRegion  start="\$\[" skip='\\\\\|\\.' end="\]" contains=@shArithList
335 syn match  shSkipInitWS contained	"^\s\+"
336elseif !exists("g:sh_no_error")
337 syn region shCommandSub matchgroup=Error start="\$(" end=")" contains=@shCommandSubList
338endif
339syn region shCmdParenRegion matchgroup=shCmdSubRegion start="(\ze[^(]" skip='\\\\\|\\.' end=")" contains=@shCommandSubList
340
341if exists("b:is_bash")
342 syn cluster shCommandSubList add=bashSpecialVariables,bashStatement
343 syn cluster shCaseList add=bashAdminStatement,bashStatement
344 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
345 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
346 syn keyword bashAdminStatement daemon killall killproc nice reload restart start status stop
347 syn keyword bashStatement	command compgen
348endif
349
350if exists("b:is_kornshell") || exists("b:is_posix")
351 syn cluster shCommandSubList add=kshSpecialVariables,kshStatement
352 syn cluster shCaseList add=kshStatement
353 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
354 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 tput
355 syn keyword kshStatement command setgroups setsenv
356endif
357
358syn match   shSource	"^\.\s"
359syn match   shSource	"\s\.\s"
360"syn region  shColon	start="^\s*:" end="$" end="\s#"me=e-2 contains=@shColonList
361"syn region  shColon	start="^\s*\zs:" end="$" end="\s#"me=e-2
362if exists("b:is_kornshell") || exists("b:is_posix")
363 syn match   shColon	'^\s*\zs:'
364endif
365
366" String And Character Constants: {{{1
367"================================
368syn match   shNumber	"\<\d\+\>#\="
369syn match   shNumber	"\<-\=\.\=\d\+\>#\="
370syn match   shCtrlSeq	"\\\d\d\d\|\\[abcfnrtv0]"			contained
371if exists("b:is_bash")
372 syn match   shSpecial	"[^\\]\(\\\\\)*\zs\\\o\o\o\|\\x\x\x\|\\c[^"]\|\\[abefnrtv]"	contained
373 syn match   shSpecial	"^\(\\\\\)*\zs\\\o\o\o\|\\x\x\x\|\\c[^"]\|\\[abefnrtv]"	contained
374 syn region  shExSingleQuote	matchgroup=shQuote start=+\$'+ skip=+\\\\\|\\.+ end=+'+	contains=shStringSpecial,shSpecial		nextgroup=shSpecialNxt
375 syn region  shExDoubleQuote	matchgroup=shQuote start=+\$"+ skip=+\\\\\|\\.\|\\"+ end=+"+	contains=@shDblQuoteList,shStringSpecial,shSpecial	nextgroup=shSpecialNxt
376elseif !exists("g:sh_no_error")
377 syn region  shExSingleQuote	matchGroup=Error start=+\$'+ skip=+\\\\\|\\.+ end=+'+	contains=shStringSpecial
378 syn region  shExDoubleQuote	matchGroup=Error start=+\$"+ skip=+\\\\\|\\.+ end=+"+	contains=shStringSpecial
379endif
380syn region  shSingleQuote	matchgroup=shQuote start=+'+ end=+'+		contains=@Spell	nextgroup=shSpecialStart,shSpecialSQ
381syn region  shDoubleQuote	matchgroup=shQuote start=+\%(\%(\\\\\)*\\\)\@<!"+ skip=+\\.+ end=+"+			contains=@shDblQuoteList,shStringSpecial,@Spell	nextgroup=shSpecialStart
382syn match   shStringSpecial	"[^[:print:] \t]"			contained
383syn match   shStringSpecial	"[^\\]\zs\%(\\\\\)*\(\\[\\"'`$()#]\)\+"			nextgroup=shComment
384syn match   shSpecialSQ	"[^\\]\zs\%(\\\\\)*\(\\[\\"'`$()#]\)\+"		contained	nextgroup=shBkslshSnglQuote,@shNoZSList
385syn match   shSpecialDQ	"[^\\]\zs\%(\\\\\)*\(\\[\\"'`$()#]\)\+"		contained	nextgroup=shBkslshDblQuote,@shNoZSList
386syn match   shSpecialStart	"\%(\\\\\)*\\[\\"'`$()#]"			contained	nextgroup=shBkslshSnglQuote,shBkslshDblQuote,@shNoZSList
387syn match   shSpecial	"^\%(\\\\\)*\\[\\"'`$()#]"
388syn match   shSpecialNoZS	contained	"\%(\\\\\)*\\[\\"'`$()#]"
389syn match   shSpecialNxt	contained	"\\[\\"'`$()#]"
390"syn region  shBkslshSnglQuote	contained	matchgroup=shQuote start=+'+ end=+'+	contains=@Spell	nextgroup=shSpecialStart
391"syn region  shBkslshDblQuote	contained	matchgroup=shQuote start=+"+ skip=+\\"+ end=+"+	contains=@shDblQuoteList,shStringSpecial,@Spell	nextgroup=shSpecialStart
392
393" Comments: {{{1
394"==========
395syn cluster	shCommentGroup	contains=shTodo,@Spell
396if exists("b:is_bash")
397 syn match	shTodo	contained		"\<\%(COMBAK\|FIXME\|TODO\|XXX\)\ze:\=\>"
398else
399 syn keyword	shTodo	contained		COMBAK FIXME TODO XXX
400endif
401syn match	shComment		"^\s*\zs#.*$"	contains=@shCommentGroup
402syn match	shComment		"\s\zs#.*$"	contains=@shCommentGroup
403syn match	shComment	contained	"#.*$"	contains=@shCommentGroup
404syn match	shQuickComment	contained	"#.*$"          contains=@shCommentGroup
405syn match	shBQComment	contained	"#.\{-}\ze`"	contains=@shCommentGroup
406
407" Here Documents: {{{1
408"  (modified by Felipe Contreras)
409" =========================================
410ShFoldHereDoc syn region shHereDoc matchgroup=shHereDoc01 start="<<\s*\z([^ \t|>]\+\)"		matchgroup=shHereDoc01 end="^\z1\s*$"	contains=@shDblQuoteList
411ShFoldHereDoc syn region shHereDoc matchgroup=shHereDoc02 start="<<-\s*\z([^ \t|>]\+\)"		matchgroup=shHereDoc02 end="^\s*\z1\s*$"	contains=@shDblQuoteList
412ShFoldHereDoc syn region shHereDoc matchgroup=shHereDoc03 start="<<\s*\\\z([^ \t|>]\+\)"		matchgroup=shHereDoc03 end="^\z1\s*$"
413ShFoldHereDoc syn region shHereDoc matchgroup=shHereDoc04 start="<<-\s*\\\z([^ \t|>]\+\)"		matchgroup=shHereDoc04 end="^\s*\z1\s*$"
414ShFoldHereDoc syn region shHereDoc matchgroup=shHereDoc05 start="<<\s*'\z([^']\+\)'"		matchgroup=shHereDoc05 end="^\z1\s*$"
415ShFoldHereDoc syn region shHereDoc matchgroup=shHereDoc06 start="<<-\s*'\z([^']\+\)'"		matchgroup=shHereDoc06 end="^\s*\z1\s*$"
416ShFoldHereDoc syn region shHereDoc matchgroup=shHereDoc07 start="<<\s*\"\z([^"]\+\)\""		matchgroup=shHereDoc07 end="^\z1\s*$"
417ShFoldHereDoc syn region shHereDoc matchgroup=shHereDoc08 start="<<-\s*\"\z([^"]\+\)\""		matchgroup=shHereDoc08 end="^\s*\z1\s*$"
418ShFoldHereDoc syn region shHereDoc matchgroup=shHereDoc09 start="<<\s*\\\_$\_s*\z([^ \t|>]\+\)"		matchgroup=shHereDoc09 end="^\z1\s*$"	contains=@shDblQuoteList
419ShFoldHereDoc syn region shHereDoc matchgroup=shHereDoc10 start="<<-\s*\\\_$\_s*\z([^ \t|>]\+\)"	matchgroup=shHereDoc10 end="^\s*\z1\s*$"	contains=@shDblQuoteList
420ShFoldHereDoc syn region shHereDoc matchgroup=shHereDoc11 start="<<\s*\\\_$\_s*\\\z([^ \t|>]\+\)"	matchgroup=shHereDoc11 end="^\z1\s*$"
421ShFoldHereDoc syn region shHereDoc matchgroup=shHereDoc12 start="<<-\s*\\\_$\_s*\\\z([^ \t|>]\+\)"	matchgroup=shHereDoc12 end="^\s*\z1\s*$"
422ShFoldHereDoc syn region shHereDoc matchgroup=shHereDoc13 start="<<\s*\\\_$\_s*'\z([^']\+\)'"		matchgroup=shHereDoc13 end="^\z1\s*$"
423ShFoldHereDoc syn region shHereDoc matchgroup=shHereDoc14 start="<<-\s*\\\_$\_s*'\z([^']\+\)'"		matchgroup=shHereDoc14 end="^\s*\z1\s*$"
424ShFoldHereDoc syn region shHereDoc matchgroup=shHereDoc15 start="<<\s*\\\_$\_s*\"\z([^"]\+\)\""		matchgroup=shHereDoc15 end="^\z1\s*$"
425ShFoldHereDoc syn region shHereDoc matchgroup=shHereDoc16 start="<<-\s*\\\_$\_s*\"\z([^"]\+\)\""	matchgroup=shHereDoc16 end="^\s*\z1\s*$"
426
427
428" Here Strings: {{{1
429" =============
430" available for: bash; ksh (really should be ksh93 only) but not if its a posix
431if exists("b:is_bash") || (exists("b:is_kornshell") && !exists("b:is_posix"))
432 syn match shHereString "<<<"	skipwhite	nextgroup=shCmdParenRegion
433endif
434
435" Identifiers: {{{1
436"=============
437syn match  shSetOption	"\s\zs[-+][a-zA-Z0-9]\+\>"	contained
438syn match  shVariable	"\<\h\w*\ze="			nextgroup=shVarAssign
439syn match  shVarAssign	"="		contained	nextgroup=shCmdParenRegion,shPattern,shDeref,shDerefSimple,shDoubleQuote,shExDoubleQuote,shSingleQuote,shExSingleQuote,shVar
440syn match  shVar	contained	"\h\w*"
441syn region shAtExpr	contained	start="@(" end=")" contains=@shIdList
442if exists("b:is_bash")
443 syn match  shSet "^\s*set\ze\s\+$"
444 syn region shSetList oneline matchgroup=shSet start="\<\%(declare\|local\|export\)\>\ze[/a-zA-Z_]\@!" end="$"	matchgroup=shSetListDelim end="\ze[}|);&]" matchgroup=NONE end="\ze\s\+#\|="	contains=@shIdList
445 syn region shSetList oneline matchgroup=shSet start="\<\%(set\|unset\)\>[/a-zA-Z_]\@!" end="\ze[;|#)]\|$"		matchgroup=shSetListDelim end="\ze[}|);&]" matchgroup=NONE end="\ze\s\+="	contains=@shIdList nextgroup=shComment
446elseif exists("b:is_kornshell") || exists("b:is_posix")
447 syn match  shSet "^\s*set\ze\s\+$"
448 if exists("b:is_dash")
449  syn region shSetList oneline matchgroup=shSet start="\<\%(local\)\>\ze[/]\@!" end="$"	                 matchgroup=shSetListDelim end="\ze[}|);&]" matchgroup=NONE end="\ze\s\+[#=]"	contains=@shIdList
450 endif
451 syn region shSetList oneline matchgroup=shSet start="\<\(export\)\>\ze[/]\@!" end="$"		matchgroup=shSetListDelim end="\ze[}|);&]" matchgroup=NONE end="\ze\s\+[#=]"	contains=@shIdList
452 syn region shSetList oneline matchgroup=shSet start="\<\%(set\|unset\>\)\ze[/a-zA-Z_]\@!" end="\ze[;|#)]\|$"		matchgroup=shSetListDelim end="\ze[}|);&]" matchgroup=NONE end="\ze\s\+[#=]"	contains=@shIdList nextgroup=shComment
453else
454 syn region shSetList oneline matchgroup=shSet start="\<\(set\|export\|unset\)\>\ze[/a-zA-Z_]\@!" end="\ze[;|#)]\|$"	matchgroup=shSetListDelim end="\ze[}|);&]" matchgroup=NONE end="\ze\s\+[#=]"	contains=@shIdList
455endif
456
457" Functions: {{{1
458if !exists("b:is_posix")
459 syn keyword shFunctionKey function	skipwhite skipnl nextgroup=shFunctionTwo
460endif
461
462if exists("b:is_bash")
463 ShFoldFunctions syn region shFunctionOne	matchgroup=shFunction start="^\s*[A-Za-z_0-9:][-a-zA-Z_0-9:]*\s*()\_s*{"		end="}"	contains=@shFunctionList		 skipwhite skipnl nextgroup=shFunctionStart,shQuickComment
464 ShFoldFunctions syn region shFunctionTwo	matchgroup=shFunction start="\%(do\)\@!\&\<[A-Za-z_0-9:][-a-zA-Z_0-9:]*\>\s*\%(()\)\=\_s*{"	end="}"	contains=shFunctionKey,@shFunctionList contained skipwhite skipnl nextgroup=shFunctionStart,shQuickComment
465 ShFoldFunctions syn region shFunctionThree	matchgroup=shFunction start="^\s*[A-Za-z_0-9:][-a-zA-Z_0-9:]*\s*()\_s*("		end=")"	contains=@shFunctionList		 skipwhite skipnl nextgroup=shFunctionStart,shQuickComment
466 ShFoldFunctions syn region shFunctionFour	matchgroup=shFunction start="\%(do\)\@!\&\<[A-Za-z_0-9:][-a-zA-Z_0-9:]*\>\s*\%(()\)\=\_s*)"	end=")"	contains=shFunctionKey,@shFunctionList contained skipwhite skipnl nextgroup=shFunctionStart,shQuickComment
467else
468 ShFoldFunctions syn region shFunctionOne	matchgroup=shFunction start="^\s*\h\w*\s*()\_s*{"			end="}"	contains=@shFunctionList		 skipwhite skipnl nextgroup=shFunctionStart,shQuickComment
469 ShFoldFunctions syn region shFunctionTwo	matchgroup=shFunction start="\%(do\)\@!\&\<\h\w*\>\s*\%(()\)\=\_s*{"		end="}"	contains=shFunctionKey,@shFunctionList contained skipwhite skipnl nextgroup=shFunctionStart,shQuickComment
470 ShFoldFunctions syn region shFunctionThree	matchgroup=shFunction start="^\s*\h\w*\s*()\_s*("			end=")"	contains=@shFunctionList		 skipwhite skipnl nextgroup=shFunctionStart,shQuickComment
471 ShFoldFunctions syn region shFunctionFour	matchgroup=shFunction start="\%(do\)\@!\&\<\h\w*\>\s*\%(()\)\=\_s*("		end=")"	contains=shFunctionKey,@shFunctionList contained skipwhite skipnl nextgroup=shFunctionStart,shQuickComment
472endif
473
474" Parameter Dereferencing: {{{1
475" ========================
476if !exists("g:sh_no_error")
477 syn match  shDerefWordError	"[^}$[~]"	contained
478endif
479syn match  shDerefSimple	"\$\%(\h\w*\|\d\)"	nextgroup=@shNoZSList
480syn region shDeref	matchgroup=PreProc start="\${" end="}"	contains=@shDerefList,shDerefVarArray nextgroup=shSpecialStart
481syn match  shDerefSimple	"\$[-#*@!?]"	nextgroup=@shNoZSList
482syn match  shDerefSimple	"\$\$"	nextgroup=@shNoZSList
483syn match  shDerefSimple	"\${\d}"	nextgroup=@shNoZSList	nextgroup=shSpecialStart
484if exists("b:is_bash") || exists("b:is_kornshell") || exists("b:is_posix")
485 syn region shDeref	matchgroup=PreProc start="\${##\=" end="}"	contains=@shDerefList	nextgroup=@shSpecialNoZS,shSpecialStart
486 syn region shDeref	matchgroup=PreProc start="\${\$\$" end="}"	contains=@shDerefList	nextgroup=@shSpecialNoZS,shSpecialStart
487endif
488
489" ksh: ${!var[*]} array index list syntax: {{{1
490" ========================================
491if exists("b:is_kornshell") || exists("b:is_posix")
492 syn region shDeref	matchgroup=PreProc start="\${!" end="}"	contains=@shDerefVarArray
493endif
494
495" bash: ${!prefix*} and ${#parameter}: {{{1
496" ====================================
497if exists("b:is_bash")
498 syn region shDeref	matchgroup=PreProc start="\${!" end="\*\=}"	contains=@shDerefList,shDerefOffset
499 syn match  shDerefVar	contained	"{\@<=!\h\w*"		nextgroup=@shDerefVarList
500endif
501if exists("b:is_kornshell")
502 syn match  shDerefVar	contained	"{\@<=!\h\w*[[:alnum:]_.]*"	nextgroup=@shDerefVarList
503endif
504
505syn match  shDerefSpecial	contained	"{\@<=[-*@?0]"		nextgroup=shDerefOp,shDerefOffset,shDerefOpError
506syn match  shDerefSpecial	contained	"\({[#!]\)\@<=[[:alnum:]*@_]\+"	nextgroup=@shDerefVarList,shDerefOp
507syn match  shDerefVar	contained	"{\@<=\h\w*"		nextgroup=@shDerefVarList
508syn match  shDerefVar	contained	'\d'                            nextgroup=@shDerefVarList
509if exists("b:is_kornshell") || exists("b:is_posix")
510  syn match  shDerefVar	contained	"{\@<=\h\w*[[:alnum:]_.]*"	nextgroup=@shDerefVarList
511endif
512
513" sh ksh bash : ${var[... ]...}  array reference: {{{1
514syn region  shDerefVarArray   contained	matchgroup=shDeref start="\[" end="]"	contains=@shCommandSubList nextgroup=shDerefOp,shDerefOpError
515
516" Special ${parameter OPERATOR word} handling: {{{1
517" sh ksh bash : ${parameter:-word}    word is default value
518" sh ksh bash : ${parameter:=word}    assign word as default value
519" sh ksh bash : ${parameter:?word}    display word if parameter is null
520" sh ksh bash : ${parameter:+word}    use word if parameter is not null, otherwise nothing
521"    ksh bash : ${parameter#pattern}  remove small left  pattern
522"    ksh bash : ${parameter##pattern} remove large left  pattern
523"    ksh bash : ${parameter%pattern}  remove small right pattern
524"    ksh bash : ${parameter%%pattern} remove large right pattern
525"        bash : ${parameter^pattern}  Case modification
526"        bash : ${parameter^^pattern} Case modification
527"        bash : ${parameter,pattern}  Case modification
528"        bash : ${parameter,,pattern} Case modification
529"        bash : ${@:start:qty}        display command line arguments from start to start+qty-1 (inferred)
530syn cluster shDerefPatternList	contains=shDerefPattern,shDerefString
531if !exists("g:sh_no_error")
532 syn match shDerefOpError	contained	":[[:punct:]]"
533endif
534syn match  shDerefOp	contained	":\=[-=?]"	nextgroup=@shDerefPatternList
535syn match  shDerefOp	contained	":\=+"	nextgroup=@shDerefPatternList
536if exists("b:is_bash") || exists("b:is_kornshell") || exists("b:is_posix")
537 syn match  shDerefOp	contained	"#\{1,2}"		nextgroup=@shDerefPatternList
538 syn match  shDerefOp	contained	"%\{1,2}"		nextgroup=@shDerefPatternList
539 syn match  shDerefPattern	contained	"[^{}]\+"		contains=shDeref,shDerefSimple,shDerefPattern,shDerefString,shCommandSub,shDerefEscape nextgroup=shDerefPattern
540 syn region shDerefPattern	contained	start="{" end="}"	contains=shDeref,shDerefSimple,shDerefString,shCommandSub nextgroup=shDerefPattern
541 syn match  shDerefEscape	contained	'\%(\\\\\)*\\.'
542endif
543if exists("b:is_bash")
544 syn match  shDerefOp	contained	"[,^]\{1,2}"	nextgroup=@shDerefPatternList
545endif
546syn region shDerefString	contained	matchgroup=shDerefDelim start=+\%(\\\)\@<!'+ end=+'+	contains=shStringSpecial
547syn region shDerefString	contained	matchgroup=shDerefDelim start=+\%(\\\)\@<!"+ skip=+\\"+ end=+"+	contains=@shDblQuoteList,shStringSpecial
548syn match  shDerefString	contained	"\\["']"	nextgroup=shDerefPattern
549
550if exists("b:is_bash") || exists("b:is_kornshell") || exists("b:is_posix")
551 " bash ksh posix : ${parameter:offset}
552 " bash ksh posix : ${parameter:offset:length}
553 syn region shDerefOffset	contained	start=':[^-=?+]' end='\ze:'	end='\ze}'	contains=shDeref,shDerefSimple,shDerefEscape	nextgroup=shDerefLen,shDeref,shDerefSimple
554 syn region shDerefOffset	contained	start=':\s-'	end='\ze:'	end='\ze}'	contains=shDeref,shDerefSimple,shDerefEscape	nextgroup=shDerefLen,shDeref,shDerefSimple
555 syn match  shDerefLen	contained	":[^}]\+"	contains=shDeref,shDerefSimple,shArithmetic
556endif
557
558if exists("b:is_bash")
559 " bash : ${parameter//pattern/string}
560 " bash : ${parameter//pattern}
561 syn match  shDerefPPS	contained	'/\{1,2}'	nextgroup=shDerefPPSleft
562 syn region shDerefPPSleft	contained	start='.'	skip=@\%(\\\\\)*\\/@ matchgroup=shDerefOp	end='/' end='\ze}' end='"'	nextgroup=shDerefPPSright	contains=@shPPSLeftList
563 syn region shDerefPPSright	contained	start='.'	skip=@\%(\\\\\)\+@		end='\ze}'				contains=@shPPSRightList
564
565 " bash : ${parameter/#substring/replacement}
566 syn match  shDerefPSR	contained	'/#'	nextgroup=shDerefPSRleft,shDoubleQuote,shSingleQuote
567 syn region shDerefPSRleft	contained	start='[^"']'	skip=@\%(\\\\\)*\\/@ matchgroup=shDerefOp	end='/' end='\ze}'	nextgroup=shDerefPSRright
568 syn region shDerefPSRright	contained	start='.'	skip=@\%(\\\\\)\+@		end='\ze}'
569endif
570
571" Arithmetic Parenthesized Expressions: {{{1
572"syn region shParen matchgroup=shArithRegion start='[^$]\zs(\%(\ze[^(]\|$\)' end=')' contains=@shArithParenList
573syn region shParen matchgroup=shArithRegion start='\$\@!(\%(\ze[^(]\|$\)' end=')' contains=@shArithParenList
574
575" Additional sh Keywords: {{{1
576" ===================
577syn keyword shStatement break cd chdir continue eval exec exit kill newgrp pwd read readonly return shift test trap ulimit umask wait
578syn keyword shConditional contained elif else then
579if !exists("g:sh_no_error")
580 syn keyword shCondError elif else then
581endif
582
583" Additional ksh Keywords and Aliases: {{{1
584" ===================================
585if exists("b:is_kornshell") || exists("b:is_posix")
586 syn keyword shStatement bg builtin disown enum export false fg getconf getopts hist jobs let printf sleep true unalias whence
587 syn keyword shStatement typeset skipwhite nextgroup=shSetOption
588 syn keyword shStatement autoload compound fc float functions hash history integer nameref nohup r redirect source stop suspend times type
589 if exists("b:is_posix")
590  syn keyword shStatement command
591 else
592  syn keyword shStatement time
593 endif
594
595" Additional bash Keywords: {{{1
596" =====================
597elseif exists("b:is_bash")
598 syn keyword shStatement bg builtin disown export false fg getopts jobs let printf sleep true unalias
599 syn keyword shStatement typeset nextgroup=shSetOption
600 syn keyword shStatement fc hash history source suspend times type
601 syn keyword shStatement bind builtin caller compopt declare dirs disown enable export help logout mapfile popd pushd readarray shopt source typeset
602else
603 syn keyword shStatement login newgrp
604endif
605
606" Synchronization: {{{1
607" ================
608if !exists("g:sh_minlines")
609 let s:sh_minlines = 200
610else
611 let s:sh_minlines= g:sh_minlines
612endif
613if !exists("g:sh_maxlines")
614 let s:sh_maxlines = 2*s:sh_minlines
615 if s:sh_maxlines < 25
616  let s:sh_maxlines= 25
617 endif
618else
619 let s:sh_maxlines= g:sh_maxlines
620endif
621exec "syn sync minlines=" . s:sh_minlines . " maxlines=" . s:sh_maxlines
622syn sync match shCaseEsacSync	grouphere	shCaseEsac	"\<case\>"
623syn sync match shCaseEsacSync	groupthere	shCaseEsac	"\<esac\>"
624syn sync match shDoSync	grouphere	shDo	"\<do\>"
625syn sync match shDoSync	groupthere	shDo	"\<done\>"
626syn sync match shForSync	grouphere	shFor	"\<for\>"
627syn sync match shForSync	groupthere	shFor	"\<in\>"
628syn sync match shIfSync	grouphere	shIf	"\<if\>"
629syn sync match shIfSync	groupthere	shIf	"\<fi\>"
630syn sync match shUntilSync	grouphere	shRepeat	"\<until\>"
631syn sync match shWhileSync	grouphere	shRepeat	"\<while\>"
632
633" Default Highlighting: {{{1
634" =====================
635if !exists("skip_sh_syntax_inits")
636 hi def link shArithRegion	shShellVariables
637 hi def link shAstQuote	shDoubleQuote
638 hi def link shAtExpr	shSetList
639 hi def link shBkslshSnglQuote	shSingleQuote
640 hi def link shBkslshDblQuote	shDOubleQuote
641 hi def link shBeginHere	shRedir
642 hi def link shCaseBar	shConditional
643 hi def link shCaseCommandSub	shCommandSub
644 hi def link shCaseDoubleQuote	shDoubleQuote
645 hi def link shCaseIn	shConditional
646 hi def link shQuote	shOperator
647 hi def link shCaseSingleQuote	shSingleQuote
648 hi def link shCaseStart	shConditional
649 hi def link shCmdSubRegion	shShellVariables
650 hi def link shColon	shComment
651 hi def link shDerefOp	shOperator
652 hi def link shDerefPOL	shDerefOp
653 hi def link shDerefPPS	shDerefOp
654 hi def link shDerefPSR	shDerefOp
655 hi def link shDeref	shShellVariables
656 hi def link shDerefDelim	shOperator
657 hi def link shDerefSimple	shDeref
658 hi def link shDerefSpecial	shDeref
659 hi def link shDerefString	shDoubleQuote
660 hi def link shDerefVar	shDeref
661 hi def link shDoubleQuote	shString
662 hi def link shEcho	shString
663 hi def link shEchoDelim	shOperator
664 hi def link shEchoQuote	shString
665 hi def link shForPP	shLoop
666 hi def link shFunction	Function
667 hi def link shEmbeddedEcho	shString
668 hi def link shEscape	shCommandSub
669 hi def link shExDoubleQuote	shDoubleQuote
670 hi def link shExSingleQuote	shSingleQuote
671 hi def link shHereDoc	shString
672 hi def link shHereString	shRedir
673 hi def link shHerePayload	shHereDoc
674 hi def link shLoop	shStatement
675 hi def link shSpecialNxt	shSpecial
676 hi def link shNoQuote	shDoubleQuote
677 hi def link shOption	shCommandSub
678 hi def link shPattern	shString
679 hi def link shParen	shArithmetic
680 hi def link shPosnParm	shShellVariables
681 hi def link shQuickComment	shComment
682 hi def link shBQComment	shComment
683 hi def link shRange	shOperator
684 hi def link shRedir	shOperator
685 hi def link shSetListDelim	shOperator
686 hi def link shSetOption	shOption
687 hi def link shSingleQuote	shString
688 hi def link shSource	shOperator
689 hi def link shStringSpecial	shSpecial
690 hi def link shSpecialStart	shSpecial
691 hi def link shSubShRegion	shOperator
692 hi def link shTestOpr	shConditional
693 hi def link shTestPattern	shString
694 hi def link shTestDoubleQuote	shString
695 hi def link shTestSingleQuote	shString
696 hi def link shTouchCmd	shStatement
697 hi def link shVariable	shSetList
698 hi def link shWrapLineOperator	shOperator
699
700 if exists("b:is_bash")
701   hi def link bashAdminStatement	shStatement
702   hi def link bashSpecialVariables	shShellVariables
703   hi def link bashStatement		shStatement
704   hi def link shCharClass		shSpecial
705   hi def link shDerefOffset		shDerefOp
706   hi def link shDerefLen		shDerefOffset
707 endif
708 if exists("b:is_kornshell") || exists("b:is_posix")
709   hi def link kshSpecialVariables	shShellVariables
710   hi def link kshStatement		shStatement
711 endif
712
713 if !exists("g:sh_no_error")
714  hi def link shCaseError		Error
715  hi def link shCondError		Error
716  hi def link shCurlyError		Error
717  hi def link shDerefOpError		Error
718  hi def link shDerefWordError		Error
719  hi def link shDoError		Error
720  hi def link shEsacError		Error
721  hi def link shIfError		Error
722  hi def link shInError		Error
723  hi def link shParenError		Error
724  hi def link shTestError		Error
725  if exists("b:is_kornshell") || exists("b:is_posix")
726    hi def link shDTestError		Error
727  endif
728 endif
729
730 hi def link shArithmetic		Special
731 hi def link shCharClass		Identifier
732 hi def link shSnglCase		Statement
733 hi def link shCommandSub		Special
734 hi def link shCommandSubBQ		shCommandSub
735 hi def link shComment		Comment
736 hi def link shConditional		Conditional
737 hi def link shCtrlSeq		Special
738 hi def link shExprRegion		Delimiter
739 hi def link shFunctionKey		Function
740 hi def link shFunctionName		Function
741 hi def link shNumber		Number
742 hi def link shOperator		Operator
743 hi def link shRepeat		Repeat
744 hi def link shSet		Statement
745 hi def link shSetList		Identifier
746 hi def link shShellVariables		PreProc
747 hi def link shSpecial		Special
748 hi def link shSpecialDQ		Special
749 hi def link shSpecialSQ		Special
750 hi def link shSpecialNoZS		shSpecial
751 hi def link shStatement		Statement
752 hi def link shString		String
753 hi def link shTodo		Todo
754 hi def link shAlias		Identifier
755 hi def link shHereDoc01		shRedir
756 hi def link shHereDoc02		shRedir
757 hi def link shHereDoc03		shRedir
758 hi def link shHereDoc04		shRedir
759 hi def link shHereDoc05		shRedir
760 hi def link shHereDoc06		shRedir
761 hi def link shHereDoc07		shRedir
762 hi def link shHereDoc08		shRedir
763 hi def link shHereDoc09		shRedir
764 hi def link shHereDoc10		shRedir
765 hi def link shHereDoc11		shRedir
766 hi def link shHereDoc12		shRedir
767 hi def link shHereDoc13		shRedir
768 hi def link shHereDoc14		shRedir
769 hi def link shHereDoc15		shRedir
770 hi def link shHereDoc16		shRedir
771endif
772
773" Delete shell folding commands {{{1
774" =============================
775delc ShFoldFunctions
776delc ShFoldHereDoc
777delc ShFoldIfDoFor
778
779" Set Current Syntax: {{{1
780" ===================
781if exists("b:is_bash")
782 let b:current_syntax = "bash"
783elseif exists("b:is_kornshell")
784 let b:current_syntax = "ksh"
785elseif exists("b:is_posix")
786 let b:current_syntax = "posix"
787else
788 let b:current_syntax = "sh"
789endif
790
791" vim: ts=16 fdm=marker
792