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