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