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