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