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