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