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