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