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