xref: /vim-8.2.3635/runtime/syntax/sh.vim (revision 044b68f4)
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:		Dec 12, 2006
6" Version:		89
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
209else
210 syn region  shCaseExSingleQuote	matchgroup=Error start=+\$'+ skip=+\\\\\|\\.+ end=+'+	contains=shStringSpecial	skipwhite skipnl nextgroup=shCaseBar	contained
211endif
212syn region  shCaseSingleQuote	matchgroup=shOperator start=+'+ end=+'+		contains=shStringSpecial		skipwhite skipnl nextgroup=shCaseBar	contained
213syn region  shCaseDoubleQuote	matchgroup=shOperator start=+"+ skip=+\\\\\|\\.+ end=+"+	contains=@shDblQuoteList,shStringSpecial	skipwhite skipnl nextgroup=shCaseBar	contained
214syn region  shCaseCommandSub	start=+`+ skip=+\\\\\|\\.+ end=+`+		contains=@shCommandSubList		skipwhite skipnl nextgroup=shCaseBar	contained
215
216" Misc: {{{1
217"======
218syn match   shWrapLineOperator "\\$"
219syn region  shCommandSub   start="`" skip="\\\\\|\\." end="`" contains=@shCommandSubList
220
221" $() and $(()): {{{1
222" $(..) is not supported by sh (Bourne shell).  However, apparently
223" some systems (HP?) have as their /bin/sh a (link to) Korn shell
224" (ie. Posix compliant shell).  /bin/ksh should work for those
225" systems too, however, so the following syntax will flag $(..) as
226" an Error under /bin/sh.  By consensus of vimdev'ers!
227if exists("b:is_kornshell") || exists("b:is_bash")
228 syn region shCommandSub matchgroup=shCmdSubRegion start="\$("  skip='\\\\\|\\.' end=")"  contains=@shCommandSubList
229 syn region shArithmetic matchgroup=shArithRegion  start="\$((" skip='\\\\\|\\.' end="))" contains=@shCommandSubList
230 syn match  shSkipInitWS contained	"^\s\+"
231else
232 syn region shCommandSub matchgroup=Error start="\$(" end=")" contains=@shCommandSubList
233endif
234
235if exists("b:is_bash")
236 syn cluster shCommandSubList add=bashSpecialVariables,bashStatement
237 syn cluster shCaseList add=bashAdminStatement,bashStatement
238 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
239 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
240 syn keyword bashAdminStatement daemon killall killproc nice reload restart start status stop
241endif
242
243if exists("b:is_kornshell")
244 syn cluster shCommandSubList add=kshSpecialVariables,kshStatement
245 syn cluster shCaseList add=kshStatement
246 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
247 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
248endif
249
250syn match   shSource	"^\.\s"
251syn match   shSource	"\s\.\s"
252syn region  shColon	start="^\s*:" end="$\|" end="#"me=e-1 contains=@shColonList
253
254" String And Character Constants: {{{1
255"================================
256syn match   shNumber	"-\=\<\d\+\>#\="
257syn match   shCtrlSeq	"\\\d\d\d\|\\[abcfnrtv0]"		contained
258if exists("b:is_bash")
259 syn match   shSpecial	"\\\o\o\o\|\\x\x\x\|\\c.\|\\[abefnrtv]"	contained
260endif
261if exists("b:is_bash")
262 syn region  shExSingleQuote	matchgroup=shOperator start=+\$'+ skip=+\\\\\|\\.+ end=+'+	contains=shStringSpecial,shSpecial
263else
264 syn region  shExSingleQuote	matchGroup=Error start=+\$'+ skip=+\\\\\|\\.+ end=+'+	contains=shStringSpecial
265endif
266syn region  shSingleQuote	matchgroup=shOperator start=+'+ end=+'+		contains=shStringSpecial,@Spell
267syn region  shDoubleQuote	matchgroup=shOperator start=+"+ skip=+\\"+ end=+"+	contains=@shDblQuoteList,shStringSpecial,@Spell
268syn match   shStringSpecial	"[^[:print:]]"	contained
269syn match   shStringSpecial	"\%(\\\\\)*\\[\\"'`$()#]"
270syn match   shSpecial	"[^\\]\zs\%(\\\\\)*\\[\\"'`$()#]"
271syn match   shSpecial	"^\%(\\\\\)*\\[\\"'`$()#]"
272
273" Comments: {{{1
274"==========
275syn cluster    shCommentGroup	contains=shTodo,@Spell
276syn keyword    shTodo	contained	COMBAK FIXME TODO XXX
277syn match      shComment	"^\s*\zs#.*$"	contains=@shCommentGroup
278syn match      shComment	"#.*$"	contains=@shCommentGroup
279
280" Here Documents: {{{1
281" =========================================
282if version < 600
283 syn region shHereDoc matchgroup=shRedir start="<<\s*\**END[a-zA-Z_0-9]*\**"  matchgroup=shRedir end="^END[a-zA-Z_0-9]*$" contains=@shDblQuoteList
284 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
285 syn region shHereDoc matchgroup=shRedir start="<<\s*\**EOF\**"	matchgroup=shRedir	end="^EOF$"	contains=@shDblQuoteList
286 syn region shHereDoc matchgroup=shRedir start="<<-\s*\**EOF\**" matchgroup=shRedir	end="^\s*EOF$"	contains=@shDblQuoteList
287 syn region shHereDoc matchgroup=shRedir start="<<\s*\**\.\**"	matchgroup=shRedir	end="^\.$"	contains=@shDblQuoteList
288 syn region shHereDoc matchgroup=shRedir start="<<-\s*\**\.\**"	matchgroup=shRedir	end="^\s*\.$"	contains=@shDblQuoteList
289
290elseif g:sh_fold_enabled
291 syn region shHereDoc matchgroup=shRedir fold start="<<\s*\z(\S*\)"		matchgroup=shRedir end="^\z1\s*$"	contains=@shDblQuoteList
292 syn region shHereDoc matchgroup=shRedir fold start="<<\s*\"\z(\S*\)\""		matchgroup=shRedir end="^\z1\s*$"
293 syn region shHereDoc matchgroup=shRedir fold start="<<\s*'\z(\S*\)'"		matchgroup=shRedir end="^\z1\s*$"
294 syn region shHereDoc matchgroup=shRedir fold start="<<-\s*\z(\S*\)"		matchgroup=shRedir end="^\s*\z1\s*$"	contains=@shDblQuoteList
295 syn region shHereDoc matchgroup=shRedir fold start="<<-\s*\"\z(\S*\)\""		matchgroup=shRedir end="^\s*\z1\s*$"
296 syn region shHereDoc matchgroup=shRedir fold start="<<-\s*'\z(\S*\)'"		matchgroup=shRedir end="^\s*\z1\s*$"
297 syn region shHereDoc matchgroup=shRedir fold start="<<\s*\\\_$\_s*\z(\S*\)"		matchgroup=shRedir end="^\z1\s*$"
298 syn region shHereDoc matchgroup=shRedir fold start="<<\s*\\\_$\_s*\"\z(\S*\)\""	matchgroup=shRedir end="^\z1\s*$"
299 syn region shHereDoc matchgroup=shRedir fold start="<<-\s*\\\_$\_s*'\z(\S*\)'"		matchgroup=shRedir end="^\s*\z1\s*$"
300 syn region shHereDoc matchgroup=shRedir fold start="<<-\s*\\\_$\_s*\z(\S*\)"		matchgroup=shRedir end="^\s*\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="^\z1\s*$"
303 syn region shHereDoc matchgroup=shRedir fold start="<<\\\z(\S*\)"		matchgroup=shRedir end="^\z1\s*$"
304
305else
306 syn region shHereDoc matchgroup=shRedir start="<<\s*\\\=\z(\S*\)"	matchgroup=shRedir end="^\z1\s*$"    contains=@shDblQuoteList
307 syn region shHereDoc matchgroup=shRedir start="<<\s*\"\z(\S*\)\""	matchgroup=shRedir end="^\z1\s*$"
308 syn region shHereDoc matchgroup=shRedir start="<<-\s*\z(\S*\)"		matchgroup=shRedir end="^\s*\z1\s*$" contains=@shDblQuoteList
309 syn region shHereDoc matchgroup=shRedir start="<<-\s*'\z(\S*\)'"	matchgroup=shRedir end="^\s*\z1\s*$"
310 syn region shHereDoc matchgroup=shRedir start="<<\s*'\z(\S*\)'"	matchgroup=shRedir end="^\z1\s*$"
311 syn region shHereDoc matchgroup=shRedir start="<<-\s*\"\z(\S*\)\""	matchgroup=shRedir end="^\s*\z1\s*$"
312 syn region shHereDoc matchgroup=shRedir start="<<\s*\\\_$\_s*\z(\S*\)"	matchgroup=shRedir end="^\z1\s*$"
313 syn region shHereDoc matchgroup=shRedir start="<<-\s*\\\_$\_s*\z(\S*\)"	matchgroup=shRedir end="^\s*\z1\s*$"
314 syn region shHereDoc matchgroup=shRedir start="<<-\s*\\\_$\_s*'\z(\S*\)'"	matchgroup=shRedir end="^\s*\z1\s*$"
315 syn region shHereDoc matchgroup=shRedir start="<<\s*\\\_$\_s*'\z(\S*\)'"	matchgroup=shRedir end="^\z1\s*$"
316 syn region shHereDoc matchgroup=shRedir start="<<\s*\\\_$\_s*\"\z(\S*\)\""	matchgroup=shRedir end="^\z1\s*$"
317 syn region shHereDoc matchgroup=shRedir start="<<-\s*\\\_$\_s*\"\z(\S*\)\""	matchgroup=shRedir end="^\s*\z1\s*$"
318 syn region shHereDoc matchgroup=shRedir start="<<\\\z(\S*\)"		matchgroup=shRedir end="^\z1\s*$"
319endif
320
321" Here Strings: {{{1
322" =============
323if exists("b:is_bash")
324 syn match shRedir "<<<"
325endif
326
327" Identifiers: {{{1
328"=============
329syn match  shVariable "\<\([bwglsav]:\)\=[a-zA-Z0-9.!@_%+,]*\ze="	nextgroup=shSetIdentifier
330syn match  shIdWhiteSpace  contained	"\s"
331syn match  shSetIdentifier contained	"="	nextgroup=shPattern,shDeref,shDerefSimple,shDoubleQuote,shSingleQuote,shExSingleQuote
332if exists("b:is_bash")
333  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
334  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
335  syn match  shSet "\<\(declare\|typeset\|local\|export\|set\|unset\)\>"
336elseif exists("b:is_kornshell")
337  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
338  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
339  syn match  shSet "\<\(typeset\|set\|export\|unset\)\>"
340else
341  syn region shSetList matchgroup=shSet start="\<\(set\|export\|unset\)\>\ze[^/]" end="$\|\ze[|)]"	matchgroup=shOperator end="\ze[|);&]" matchgroup=NONE end="[#=]"me=e-1 contains=@shIdList
342  syn match  shStatement "\<\(set\|export\|unset\)\>"
343endif
344
345" Functions: {{{1
346syn keyword shFunctionKey function	skipwhite skipnl nextgroup=shFunctionTwo
347" COMBAK -- look at bash09.  function foo() (line#35) is folding 38 lines.  Not being terminated properly
348"syn match   shFunctionStart	"{"	contained
349if g:sh_fold_enabled
350 syn region shFunctionOne transparent fold	start="^\s*\h\w*\s*()\_s*\ze{"    matchgroup=shFunctionStart end="}"	contains=@shFunctionList			skipwhite skipnl nextgroup=shFunctionStart
351 syn region shFunctionTwo transparent fold	start="\h\w*\s*\%(()\)\=\_s*\ze{" matchgroup=shFunctionStart end="}"	contains=shFunctionKey,@shFunctionList contained	skipwhite skipnl nextgroup=shFunctionStart
352else
353 syn region shFunctionOne transparent	start="^\s*\h\w*\s*()\_s*\ze{"    matchgroup=shFunctionStart end="}"	contains=@shFunctionList
354 syn region shFunctionTwo transparent	start="\h\w*\s*\%(()\)\=\_s*\ze{" matchgroup=shFunctionStart end="}"	contains=shFunctionKey,@shFunctionList contained
355endif
356
357" Parameter Dereferencing: {{{1
358" ========================
359syn match  shDerefSimple	"\$\%(\h\w*\|\d\)"
360syn region shDeref	matchgroup=PreProc start="\${" end="}"	contains=@shDerefList,shDerefVarArray
361syn match  shDerefWordError	"[^}$[]"	contained
362syn match  shDerefSimple	"\$[-#*@!?]"
363syn match  shDerefSimple	"\$\$"
364if exists("b:is_bash") || exists("b:is_kornshell")
365 syn region shDeref	matchgroup=PreProc start="\${##\=" end="}"	contains=@shDerefList
366endif
367
368" bash: ${!prefix*} and ${#parameter}: {{{1
369" ====================================
370if exists("b:is_bash")
371 syn region shDeref	matchgroup=PreProc start="\${!" end="\*\=}"	contains=@shDerefList,shDerefOp
372 syn match  shDerefVar	contained	"{\@<=!\w\+"		nextgroup=@shDerefVarList
373endif
374
375syn match  shDerefSpecial	contained	"{\@<=[-*@?0]"		nextgroup=shDerefOp,shDerefOpError
376syn match  shDerefSpecial	contained	"\({[#!]\)\@<=[[:alnum:]*@_]\+"	nextgroup=@shDerefVarList,shDerefOp
377syn match  shDerefVar	contained	"{\@<=\w\+"		nextgroup=@shDerefVarList
378
379" sh ksh bash : ${var[... ]...}  array reference: {{{1
380syn region  shDerefVarArray   contained	matchgroup=shDeref start="\[" end="]"	contains=@shCommandSubList nextgroup=shDerefOp,shDerefOpError
381
382" Special ${parameter OPERATOR word} handling: {{{1
383" sh ksh bash : ${parameter:-word}    word is default value
384" sh ksh bash : ${parameter:=word}    assign word as default value
385" sh ksh bash : ${parameter:?word}    display word if parameter is null
386" sh ksh bash : ${parameter:+word}    use word if parameter is not null, otherwise nothing
387"    ksh bash : ${parameter#pattern}  remove small left  pattern
388"    ksh bash : ${parameter##pattern} remove large left  pattern
389"    ksh bash : ${parameter%pattern}  remove small right pattern
390"    ksh bash : ${parameter%%pattern} remove large right pattern
391syn cluster shDerefPatternList	contains=shDerefPattern,shDerefString
392syn match shDerefOpError	contained	":[[:punct:]]"
393syn match  shDerefOp	contained	":\=[-=?]"	nextgroup=@shDerefPatternList
394syn match  shDerefOp	contained	":\=+"	nextgroup=@shDerefPatternList
395if exists("b:is_bash") || exists("b:is_kornshell")
396 syn match  shDerefOp	contained	"#\{1,2}"	nextgroup=@shDerefPatternList
397 syn match  shDerefOp	contained	"%\{1,2}"	nextgroup=@shDerefPatternList
398 syn match  shDerefPattern	contained	"[^{}]\+"	contains=shDeref,shDerefSimple,shDerefPattern,shDerefString,shCommandSub,shDerefEscape nextgroup=shDerefPattern
399 syn region shDerefPattern	contained	start="{" end="}"	contains=shDeref,shDerefSimple,shDerefString,shCommandSub nextgroup=shDerefPattern
400 syn match  shDerefEscape	contained	'\%(\\\\\)*\\.'
401endif
402syn region shDerefString	contained	matchgroup=shOperator start=+'+ end=+'+		contains=shStringSpecial
403syn region shDerefString	contained	matchgroup=shOperator start=+"+ skip=+\\"+ end=+"+	contains=@shDblQuoteList,shStringSpecial
404syn match  shDerefString	contained	"\\["']"
405
406if exists("b:is_bash")
407 " bash : ${parameter:offset}
408 " bash : ${parameter:offset:length}
409 syn region shDerefOp	contained	start=":[$[:alnum:]_]"me=e-1 end=":"me=e-1 end="}"me=e-1 contains=@shCommandSubList nextgroup=shDerefPOL
410 syn match  shDerefPOL	contained	":[^}]\+"	contains=@shCommandSubList
411
412 " bash : ${parameter//pattern/string}
413 " bash : ${parameter//pattern}
414 syn match  shDerefPPS	contained	'/\{1,2}'	nextgroup=shDerefPPSleft
415 syn region shDerefPPSleft	contained	start='.'	skip=@\%(\\\)\/@ matchgroup=shDerefOp end='/' end='\ze}' nextgroup=shDerefPPSright contains=@shCommandSubList
416 syn region shDerefPPSright	contained	start='.'	end='\ze}'	contains=@shCommandSubList
417endif
418
419" Useful sh Keywords: {{{1
420" ===================
421syn keyword shStatement break cd chdir continue eval exec exit kill newgrp pwd read readonly return shift test trap ulimit umask wait
422syn keyword shConditional contained elif else then
423syn keyword shCondError elif else then
424
425" Useful ksh Keywords: {{{1
426" ====================
427if exists("b:is_kornshell") || exists("b:is_bash")
428 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
429
430" Useful bash Keywords: {{{1
431" =====================
432 if exists("b:is_bash")
433  syn keyword shStatement bind builtin dirs disown enable help local logout popd pushd shopt source
434 else
435  syn keyword shStatement login newgrp
436 endif
437endif
438
439" Synchronization: {{{1
440" ================
441if !exists("sh_minlines")
442  let sh_minlines = 200
443endif
444if !exists("sh_maxlines")
445  let sh_maxlines = 2 * sh_minlines
446endif
447exec "syn sync minlines=" . sh_minlines . " maxlines=" . sh_maxlines
448syn sync match shCaseEsacSync	grouphere	shCaseEsac	"\<case\>"
449syn sync match shCaseEsacSync	groupthere	shCaseEsac	"\<esac\>"
450syn sync match shDoSync	grouphere	shDo	"\<do\>"
451syn sync match shDoSync	groupthere	shDo	"\<done\>"
452syn sync match shForSync	grouphere	shFor	"\<for\>"
453syn sync match shForSync	groupthere	shFor	"\<in\>"
454syn sync match shIfSync	grouphere	shIf	"\<if\>"
455syn sync match shIfSync	groupthere	shIf	"\<fi\>"
456syn sync match shUntilSync	grouphere	shRepeat	"\<until\>"
457syn sync match shWhileSync	grouphere	shRepeat	"\<while\>"
458
459" Default Highlighting: {{{1
460" =====================
461hi def link shArithRegion	shShellVariables
462hi def link shBeginHere	shRedir
463hi def link shCaseBar	shConditional
464hi def link shCaseCommandSub	shCommandSub
465hi def link shCaseDoubleQuote	shDoubleQuote
466hi def link shCaseIn	shConditional
467hi def link shCaseSingleQuote	shSingleQuote
468hi def link shCaseStart	shConditional
469hi def link shCmdSubRegion	shShellVariables
470hi def link shColon	shStatement
471hi def link shDerefOp	shOperator
472hi def link shDerefPOL	shDerefOp
473hi def link shDerefPPS	shDerefOp
474hi def link shDeref	shShellVariables
475hi def link shDerefSimple	shDeref
476hi def link shDerefSpecial	shDeref
477hi def link shDerefString	shDoubleQuote
478hi def link shDerefVar	shDeref
479hi def link shDoubleQuote	shString
480hi def link shEcho	shString
481hi def link shEmbeddedEcho	shString
482hi def link shExSingleQuote	shSingleQuote
483hi def link shFunctionStart	Delimiter
484hi def link shHereDoc	shString
485hi def link shHerePayload	shHereDoc
486hi def link shLoop	shStatement
487hi def link shOption	shCommandSub
488hi def link shPattern	shString
489hi def link shPosnParm	shShellVariables
490hi def link shRange	shOperator
491hi def link shRedir	shOperator
492hi def link shSingleQuote	shString
493hi def link shSource	shOperator
494hi def link shStringSpecial	shSpecial
495hi def link shSubShRegion	shOperator
496hi def link shTestOpr	shConditional
497hi def link shTestPattern	shString
498hi def link shTestDoubleQuote	shString
499hi def link shTestSingleQuote	shString
500hi def link shVariable	shSetList
501hi def link shWrapLineOperator	shOperator
502
503if exists("b:is_bash")
504  hi def link bashAdminStatement	shStatement
505  hi def link bashSpecialVariables	shShellVariables
506  hi def link bashStatement		shStatement
507  hi def link shFunctionParen		Delimiter
508  hi def link shFunctionDelim		Delimiter
509endif
510if exists("b:is_kornshell")
511  hi def link kshSpecialVariables	shShellVariables
512  hi def link kshStatement		shStatement
513  hi def link shFunctionParen		Delimiter
514endif
515
516hi def link shCaseError		Error
517hi def link shCondError		Error
518hi def link shCurlyError		Error
519hi def link shDerefError		Error
520hi def link shDerefOpError		Error
521hi def link shDerefWordError		Error
522hi def link shDoError		Error
523hi def link shEsacError		Error
524hi def link shIfError		Error
525hi def link shInError		Error
526hi def link shParenError		Error
527hi def link shTestError		Error
528if exists("b:is_kornshell")
529  hi def link shDTestError		Error
530endif
531
532hi def link shArithmetic		Special
533hi def link shCharClass		Identifier
534hi def link shSnglCase		Statement
535hi def link shCommandSub		Special
536hi def link shComment		Comment
537hi def link shConditional		Conditional
538hi def link shCtrlSeq		Special
539hi def link shExprRegion		Delimiter
540hi def link shFunctionKey		Function
541hi def link shFunctionName		Function
542hi def link shNumber		Number
543hi def link shOperator		Operator
544hi def link shRepeat		Repeat
545hi def link shSet		Statement
546hi def link shSetList		Identifier
547hi def link shShellVariables		PreProc
548hi def link shSpecial		Special
549hi def link shStatement		Statement
550hi def link shString		String
551hi def link shTodo		Todo
552hi def link shAlias		Identifier
553
554" Set Current Syntax: {{{1
555" ===================
556if exists("b:is_bash")
557 let b:current_syntax = "bash"
558elseif exists("b:is_kornshell")
559 let b:current_syntax = "ksh"
560else
561 let b:current_syntax = "sh"
562endif
563
564" vim: ts=16 fdm=marker
565