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