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