@@ -20,9 +20,18 @@ variables:
2020 float_suffix : (?i:[fdm](?!b))
2121 integer_suffix : (?i:ul?|lu?)
2222 bytes_unit : (?i:[kmgtp]b)
23+ kebab_break : (?![\w-])
2324
2425contexts :
2526
27+ pop-before-newline :
28+ - match : (?=\n|$)
29+ pop : true
30+
31+ pop-at-newline :
32+ - match : \n|$
33+ pop : true
34+
2635 main :
2736 - include : comments
2837 - include : redirection
@@ -61,75 +70,128 @@ contexts:
6170 - include : main
6271 - match : \b[\w.-]+\.(?i:exe|com|cmd|bat)\b
6372 scope : variable.function.powershell
64- - match : \b(?:(?i:begin|break|catch|continue|data|default|define|do|dynamicparam|else|elseif|end|exit|finally|for|foreach(?!-object)|from|if|in|inlinescript|parallel|param|process|return|switch|throw|trap|try|until|var|where(?!-object)|while)|%|\?)(?!\w)
73+ # Exceptions
74+ - match : \b(?i:throw){{kebab_break}}
75+ scope : keyword.control.exception.raise.powershell
76+ - match : \b(?i:try){{kebab_break}}
77+ scope : keyword.control.exception.try.powershell
78+ - match : \b(?i:catch|trap){{kebab_break}}
79+ scope : keyword.control.exception.catch.powershell
80+ - match : \b(?i:finally){{kebab_break}}
81+ scope : keyword.control.exception.finally.powershell
82+ # Conditionals
83+ - match : \b(?i:if){{kebab_break}}
84+ scope : keyword.control.conditional.if.powershell
85+ - match : \b(?i:elseif){{kebab_break}}
86+ scope : keyword.control.conditional.elseif.powershell
87+ - match : \b(?i:else){{kebab_break}}
88+ scope : keyword.control.conditional.else.powershell
89+ - match : \b(?i:switch){{kebab_break}}
90+ scope : keyword.control.conditional.switch.powershell
91+ - match : \?
92+ scope : keyword.control.conditional.select.powershell
93+ - match : \b(?i:where(?!-object)){{kebab_break}}
94+ scope : keyword.control.conditional.select.powershell
95+ # Begin/End
96+ - match : \b(?i:begin){{kebab_break}}
97+ scope : keyword.context.block.begin.powershell
98+ - match : \b(?i:end){{kebab_break}}
99+ scope : keyword.context.block.end.powershell
100+ # Loops
101+ - match : \b(?i:for|foreach(?!-object)){{kebab_break}}
102+ scope : keyword.control.loop.for.powershell
103+ - match : \b(?i:do){{kebab_break}}
104+ scope : keyword.control.loop.do-while.powershell
105+ - match : \b(?i:while){{kebab_break}}
106+ scope : keyword.control.loop.while.powershell
107+ - match : \b(?i:until){{kebab_break}}
108+ scope : keyword.control.loop.repeat-until.powershell
109+ # Flow
110+ - match : \b(?i:break){{kebab_break}}
111+ scope : keyword.control.flow.break.powershell
112+ - match : \b(?i:continue){{kebab_break}}
113+ scope : keyword.control.flow.continue.powershell
114+ - match : \b(?i:exit){{kebab_break}}
115+ scope : keyword.control.flow.exit.powershell
116+ - match : \b(?i:return){{kebab_break}}
117+ scope : keyword.control.flow.return.powershell
118+ # Declaration
119+ - match : \b(?i:var){{kebab_break}}
120+ # scope: storage.type.variable.powershell
121+ scope : keyword.declaration.variable.powershell
122+ - match : \b(?i:(?:dynamic)?param){{kebab_break}}
123+ scope : keyword.declaration.parameter.powershell # This scope is not standard
124+ # Uncategorized keywords
125+ - match : \b(?i:data|default|define|from|in|inlinescript|parallel|process){{kebab_break}}
65126 scope : keyword.control.powershell
66127 - match : \B--%\B
67128 scope : keyword.control.powershell
68129 push :
69130 - meta_content_scope : string.unquoted.powershell
70- - match : (?=\n|$)
71- pop : true
131+ - include : pop-before-newline
72132 - match : \b(?i:hidden|static)\b
73133 # This should only be relevant inside a class but will require a rework of how classes are matched. This is a temp fix.
74134 scope : storage.modifier.powershell
75- - match : \b((?i:class)|%|\?)(?:\s) +([\w-]+)\b
135+ - match : \b((?i:class))\s +([\w-]+)\b
76136 captures :
77137 1 : storage.type.class.powershell
78138 2 : meta.class.powershell entity.name.class.powershell
79139 # Operators...
80- - match : \B(-)(?i:as)\b
140+ - match : \B(-)(?i:as){{kebab_break}}
81141 scope : keyword.operator.cast.powershell
82142 captures :
83143 1 : punctuation.definition.keyword.powershell
84- - match : \B(-)(?i:[ic]?(?:eq|ne|[gl][te]))\b
144+ - match : \B(-)(?i:[ic]?(?:eq|ne|[gl][te])){{kebab_break}}
85145 scope : keyword.operator.comparison.powershell
86146 captures :
87147 1 : punctuation.definition.keyword.powershell
88- - match : \B(-)(?i:[ic]?(?:not)?(?:like|match|contains|in))\b
148+ - match : \B(-)(?i:[ic]?(?:not)?(?:like|match|contains|in)){{kebab_break}}
89149 scope : keyword.operator.logical.powershell
90150 captures :
91151 1 : punctuation.definition.keyword.powershell
92- - match : \B(-)(?i:join|split|replace)\b
152+ - match : \B(-)(?i:join|split|replace){{kebab_break}}
93153 scope : keyword.operator.string.powershell
94154 captures :
95155 1 : punctuation.definition.keyword.powershell
96- - match : \B(-)(?i:is(?:not)?)\b
156+ - match : \B(-)(?i:is(?:not)?){{kebab_break}}
97157 scope : keyword.operator.logical.powershell
98158 captures :
99159 1 : punctuation.definition.keyword.powershell
100- - match : \B(-)(?i:and|or|not|xor)\b|!
160+ - match : \B(-)(?i:and|or|not|xor){{kebab_break}}|! # <-- note `!`
101161 scope : keyword.operator.logical.powershell
102162 captures :
103163 1 : punctuation.definition.keyword.powershell
104- - match : \B(-)(?i:band|bor|bnot|bxor|sh[lr])\b
164+ - match : \B(-)(?i:band|bor|bnot|bxor|sh[lr]){{kebab_break}}
105165 scope : keyword.operator.bitwise.powershell
106166 captures :
107167 1 : punctuation.definition.keyword.powershell
108- - match : \B(-)(?i:f)\b
168+ - match : \B(-)(?i:f){{kebab_break}}
109169 scope : keyword.operator.string-format.powershell
110170 captures :
111171 1 : punctuation.definition.keyword.powershell
112172 # Flags/Options/Parameters
113- - match : \B([-/])[ \p{L}] (?:[\w-]*\w)?
173+ - match : \B([-/])\p{L}(?:[\w-]*\w)?
114174 scope : variable.parameter.option.powershell
115175 captures :
116176 1 : punctuation.definition.parameter.powershell
117- # operators continue...
177+ # Operators continue...
118178 - match : ' [+/*%-]?='
119179 scope : keyword.operator.assignment.powershell
120180 - match : (?:\+\+|--)(?![ \t]*\d)
121181 scope : keyword.operator.assignment.powershell
122- - match : ' [+-](?=\.?\d)'
182+ - match : ' [+-](?=\.?\d)' # This is sort of heuristic
123183 scope : keyword.operator.unary.powershell
124- - match : ' [+/*%-]'
184+ - match : ' [+/*-]'
185+ scope : keyword.operator.arithmetic.powershell
186+ - match : ' %(?!\s*\{)'
125187 scope : keyword.operator.arithmetic.powershell
126188 - match : \|\||&&
127189 scope : keyword.operator.logical.powershell
128190 - match : \|
129191 scope : keyword.operator.logical.pipe.powershell
130192 - match : ;
131193 scope : punctuation.terminator.statement.powershell
132- - match : \`
194+ - match : \`(?=\n|$)
133195 scope : punctuation.separator.continuation.line.powershell
134196 - match : ' ,'
135197 scope : punctuation.separator.sequence.powershell
@@ -167,8 +229,7 @@ contexts:
167229 2 : keyword.control.import.require.powershell
168230 push :
169231 - meta_scope : meta.requires.powershell
170- - match : \n|$
171- pop : true
232+ - include : pop-at-newline
172233 - include : hashtable
173234 - match : (-)(?i:Modules|PSSnapin|RunAsAdministrator|ShellId|Version)
174235 scope : variable.parameter.option.powershell
@@ -185,7 +246,14 @@ contexts:
185246 3 : variable.parameter.powershell
186247
187248 attribute :
188- - match : (\[)\s*\b(?i)(cmdletbinding|alias|outputtype|parameter|validatenotnull|validatenotnullorempty|validatecount|validateset|allownull|allowemptycollection|allowemptystring|validatescript|validaterange|validatepattern|validatelength)\b
249+ - match : |-
250+ (?xi:
251+ (\[)\s*
252+ (CmdletBinding|Alias|OutputType|Parameter
253+ |Validate(?:Count|NotNull(?:OrEmpty)?|Range|Pattern|Length|Set|Script)
254+ |Allow(?:Null|Empty(?:Collection|String))
255+ )\b
256+ )
189257 captures:
190258 1: punctuation.section.bracket.begin.powershell
191259 2: support.function.attribute.powershell
@@ -209,7 +277,14 @@ contexts:
209277 - include: type
210278 - include: numeric-constant
211279 - include: main
212- - match : (?i)\b(mandatory|valuefrompipeline|valuefrompipelinebypropertyname|valuefromremainingarguments|position|parametersetname|defaultparametersetname|supportsshouldprocess|positionalbinding|helpuri|confirmimpact|helpmessage)\b(?:\s+)?(=)
280+ - match: |-
281+ (?xi:
282+ \b(Mandatory|ValueFromPipeline(?:ByPropertyName)?
283+ |ValueFromRemainingArguments|Position
284+ |(?:Default)?ParameterSetName|SupportsShouldProcess
285+ |PositionalBinding|HelpUri|ConfirmImpact|HelpMessage)
286+ \s*(=)
287+ )
213288 captures:
214289 1: variable.parameter.attribute.powershell
215290 2: keyword.operator.assignment.powershell
@@ -224,11 +299,28 @@ contexts:
224299 pop: true
225300
226301 commands :
227- - match : (?:[\w\\:-]*\\)?\b(?i:Add|Approve|Assert|Backup|Block|Build|Checkpoint|Clear|Close|Compare|Complete|Compress|Confirm|Connect|Convert|ConvertFrom|ConvertTo|Copy|Debug|Deny|Deploy|Disable|Disconnect|Dismount|Edit|Enable|Enter|Exit|Expand|Export|Find|Format|Get|Grant|Group|Hide|Import|Initialize|Install|Invoke|Join|Limit|Lock|Measure|Merge|Mount|Move|New|Open|Optimize|Out|Ping|Pop|Protect|Publish|Push|Read|Receive|Redo|Register|Remove|Rename|Repair|Request|Reset|Resize|Resolve|Restart|Restore|Resume|Revoke|Save|Search|Select|Send|Set|Show|Skip|Split|Start|Step|Stop|Submit|Suspend|Switch|Sync|Test|Trace|Unblock|Undo|Uninstall|Unlock|Unprotect|Unpublish|Unregister|Update|Use|Wait|Watch|Write)\-.+?(?:\.(?i:exe|cmd|bat|ps1))?\b
228- # "Verb-Noun pattern:"
302+ # "Verb-Noun pattern:"
303+ - match : |-
304+ (?x:
305+ (?:[\w\\:-]*\\)? # Path stuff
306+ \b(?i:Add|Approve|Assert|Backup|Block|Build|Checkpoint|Clear|Close # "Official" Verbs
307+ |Compare|Complete|Compress|Confirm|Connect|Convert|ConvertFrom
308+ |ConvertTo|Copy|Debug|Deny|Deploy|Disable|Disconnect|Dismount|Edit
309+ |Enable|Enter|Exit|Expand|Export|Find|Format|Get|Grant|Group|Hide
310+ |Import|Initialize|Install|Invoke|Join|Limit|Lock|Measure|Merge
311+ |Mount|Move|New|Open|Optimize|Out|Ping|Pop|Protect|Publish|Push
312+ |Read|Receive|Redo|Register|Remove|Rename|Repair|Request|Reset
313+ |Resize|Resolve|Restart|Restore|Resume|Revoke|Save|Search|Select
314+ |Send|Set|Show|Skip|Split|Start|Step|Stop|Submit|Suspend|Switch
315+ |Sync|Test|Trace|Unblock|Undo|Uninstall|Unlock|Unprotect|Unpublish
316+ |Unregister|Update|Use|Wait|Watch|Write
317+ )
318+ \-\w+? # Any "noun"
319+ (?:\.(?i:exe|cmd|bat|ps1))?\b # More path stuff
320+ )
229321 scope: support.function.powershell
322+ # Builtin cmdlets with reserved verbs
230323 - match : \b(?i:(?:foreach|where|sort|tee)-object)\b
231- # Builtin cmdlets with reserved verbs
232324 scope : support.function.powershell
233325
234326 comment-block :
@@ -242,18 +334,25 @@ contexts:
242334 - include : comment-embedded-docs
243335
244336 comment-embedded-docs :
245- - match : ^\s*(\.)(?i:(COMPONENT|DESCRIPTION|EXAMPLE|EXTERNALHELP|FORWARDHELPCATEGORY|FORWARDHELPTARGETNAME|FUNCTIONALITY|INPUTS|LINK|NOTES|OUTPUTS|REMOTEHELPRUNSPACE|ROLE|SYNOPSIS))
337+ # TODO
338+ # https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_comment_based_help
339+ - match : |-
340+ (?xi:
341+ ^\s*(\.)
342+ (Component|Description|Example|ForwardHelpTargetName|Functionality
343+ |Inputs|Notes|Outputs|RemoteHelpRunSpace|Role|Synopsis)
344+ )
246345 scope: comment.documentation.embedded.powershell
247346 captures:
248347 1: punctuation.definition.keyword.documentation.powershell
249348 2: keyword.other.documentation.powershell
250- - match : ^\s*(\.)(?i:(PARAMETER )\s+([a-z0-9-_]+))
349+ - match : ^\s*(\.)(?i:(Parameter )\s+([a-z0-9-_]+))
251350 scope : comment.documentation.embedded.powershell
252351 captures :
253352 1 : punctuation.definition.keyword.documentation.powershell
254353 2 : keyword.other.documentation.param.powershell
255354 3 : variable.parameter.powershell
256- - match : ^\s*(\.)(?i:(FORWARDHELPTARGETNAME|FORWARDHELPCATEGORY|REMOTEHELPRUNSPACE|EXTERNALHELP )\s+([a-z0-9-_]+))
355+ - match : ^\s*(\.)(?i:(ForwardHelpTargetName|ForwardHelpCategory|ExternalHelp|Link )\s+([a-z0-9-_]+))
257356 scope : comment.documentation.embedded.powershell
258357 captures :
259358 1 : punctuation.definition.keyword.documentation.powershell
@@ -266,8 +365,7 @@ contexts:
266365 scope : punctuation.definition.comment.powershell
267366 push :
268367 - meta_scope : comment.line.powershell
269- - match : \n|$
270- pop : true
368+ - include : pop-at-newline
271369 - include : comment-embedded-docs
272370
273371 strings :
@@ -431,16 +529,19 @@ contexts:
431529 3 : keyword.other.unit.powershell
432530
433531 script-block :
434- - match : \{
435- scope : punctuation.section.braces.begin.powershell
532+ - match : (%)?(\{)
533+ captures :
534+ 1 : keyword.control.loop.for.powershell
535+ 2 : punctuation.section.braces.begin.powershell
436536 push :
437- - meta_scope : meta.scriptblock .powershell
537+ - meta_scope : meta.block .powershell
438538 - match : \}
439539 scope : punctuation.section.braces.end.powershell
440540 pop : true
441541 - include : main
442542
443543 type :
544+ # TODO: push a maybe-static-members context
444545 - match : \[
445546 scope : punctuation.section.bracket.begin.powershell
446547 push :
@@ -585,14 +686,13 @@ contexts:
585686 1 : punctuation.definition.variable.powershell
586687 2 : storage.modifier.scope.powershell
587688 3 : variable.other.readwrite.powershell
588- 4 : entity.name.function.invocation.powershell
589689 - match : (?i:(\$)(\{)(global|local|private|script|using|workflow):([^}]*[^}`])(\}))
590690 captures :
591691 1 : punctuation.definition.variable.powershell
592- 2 : storage.modifier.scope.powershell
593- 3 : variable.other.readwrite .powershell
594- 4 : keyword .other.powershell
595- 5 : entity.name.function.invocation.powershell
692+ 2 : punctuation.section.braces.begin
693+ 3 : storage.modifier.scope .powershell
694+ 4 : variable .other.readwrite .powershell
695+ 5 : punctuation.section.braces.end
596696 - match : (?i:(\$)(\w+:)?\w+)
597697 scope : variable.other.readwrite.powershell
598698 captures :
0 commit comments