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