From 80fb91889456e888b1a69e214c78f26f9986ef83 Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Thu, 4 Dec 2025 16:41:25 -0500 Subject: [PATCH 01/81] Reorder and rename many contexts --- PowerShell.sublime-syntax | 487 ++++++++++++++++--------------- Tests/syntax_test_PowerShell.ps1 | 2 +- 2 files changed, 258 insertions(+), 231 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index 6372d331..7a4d3f94 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -1,6 +1,6 @@ %YAML 1.2 --- -# http://www.sublimetext.com/docs/3/syntax.html +# http://www.sublimetext.com/docs/syntax.html name: PowerShell scope: source.powershell version: 2 @@ -16,23 +16,9 @@ first_line_match: |- | ^\# \s* -\*- [^*]* mode: \s* powershell [^*]* -\*- ) -variables: - dec_exponent: (?:[eE][-+]?\d*) - dec_suffix: '[dD]' - float_suffix: '[dDlL]' - int_suffix: (?i:u[lsy]?|[lnsy]) - unit_suffix: (?i:[kmgtp]b\b) - kebab_break: (?![\w-]) - contexts: - - pop-before-newline: - - match: (?=\n|$) - pop: true - - pop-at-newline: - - match: \n|$ - pop: true + # prototype: + # - include: comments main: - include: regions @@ -42,18 +28,18 @@ contexts: expressions: - include: redirection - include: commands - - include: variable - - include: group - - include: function - - include: attribute - - include: using-directive - - include: type - - include: hashtable + - include: variables + - include: groups + - include: functions + - include: attributes + - include: using-directives + - include: types + - include: hashtables - include: strings - - include: script-block - - include: escape-characters - - include: numeric-constant - - include: class-method + - include: script-blocks + - include: escape-sequences + - include: numbers + - include: class-methods - match: (@)(\() captures: 1: keyword.other.array.begin.powershell @@ -144,7 +130,7 @@ contexts: scope: keyword.control.powershell push: - meta_content_scope: string.unquoted.powershell - - include: pop-before-newline + - include: pop-before-eol - match: \b(?i:hidden|static)\b # This should only be relevant inside a class but will require a rework of how classes are matched. This is a temp fix. scope: storage.modifier.powershell @@ -217,10 +203,6 @@ contexts: # This is very imprecise. Is there a syntax for 'must come after...'? scope: keyword.operator.range.powershell - comments: - - include: comment-block - - include: comment-line - redirection: # https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_redirection - match: ([2-6*])(>&)(1) @@ -237,7 +219,7 @@ contexts: # - match: <+ # scope: invalid.illegal.powershell - requires-directive: + requires-directives: # TODO: add back `(?<=#)`-equivalent match - match: (#)((?i:requires))\s captures: @@ -245,8 +227,8 @@ contexts: 2: keyword.control.import.require.powershell push: - meta_scope: meta.requires.powershell - - include: pop-at-newline - - include: hashtable + - include: pop-eol + - include: hashtables - match: (-)(?i:Modules|PSSnapin|RunAsAdministrator|ShellId|Version) scope: variable.parameter.option.powershell captures: @@ -254,14 +236,14 @@ contexts: - match: ',' scope: punctuation.separator.powershell - using-directive: + using-directives: - match: \b(?i:(using))\s+(?i:(namespace|module))\s+(?i:((?:\w+(?:\.)?)+)) captures: 1: keyword.control.using.powershell 2: keyword.other.powershell 3: variable.parameter.powershell - attribute: + attributes: - match: |- (?xi: (\[)\s* @@ -288,14 +270,14 @@ contexts: - match: \) scope: punctuation.section.group.end.powershell pop: true - - include: variable - - include: variable-no-property - - include: hashtable - - include: script-block - - include: escape-characters - - include: double-quoted-string - - include: type - - include: numeric-constant + - include: variables + - include: variables-without-property + - include: hashtables + - include: script-blocks + - include: escape-sequences + - include: double-quoted-strings + - include: types + - include: numbers - include: main - match: |- (?xi: @@ -349,54 +331,6 @@ contexts: - match: \b(?i:(?:foreach|where|sort|tee)-object)\b scope: support.function.powershell - comment-block: - - match: <# - scope: punctuation.definition.comment.block.begin.powershell - push: - - meta_scope: comment.block.powershell - - match: '#>' - scope: punctuation.definition.comment.block.end.powershell - pop: true - - include: comment-embedded-docs - - comment-embedded-docs: - # TODO - # https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_comment_based_help - - match: |- - (?xi: - ^\s*(\.) - ( - Component | Description | Example | ExternalHelp | ForwardHelpCategory | ForwardHelpTargetName - | Functionality | Inputs | Link | Notes | Outputs | Parameter | RemoteHelpRunSpace - | Role | Synopsis - ) - ) - scope: comment.documentation.embedded.powershell - captures: - 1: punctuation.definition.keyword.documentation.powershell - 2: keyword.other.documentation.powershell - - match: ^\s*(\.)(?i:(Parameter)\s+([a-z0-9-_]+)) - scope: comment.documentation.embedded.powershell - captures: - 1: punctuation.definition.keyword.documentation.powershell - 2: keyword.other.documentation.param.powershell - 3: variable.parameter.powershell - - match: ^\s*(\.)(?i:(ForwardHelpTargetName|ForwardHelpCategory|ExternalHelp|Link)\s+([a-z0-9-_]+)) - scope: comment.documentation.embedded.powershell - captures: - 1: punctuation.definition.keyword.documentation.powershell - 2: keyword.other.documentation.powershell - 3: markup.underline.link.powershell - - comment-line: - - include: requires-directive - - match: '#' - scope: punctuation.definition.comment.powershell - push: - - meta_scope: comment.line.powershell - - include: pop-at-newline - - include: comment-embedded-docs - static-members: # - meta_content_scope: debug.in.static-members - match: '::' @@ -432,62 +366,7 @@ contexts: - match: '' pop: true - strings: - - include: double-quoted-string - - include: single-quoted-string - - match: \@"(?=$) - scope: punctuation.definition.string.begin.powershell - push: - - meta_scope: meta.string.powershell string.quoted.double.heredoc.powershell - - match: ^"@ - scope: punctuation.definition.string.end.powershell - pop: true - - include: escape-characters - - include: interpolation - - match: \@'(?=$) - scope: punctuation.definition.string.begin.powershell - push: - - meta_scope: meta.string.powershell string.quoted.single.heredoc.powershell - - match: ^'@ - scope: punctuation.definition.string.end.powershell - pop: true - - match: "''" - scope: constant.character.escape.powershell - - single-quoted-string: - - match: \' - scope: punctuation.definition.string.begin.powershell - push: - - meta_scope: meta.string.powershell string.quoted.single.powershell - - match: "''" - scope: constant.character.escape.powershell - - match: \' - scope: punctuation.definition.string.end.powershell - pop: true - - double-quoted-string: - - match: '"' - scope: punctuation.definition.string.begin.powershell - push: - - meta_scope: meta.string.powershell string.quoted.double.powershell - - match: '""' - scope: constant.character.escape.powershell - - include: escape-characters - - match: '"' - scope: punctuation.definition.string.end.powershell - pop: true - - match: '(?i)\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,64}\b' - - include: interpolation - - match: '`\s*$' - scope: keyword.other.powershell - - escape-characters: - - match: '`[0abenfrvt"''$`]' - scope: constant.character.escape.powershell - - match: '`u\{\h+\}' - scope: constant.character.escape.powershell - - function: + functions: - match: ^(?:\s*)(?i)(function|filter|configuration|workflow)\s+(?:(global|local|script|private):)?((?:\p{L}|\d|_|-|\.)+) scope: meta.function.powershell captures: @@ -499,7 +378,7 @@ contexts: pop: true - include: comment-line - hashtable: + hashtables: - match: (@)(\{) captures: 1: keyword.other.hashtable.begin.powershell @@ -516,10 +395,10 @@ contexts: 2: variable.other.readwrite.powershell 3: punctuation.definition.string.end.powershell 4: keyword.operator.assignment.powershell - - include: script-block + - include: script-blocks - include: main - group: + groups: - match: \( scope: punctuation.section.group.begin.powershell push: @@ -529,79 +408,7 @@ contexts: pop: true - include: main - interpolation: - - match: \$\( - scope: punctuation.section.interpolation.begin.powershell - push: - - clear_scopes: 1 - - meta_scope: meta.interpolation.powershell - - meta_content_scope: source.powershell.embedded - - match: \) - scope: punctuation.section.interpolation.end.powershell - pop: true - - include: main - - match: (?=\$) - push: - - clear_scopes: 1 - - meta_scope: meta.interpolation.powershell - - include: variable-no-property - - include: variable - - match: '' - pop: true - - numeric-constant: - - match: \b(0[bB])([01]*)({{int_suffix}}?{{unit_suffix}}?) - scope: meta.number.integer.binary.powershell - captures: - 1: constant.numeric.base.powershell - 2: constant.numeric.value.powershell - 3: constant.numeric.suffix.powershell - push: members - - match: \b(0[xX])(\h*)({{int_suffix}}?{{unit_suffix}}?) - scope: meta.number.integer.hexadecimal.powershell - captures: - 1: constant.numeric.base.powershell - 2: constant.numeric.value.powershell - 3: constant.numeric.suffix.powershell - push: members - - match: |- - (?x) - ( - # .10 .10e5 - (\.)\d+{{dec_exponent}}? - # 1.2 1.2e-3 1.e2 1e2 - | \d+ (?: (\.) \d+ {{dec_exponent}}? | (\.)? {{dec_exponent}} ) - ) - ( {{float_suffix}}? {{unit_suffix}}? ) - | - # 10.l 10.lGB 10.GB - ( \d+ (\.) ) - ( {{float_suffix}} {{unit_suffix}}? | {{unit_suffix}} ) - scope: meta.number.float.decimal.powershell - captures: - 1: constant.numeric.value.powershell - 2: punctuation.separator.decimal.powershell - 3: punctuation.separator.decimal.powershell - 4: punctuation.separator.decimal.powershell - 5: constant.numeric.suffix.powershell - 6: constant.numeric.value.powershell - 7: punctuation.separator.decimal.powershell - 8: constant.numeric.suffix.powershell - push: members - - match: \b(\d+)({{dec_suffix}}{{unit_suffix}}?) - scope: meta.number.float.decimal.powershell - captures: - 1: constant.numeric.value.powershell - 2: constant.numeric.suffix.powershell - push: members - - match: \b(\d+)({{int_suffix}}?{{unit_suffix}}?) - scope: meta.number.integer.decimal.powershell - captures: - 1: constant.numeric.value.powershell - 2: constant.numeric.suffix.powershell - push: members - - script-block: + script-blocks: - match: (%)?(\{) captures: 1: keyword.control.loop.for.powershell @@ -613,7 +420,7 @@ contexts: pop: true - include: main - type: + types: # TODO: push a maybe-static-members context - match: \[ scope: punctuation.section.brackets.begin.powershell @@ -628,7 +435,7 @@ contexts: scope: storage.type.powershell - include: main - variable: + variables: - match: (\$)(?i:True|False|Null)\b scope: constant.language.powershell captures: @@ -716,7 +523,7 @@ contexts: 6: punctuation.section.braces.end.powershell push: members - variable-no-property: + variables-without-property: - match: (\$)(?i:True|False|Null)\b scope: constant.language.powershell captures: @@ -796,7 +603,7 @@ contexts: 4: variable.other.readwrite.powershell 5: punctuation.section.braces.end - class-method: + class-methods: - match: ^(?:\s*)(?i)(hidden|static)?\s*(\[)((?!\d+|\.)[\p{L}\p{N}.]+)(\])\s*((?:\p{L}|\d|_|-|\.)+)\s*(?=\() scope: meta.function.powershell captures: @@ -824,3 +631,223 @@ contexts: 2: punctuation.definition.comment.powershell 3: keyword.other.region.end.powershell 4: meta.fold.end.powershell + +###[ LITERALS ]################################################################ + + literals: + - include: strings + - include: numbers + + strings: + - include: double-quoted-strings + - include: single-quoted-strings + - match: \@"(?=$) + scope: punctuation.definition.string.begin.powershell + push: + - meta_scope: meta.string.powershell string.quoted.double.heredoc.powershell + - match: ^"@ + scope: punctuation.definition.string.end.powershell + pop: true + - include: escape-sequences + - include: string-interpolations + - match: \@'(?=$) + scope: punctuation.definition.string.begin.powershell + push: + - meta_scope: meta.string.powershell string.quoted.single.heredoc.powershell + - match: ^'@ + scope: punctuation.definition.string.end.powershell + pop: true + - match: "''" + scope: constant.character.escape.powershell + + single-quoted-strings: + - match: \' + scope: punctuation.definition.string.begin.powershell + push: + - meta_scope: meta.string.powershell string.quoted.single.powershell + - match: "''" + scope: constant.character.escape.powershell + - match: \' + scope: punctuation.definition.string.end.powershell + pop: true + + double-quoted-strings: + - match: '"' + scope: punctuation.definition.string.begin.powershell + push: + - meta_scope: meta.string.powershell string.quoted.double.powershell + - match: '""' + scope: constant.character.escape.powershell + - include: escape-sequences + - match: '"' + scope: punctuation.definition.string.end.powershell + pop: true + - match: '(?i)\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,64}\b' + - include: string-interpolations + - match: '`\s*$' + scope: keyword.other.powershell + + string-interpolations: + - match: \$\( + scope: punctuation.section.interpolation.begin.powershell + push: + - clear_scopes: 1 + - meta_scope: meta.interpolation.powershell + - meta_content_scope: source.powershell.embedded + - match: \) + scope: punctuation.section.interpolation.end.powershell + pop: true + - include: main + - match: (?=\$) + push: + - clear_scopes: 1 + - meta_scope: meta.interpolation.powershell + - include: variables-without-property + - include: variables + - include: immediately-pop + + numbers: + # Binary numbers + - match: \b(0[bB])([01]*)({{int_suffix}}?{{unit_suffix}}?) + scope: meta.number.integer.binary.powershell + captures: + 1: constant.numeric.base.powershell + 2: constant.numeric.value.powershell + 3: constant.numeric.suffix.powershell + push: members + # Hexadecimal numbers + - match: \b(0[xX])(\h*)({{int_suffix}}?{{unit_suffix}}?) + scope: meta.number.integer.hexadecimal.powershell + captures: + 1: constant.numeric.base.powershell + 2: constant.numeric.value.powershell + 3: constant.numeric.suffix.powershell + push: members + # Floats + - match: |- + (?x) + ( + # .10 .10e5 + (\.)\d+{{dec_exponent}}? + # 1.2 1.2e-3 1.e2 1e2 + | \d+ (?: (\.) \d+ {{dec_exponent}}? | (\.)? {{dec_exponent}} ) + ) + ( {{float_suffix}}? {{unit_suffix}}? ) + | + # 10.l 10.lGB 10.GB + ( \d+ (\.) ) + ( {{float_suffix}} {{unit_suffix}}? | {{unit_suffix}} ) + scope: meta.number.float.decimal.powershell + captures: + 1: constant.numeric.value.powershell + 2: punctuation.separator.decimal.powershell + 3: punctuation.separator.decimal.powershell + 4: punctuation.separator.decimal.powershell + 5: constant.numeric.suffix.powershell + 6: constant.numeric.value.powershell + 7: punctuation.separator.decimal.powershell + 8: constant.numeric.suffix.powershell + push: members + # "Decimal" numbers + - match: \b(\d+)({{dec_suffix}}{{unit_suffix}}?) + scope: meta.number.float.decimal.powershell + captures: + 1: constant.numeric.value.powershell + 2: constant.numeric.suffix.powershell + push: members + # Integers + - match: \b(\d+)({{int_suffix}}?{{unit_suffix}}?) + scope: meta.number.integer.decimal.powershell + captures: + 1: constant.numeric.value.powershell + 2: constant.numeric.suffix.powershell + push: members + +###[ COMMENTS ]################################################################ + + comments: + - include: comment-block + - include: comment-line + + comment-block: + - match: <# + scope: punctuation.definition.comment.block.begin.powershell + push: + - meta_scope: comment.block.powershell + - match: '#>' + scope: punctuation.definition.comment.block.end.powershell + pop: true + - include: comment-embedded-docs + + comment-embedded-docs: + # TODO + # https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_comment_based_help + - match: |- + (?xi: + ^\s*(\.) + ( + Component | Description | Example | ExternalHelp | ForwardHelpCategory | ForwardHelpTargetName + | Functionality | Inputs | Link | Notes | Outputs | Parameter | RemoteHelpRunSpace + | Role | Synopsis + ) + ) + scope: comment.documentation.embedded.powershell + captures: + 1: punctuation.definition.keyword.documentation.powershell + 2: keyword.other.documentation.powershell + - match: ^\s*(\.)(?i:(Parameter)\s+([a-z0-9-_]+)) + scope: comment.documentation.embedded.powershell + captures: + 1: punctuation.definition.keyword.documentation.powershell + 2: keyword.other.documentation.param.powershell + 3: variable.parameter.powershell + - match: ^\s*(\.)(?i:(ForwardHelpTargetName|ForwardHelpCategory|ExternalHelp|Link)\s+([a-z0-9-_]+)) + scope: comment.documentation.embedded.powershell + captures: + 1: punctuation.definition.keyword.documentation.powershell + 2: keyword.other.documentation.powershell + 3: markup.underline.link.powershell + + comment-line: + # TODO: Is requires-directive really a thing here? + - include: requires-directives + - match: '#' + scope: punctuation.definition.comment.powershell + push: + - meta_scope: comment.line.powershell + - include: pop-eol + - include: comment-embedded-docs + +###[ COMPONENTS ]############################################################## + + escape-sequences: + - match: '`[0abenfrvt"''$`]' + scope: constant.character.escape.powershell + - match: '`u\{\h+\}' + scope: constant.character.escape.powershell + + pop-eol: + - match: $ + pop: true + + pop-before-eol: + - match: (?=$) + pop: true + + immediately-pop: + - match: '' + pop: true + + else-pop: + - match: (?=\S) + pop: true + +############################################################################### + +variables: + dec_exponent: (?:[eE][-+]?\d*) + dec_suffix: '[dD]' + float_suffix: '[dDlL]' + int_suffix: (?i:u[lsy]?|[lnsy]) + unit_suffix: (?i:[kmgtp]b\b) + kebab_break: (?![\w-]) diff --git a/Tests/syntax_test_PowerShell.ps1 b/Tests/syntax_test_PowerShell.ps1 index bb9d932a..d9154142 100644 --- a/Tests/syntax_test_PowerShell.ps1 +++ b/Tests/syntax_test_PowerShell.ps1 @@ -5,7 +5,7 @@ using namespace System.Management.Automation # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ variable.parameter #Requires -PSSnapin DiskSnapin -Version 1.2 # <- punctuation.definition.keyword -#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.requires +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.requires #^^^^^^^^ keyword.control.import.require # ^^^^^^^^^ variable.parameter # ^^^^^^^^ variable.parameter From 85fa6e2cb8aea93f983a7784c3a4ca1ced9c6ba0 Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Thu, 4 Dec 2025 17:15:18 -0500 Subject: [PATCH 02/81] Introduce a statements context --- PowerShell.sublime-syntax | 252 +++++++++++++++++-------------- Tests/syntax_test_PowerShell.ps1 | 1 - 2 files changed, 139 insertions(+), 114 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index 7a4d3f94..352a0d99 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -17,57 +17,15 @@ first_line_match: |- ) contexts: - # prototype: - # - include: comments + prototype: + - include: comments main: - - include: regions + - include: statements + + statements: - include: comments - include: expressions - - expressions: - - include: redirection - - include: commands - - include: variables - - include: groups - - include: functions - - include: attributes - - include: using-directives - - include: types - - include: hashtables - - include: strings - - include: script-blocks - - include: escape-sequences - - include: numbers - - include: class-methods - - match: (@)(\() - captures: - 1: keyword.other.array.begin.powershell - 2: punctuation.section.group.begin.powershell - push: - - meta_scope: meta.group.array-expression.powershell - - match: \) - scope: punctuation.section.group.end.powershell - pop: true - - include: main - - match: (\$)(\() - # TODO: move to repo; make recursive. - captures: - 1: keyword.other.variable.definition.powershell - 2: punctuation.section.group.begin.powershell - push: - - meta_scope: meta.group.complex.subexpression.powershell - - match: \) - scope: punctuation.section.group.end.powershell - pop: true - - include: main - - match: \b[\w.-]+\.(?i:exe|com|cmd|bat)\b - scope: variable.function.powershell - # Consume a string with a trailing dot - # to prevent members with particular names from being recognized as keywords. - - match: \b[\w-]+(?=\.) - scope: variable.other.object.powershell - push: members # Exceptions - match: \b(?i:throw){{kebab_break}} scope: keyword.control.exception.raise.powershell @@ -77,19 +35,6 @@ contexts: scope: keyword.control.exception.catch.powershell - match: \b(?i:finally){{kebab_break}} scope: keyword.control.exception.finally.powershell - # Conditionals - - match: \b(?i:if){{kebab_break}} - scope: keyword.control.conditional.if.powershell - - match: \b(?i:elseif){{kebab_break}} - scope: keyword.control.conditional.elseif.powershell - - match: \b(?i:else){{kebab_break}} - scope: keyword.control.conditional.else.powershell - - match: \b(?i:switch){{kebab_break}} - scope: keyword.control.conditional.switch.powershell - - match: \? - scope: keyword.control.conditional.select.powershell - - match: \b(?i:where(?!-object)){{kebab_break}} - scope: keyword.control.conditional.select.powershell # Begin/End - match: \b(?i:begin){{kebab_break}} scope: keyword.context.block.begin.powershell @@ -117,12 +62,69 @@ contexts: scope: keyword.control.flow.exit.powershell - match: \b(?i:return){{kebab_break}} scope: keyword.control.flow.return.powershell + # Conditionals + - match: \b(?i:if){{kebab_break}} + scope: keyword.control.conditional.if.powershell + - match: \b(?i:elseif){{kebab_break}} + scope: keyword.control.conditional.elseif.powershell + - match: \b(?i:else){{kebab_break}} + scope: keyword.control.conditional.else.powershell + - match: \b(?i:switch){{kebab_break}} + scope: keyword.control.conditional.switch.powershell + - match: \? + scope: keyword.control.conditional.select.powershell + - match: \b(?i:where(?!-object)){{kebab_break}} + scope: keyword.control.conditional.select.powershell # Declaration - match: \b(?i:var){{kebab_break}} # scope: storage.type.variable.powershell scope: keyword.declaration.variable.powershell - match: \b(?i:(?:dynamic)?param){{kebab_break}} scope: keyword.declaration.parameter.powershell # This scope is not standard + + expressions: + - include: redirection + - include: commands + - include: variables + - include: groups + - include: functions + - include: attributes + - include: using-directives + - include: types + - include: hashtables + - include: strings + - include: script-blocks + - include: escape-sequences + - include: numbers + - include: class-methods + - match: (@)(\() + captures: + 1: keyword.other.array.begin.powershell + 2: punctuation.section.group.begin.powershell + push: + - meta_scope: meta.group.array-expression.powershell + - match: \) + scope: punctuation.section.group.end.powershell + pop: true + - include: statements + - match: (\$)(\() + # TODO: move to repo; make recursive. + captures: + 1: keyword.other.variable.definition.powershell + 2: punctuation.section.group.begin.powershell + push: + - meta_scope: meta.group.complex.subexpression.powershell + - match: \) + scope: punctuation.section.group.end.powershell + pop: true + - include: statements + - match: \b[\w.-]+\.(?i:exe|com|cmd|bat)\b + scope: variable.function.powershell + # Consume a string with a trailing dot + # to prevent members with particular names from being recognized as keywords. + - match: \b[\w-]+(?=\.) + scope: variable.other.object.powershell + push: members # Uncategorized keywords - match: \b(?i:data|default|define|from|in|inlinescript|parallel|sequence){{kebab_break}} scope: keyword.control.powershell @@ -138,7 +140,17 @@ contexts: captures: 1: storage.type.class.powershell 2: meta.class.powershell entity.name.class.powershell - # Operators... + + - include: operators + + # Flags/Options/Parameters + - match: \B(--?|[/+])\p{L}(?:[\w-]*\w)? + scope: variable.parameter.option.powershell + captures: + 1: punctuation.definition.parameter.powershell + + operators: + # Word operators - match: \B(-)(?i:as){{kebab_break}} scope: keyword.operator.cast.powershell captures: @@ -171,19 +183,19 @@ contexts: scope: keyword.operator.string-format.powershell captures: 1: punctuation.definition.keyword.powershell - # Flags/Options/Parameters - - match: \B(--?|[/+])\p{L}(?:[\w-]*\w)? - scope: variable.parameter.option.powershell - captures: - 1: punctuation.definition.parameter.powershell - # Operators continue... + # Symbol operators - match: '[+/*%-]?=' scope: keyword.operator.assignment.powershell - - match: (?:\+\+|--)(?![ \t]*\d) + - match: (?:\+\+|--)(?![ \t]*\d|[[:alpha:]]) scope: keyword.operator.assignment.powershell - match: '[+-](?=\.?\d)' # This is sort of heuristic scope: keyword.operator.unary.powershell - - match: '[+/*-]' + # Be careful about matching arithmetic with tightly following words + - match: '[/+](?![[:alpha:]])' + scope: keyword.operator.arithmetic.powershell + - match: -(?![[:alpha:]-]) + scope: keyword.operator.arithmetic.powershell + - match: \* scope: keyword.operator.arithmetic.powershell - match: '%(?!\s*\{)' scope: keyword.operator.arithmetic.powershell @@ -203,6 +215,7 @@ contexts: # This is very imprecise. Is there a syntax for 'must come after...'? scope: keyword.operator.range.powershell + redirection: # https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_redirection - match: ([2-6*])(>&)(1) @@ -270,15 +283,15 @@ contexts: - match: \) scope: punctuation.section.group.end.powershell pop: true - - include: variables - - include: variables-without-property - - include: hashtables - - include: script-blocks - - include: escape-sequences - - include: double-quoted-strings - - include: types - - include: numbers - - include: main + # - include: variables + # - include: variables-without-property + # - include: hashtables + # - include: script-blocks + # - include: escape-sequences + # - include: double-quoted-strings + # - include: types + # - include: numbers + - include: statements - match: |- (?xi: \b( @@ -396,7 +409,7 @@ contexts: 3: punctuation.definition.string.end.powershell 4: keyword.operator.assignment.powershell - include: script-blocks - - include: main + - include: statements groups: - match: \( @@ -406,7 +419,7 @@ contexts: - match: \) scope: punctuation.section.group.end.powershell pop: true - - include: main + - include: statements script-blocks: - match: (%)?(\{) @@ -418,7 +431,7 @@ contexts: - match: \} scope: punctuation.section.braces.end.powershell pop: true - - include: main + - include: statements types: # TODO: push a maybe-static-members context @@ -433,7 +446,7 @@ contexts: pop: true - match: (?!\d+|\.)[\p{L}\p{N}.]+ scope: storage.type.powershell - - include: main + - include: types variables: - match: (\$)(?i:True|False|Null)\b @@ -641,18 +654,46 @@ contexts: strings: - include: double-quoted-strings - include: single-quoted-strings - - match: \@"(?=$) + - include: double-quoted-heredoc-strings + - include: single-quoted-heredoc-strings + + single-quoted-strings: + - match: \' scope: punctuation.definition.string.begin.powershell - push: - - meta_scope: meta.string.powershell string.quoted.double.heredoc.powershell - - match: ^"@ - scope: punctuation.definition.string.end.powershell - pop: true - - include: escape-sequences - - include: string-interpolations + push: inside-single-quoted-string + + inside-single-quoted-string: + - meta_scope: meta.string.powershell string.quoted.single.powershell + - match: "''" + scope: constant.character.escape.powershell + - match: \' + scope: punctuation.definition.string.end.powershell + pop: true + + double-quoted-strings: + - match: '"' + scope: punctuation.definition.string.begin.powershell + push: inside-double-quoted-string + + inside-double-quoted-string: + - meta_include_prototype: false + - meta_scope: meta.string.powershell string.quoted.double.powershell + - match: '""' + scope: constant.character.escape.powershell + - include: escape-sequences + - match: '"' + scope: punctuation.definition.string.end.powershell + pop: true + - match: '(?i)\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,64}\b' + - include: string-interpolations + - match: '`\s*$' + scope: keyword.other.powershell + + single-quoted-heredoc-strings: - match: \@'(?=$) scope: punctuation.definition.string.begin.powershell push: + - meta_include_prototype: false - meta_scope: meta.string.powershell string.quoted.single.heredoc.powershell - match: ^'@ scope: punctuation.definition.string.end.powershell @@ -660,32 +701,17 @@ contexts: - match: "''" scope: constant.character.escape.powershell - single-quoted-strings: - - match: \' + double-quoted-heredoc-strings: + - match: \@"(?=$) scope: punctuation.definition.string.begin.powershell push: - - meta_scope: meta.string.powershell string.quoted.single.powershell - - match: "''" - scope: constant.character.escape.powershell - - match: \' + - meta_include_prototype: false + - meta_scope: meta.string.powershell string.quoted.double.heredoc.powershell + - match: ^"@ scope: punctuation.definition.string.end.powershell pop: true - - double-quoted-strings: - - match: '"' - scope: punctuation.definition.string.begin.powershell - push: - - meta_scope: meta.string.powershell string.quoted.double.powershell - - match: '""' - scope: constant.character.escape.powershell - include: escape-sequences - - match: '"' - scope: punctuation.definition.string.end.powershell - pop: true - - match: '(?i)\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,64}\b' - include: string-interpolations - - match: '`\s*$' - scope: keyword.other.powershell string-interpolations: - match: \$\( @@ -697,7 +723,7 @@ contexts: - match: \) scope: punctuation.section.interpolation.end.powershell pop: true - - include: main + - include: expressions - match: (?=\$) push: - clear_scopes: 1 @@ -766,6 +792,8 @@ contexts: ###[ COMMENTS ]################################################################ comments: + - include: regions + - include: requires-directives - include: comment-block - include: comment-line @@ -809,8 +837,6 @@ contexts: 3: markup.underline.link.powershell comment-line: - # TODO: Is requires-directive really a thing here? - - include: requires-directives - match: '#' scope: punctuation.definition.comment.powershell push: diff --git a/Tests/syntax_test_PowerShell.ps1 b/Tests/syntax_test_PowerShell.ps1 index d9154142..85ba6d93 100644 --- a/Tests/syntax_test_PowerShell.ps1 +++ b/Tests/syntax_test_PowerShell.ps1 @@ -777,7 +777,6 @@ A 'single quoted' "heredoc" # <- punctuation.section.brackets.begin # ^^^^^^^^^^^ storage.type # ^^^^^^^^^^^^^^^^^ storage.type -# ^ keyword.operator # ^ punctuation.section.brackets.end [int]::MinValue # <- punctuation.section.brackets.begin From 786aec357fb5451b253bdb6f8d0ebd9e88e5304e Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Thu, 4 Dec 2025 17:57:35 -0500 Subject: [PATCH 03/81] Move comment-like contexts --- PowerShell.sublime-syntax | 65 +++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 33 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index 352a0d99..9d8ab4dc 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -215,7 +215,6 @@ contexts: # This is very imprecise. Is there a syntax for 'must come after...'? scope: keyword.operator.range.powershell - redirection: # https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_redirection - match: ([2-6*])(>&)(1) @@ -232,23 +231,6 @@ contexts: # - match: <+ # scope: invalid.illegal.powershell - requires-directives: - # TODO: add back `(?<=#)`-equivalent match - - match: (#)((?i:requires))\s - captures: - 1: punctuation.definition.keyword.powershell - 2: keyword.control.import.require.powershell - push: - - meta_scope: meta.requires.powershell - - include: pop-eol - - include: hashtables - - match: (-)(?i:Modules|PSSnapin|RunAsAdministrator|ShellId|Version) - scope: variable.parameter.option.powershell - captures: - 1: punctuation.definition.variable.powershell - - match: ',' - scope: punctuation.separator.powershell - using-directives: - match: \b(?i:(using))\s+(?i:(namespace|module))\s+(?i:((?:\w+(?:\.)?)+)) captures: @@ -630,21 +612,6 @@ contexts: pop: true - include: comment-line - regions: - - match: ^\s*((#)\s*(region\b)(?:\s*(\S.*))?(\n?)) - captures: - 1: comment.line.powershell - 2: punctuation.definition.comment.powershell - 3: keyword.other.region.begin.powershell - 4: meta.toc-list.powershell entity.name.section.powershell - 5: meta.fold.begin.powershell - - match: ^\s*((#)\s*(endregion\b).*(\n?)) - captures: - 1: comment.line.powershell - 2: punctuation.definition.comment.powershell - 3: keyword.other.region.end.powershell - 4: meta.fold.end.powershell - ###[ LITERALS ]################################################################ literals: @@ -844,6 +811,38 @@ contexts: - include: pop-eol - include: comment-embedded-docs + regions: + - match: ^\s*((#)\s*(region\b)(?:\s*(\S.*))?(\n?)) + captures: + 1: comment.line.powershell + 2: punctuation.definition.comment.powershell + 3: keyword.other.region.begin.powershell + 4: meta.toc-list.powershell entity.name.section.powershell + 5: meta.fold.begin.powershell + - match: ^\s*((#)\s*(endregion\b).*(\n?)) + captures: + 1: comment.line.powershell + 2: punctuation.definition.comment.powershell + 3: keyword.other.region.end.powershell + 4: meta.fold.end.powershell + + requires-directives: + # TODO: add back `(?<=#)`-equivalent match + - match: (#)((?i:requires))\s + captures: + 1: punctuation.definition.keyword.powershell + 2: keyword.control.import.require.powershell + push: + - meta_scope: meta.requires.powershell + - include: pop-eol + - include: hashtables + - match: (-)(?i:Modules|PSSnapin|RunAsAdministrator|ShellId|Version) + scope: variable.parameter.option.powershell + captures: + 1: punctuation.definition.variable.powershell + - match: ',' + scope: punctuation.separator.powershell + ###[ COMPONENTS ]############################################################## escape-sequences: From c39407ebb972f51dc710849b1b257540891f2887 Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Thu, 4 Dec 2025 18:00:21 -0500 Subject: [PATCH 04/81] Tighten attributes context --- PowerShell.sublime-syntax | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index 9d8ab4dc..ffa68c5d 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -265,15 +265,6 @@ contexts: - match: \) scope: punctuation.section.group.end.powershell pop: true - # - include: variables - # - include: variables-without-property - # - include: hashtables - # - include: script-blocks - # - include: escape-sequences - # - include: double-quoted-strings - # - include: types - # - include: numbers - - include: statements - match: |- (?xi: \b( @@ -287,15 +278,7 @@ contexts: captures: 1: variable.parameter.attribute.powershell 2: keyword.operator.assignment.powershell - - match: \' - scope: punctuation.definition.string.begin.powershell - push: - - meta_scope: string.quoted.single.powershell - - match: \'\' - scope: constant.character.escape.powershell - - match: \' - scope: punctuation.definition.string.end.powershell - pop: true + - include: expressions commands: # "Verb-Noun pattern:" From 6571fd387a5442588ef52d0de080147fe7b38883 Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Thu, 4 Dec 2025 18:18:36 -0500 Subject: [PATCH 05/81] Rearrange groups --- PowerShell.sublime-syntax | 102 ++++++++++++++++++++++---------------- 1 file changed, 60 insertions(+), 42 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index ffa68c5d..83ea22a2 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -24,8 +24,8 @@ contexts: - include: statements statements: - - include: comments - include: expressions + - include: functions # Exceptions - match: \b(?i:throw){{kebab_break}} scope: keyword.control.exception.raise.powershell @@ -83,11 +83,13 @@ contexts: scope: keyword.declaration.parameter.powershell # This scope is not standard expressions: + # BUG: When we figure out what's wrong with `prototype`, remove this. + - include: comments + - include: redirection - include: commands + - include: constants - include: variables - - include: groups - - include: functions - include: attributes - include: using-directives - include: types @@ -97,27 +99,9 @@ contexts: - include: escape-sequences - include: numbers - include: class-methods - - match: (@)(\() - captures: - 1: keyword.other.array.begin.powershell - 2: punctuation.section.group.begin.powershell - push: - - meta_scope: meta.group.array-expression.powershell - - match: \) - scope: punctuation.section.group.end.powershell - pop: true - - include: statements - - match: (\$)(\() - # TODO: move to repo; make recursive. - captures: - 1: keyword.other.variable.definition.powershell - 2: punctuation.section.group.begin.powershell - push: - - meta_scope: meta.group.complex.subexpression.powershell - - match: \) - scope: punctuation.section.group.end.powershell - pop: true - - include: statements + - include: groups + - include: arrays + - include: subexpressions - match: \b[\w.-]+\.(?i:exe|com|cmd|bat)\b scope: variable.function.powershell # Consume a string with a trailing dot @@ -376,16 +360,6 @@ contexts: - include: script-blocks - include: statements - groups: - - match: \( - scope: punctuation.section.group.begin.powershell - push: - - meta_scope: meta.group.powershell - - match: \) - scope: punctuation.section.group.end.powershell - pop: true - - include: statements - script-blocks: - match: (%)?(\{) captures: @@ -414,10 +388,6 @@ contexts: - include: types variables: - - match: (\$)(?i:True|False|Null)\b - scope: constant.language.powershell - captures: - 1: punctuation.definition.variable.powershell - match: |- (?xi: (\$) @@ -502,10 +472,6 @@ contexts: push: members variables-without-property: - - match: (\$)(?i:True|False|Null)\b - scope: constant.language.powershell - captures: - 1: punctuation.definition.variable.powershell - match: |- (?xi: (\$) @@ -595,6 +561,58 @@ contexts: pop: true - include: comment-line +###[ GROUPS ]################################################################## + + groups: + - match: \( + scope: punctuation.section.group.begin.powershell + push: + - meta_scope: meta.group.powershell + - match: \) + scope: punctuation.section.group.end.powershell + pop: true + - include: expressions + + arrays: + - match: (@)(\() + captures: + 1: keyword.other.array.begin.powershell + 2: punctuation.section.group.begin.powershell + push: + - meta_scope: meta.group.array-expression.powershell + - match: \) + scope: punctuation.section.group.end.powershell + pop: true + - include: expressions + + subexpressions: + - match: (\$)(\() + captures: + 1: keyword.other.variable.definition.powershell + 2: punctuation.section.group.begin.powershell + push: + - meta_scope: meta.group.complex.subexpression.powershell + - match: \) + scope: punctuation.section.group.end.powershell + pop: true + - include: expressions + +###[ CONSTANTS ]############################################################### + + constants: + - match: (?i)(\$)True\b + scope: constant.language.boolean.true.powershell + captures: + 1: punctuation.definition.variable.powershell + - match: (?i)(\$)False\b + scope: constant.language.boolean.false.powershell + captures: + 1: punctuation.definition.variable.powershell + - match: (?i)(\$)Null\b + scope: constant.language.null.powershell + captures: + 1: punctuation.definition.variable.powershell + ###[ LITERALS ]################################################################ literals: From d9616c787fa4c3d16b474b0a653fa4708ed27288 Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Thu, 4 Dec 2025 18:23:30 -0500 Subject: [PATCH 06/81] Move classes to statements --- PowerShell.sublime-syntax | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index 83ea22a2..0e9cb1aa 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -26,6 +26,10 @@ contexts: statements: - include: expressions - include: functions + - match: \b((?i:class))\s+([\w-]+)\b + captures: + 1: storage.type.class.powershell + 2: meta.class.powershell entity.name.class.powershell # Exceptions - match: \b(?i:throw){{kebab_break}} scope: keyword.control.exception.raise.powershell @@ -120,10 +124,6 @@ contexts: - match: \b(?i:hidden|static)\b # This should only be relevant inside a class but will require a rework of how classes are matched. This is a temp fix. scope: storage.modifier.powershell - - match: \b((?i:class))\s+([\w-]+)\b - captures: - 1: storage.type.class.powershell - 2: meta.class.powershell entity.name.class.powershell - include: operators From e774fa2b476cd18b42c0a4d58750cbc9e5dbc69b Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Thu, 4 Dec 2025 18:24:01 -0500 Subject: [PATCH 07/81] Comment out special handling of emails in strings --- PowerShell.sublime-syntax | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index 0e9cb1aa..d13bfc76 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -652,7 +652,8 @@ contexts: - match: '"' scope: punctuation.definition.string.end.powershell pop: true - - match: '(?i)\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,64}\b' + # # Silently eat email addresses + # - match: '(?i)\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,64}\b' - include: string-interpolations - match: '`\s*$' scope: keyword.other.powershell From 967ebaff1ea1d60cfff5bc106a8e9282320115c7 Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Thu, 4 Dec 2025 18:34:25 -0500 Subject: [PATCH 08/81] Slot hashtables in among groups --- PowerShell.sublime-syntax | 40 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index d13bfc76..4c2087a4 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -81,7 +81,6 @@ contexts: scope: keyword.control.conditional.select.powershell # Declaration - match: \b(?i:var){{kebab_break}} - # scope: storage.type.variable.powershell scope: keyword.declaration.variable.powershell - match: \b(?i:(?:dynamic)?param){{kebab_break}} scope: keyword.declaration.parameter.powershell # This scope is not standard @@ -340,26 +339,6 @@ contexts: pop: true - include: comment-line - hashtables: - - match: (@)(\{) - captures: - 1: keyword.other.hashtable.begin.powershell - 2: punctuation.section.braces.begin.powershell - push: - - meta_scope: meta.hashtable.powershell - - match: \} - scope: punctuation.section.braces.end.powershell - pop: true - - match: \b(['"]?)(\w+)(['"]?)\s*(=)\s* - scope: meta.hashtable.assignment.powershell - captures: - 1: punctuation.definition.string.begin.powershell - 2: variable.other.readwrite.powershell - 3: punctuation.definition.string.end.powershell - 4: keyword.operator.assignment.powershell - - include: script-blocks - - include: statements - script-blocks: - match: (%)?(\{) captures: @@ -585,6 +564,25 @@ contexts: pop: true - include: expressions + hashtables: + - match: (@)(\{) + captures: + 1: keyword.other.hashtable.begin.powershell + 2: punctuation.section.braces.begin.powershell + push: + - meta_scope: meta.hashtable.powershell + - match: \} + scope: punctuation.section.braces.end.powershell + pop: true + - match: \b(['"]?)(\w+)(['"]?)\s*(=)\s* + scope: meta.hashtable.assignment.powershell + captures: + 1: punctuation.definition.string.begin.powershell + 2: variable.other.readwrite.powershell + 3: punctuation.definition.string.end.powershell + 4: keyword.operator.assignment.powershell + - include: expressions + subexpressions: - match: (\$)(\() captures: From 1097d7115b5b4caa6ffc72900fa12af1bbf612c4 Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Thu, 4 Dec 2025 18:41:14 -0500 Subject: [PATCH 09/81] Require class stuff to at least be in a block --- PowerShell.sublime-syntax | 53 +++++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index 4c2087a4..8ee4f560 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -24,12 +24,9 @@ contexts: - include: statements statements: + - include: classes - include: expressions - include: functions - - match: \b((?i:class))\s+([\w-]+)\b - captures: - 1: storage.type.class.powershell - 2: meta.class.powershell entity.name.class.powershell # Exceptions - match: \b(?i:throw){{kebab_break}} scope: keyword.control.exception.raise.powershell @@ -101,7 +98,6 @@ contexts: - include: script-blocks - include: escape-sequences - include: numbers - - include: class-methods - include: groups - include: arrays - include: subexpressions @@ -120,9 +116,6 @@ contexts: push: - meta_content_scope: string.unquoted.powershell - include: pop-before-eol - - match: \b(?i:hidden|static)\b - # This should only be relevant inside a class but will require a rework of how classes are matched. This is a temp fix. - scope: storage.modifier.powershell - include: operators @@ -349,6 +342,12 @@ contexts: - match: \} scope: punctuation.section.braces.end.powershell pop: true + + # TODO: Fix classes, so this doesn't nest here. + - include: class-methods + - match: \b(?i:hidden|static)\b + scope: storage.modifier.powershell + - include: statements types: @@ -366,6 +365,30 @@ contexts: scope: storage.type.powershell - include: types +###[ CLASSES ]################################################################# + + classes: + - match: \b((?i:class))\s+([\w-]+)\b + captures: + 1: storage.type.class.powershell + 2: meta.class.powershell entity.name.class.powershell + + class-methods: + - match: ^(?:\s*)(?i)(hidden|static)?\s*(\[)((?!\d+|\.)[\p{L}\p{N}.]+)(\])\s*((?:\p{L}|\d|_|-|\.)+)\s*(?=\() + scope: meta.function.powershell + captures: + 1: storage.modifier.powershell + 2: punctuation.section.brackets.begin.powershell + 3: storage.type.powershell + 4: punctuation.section.brackets.end.powershell + 5: entity.name.function.powershell + push: + - match: (?=\() + pop: true + - include: comment-line + +###[ VARIABLES ]############################################################### + variables: - match: |- (?xi: @@ -526,20 +549,6 @@ contexts: 4: variable.other.readwrite.powershell 5: punctuation.section.braces.end - class-methods: - - match: ^(?:\s*)(?i)(hidden|static)?\s*(\[)((?!\d+|\.)[\p{L}\p{N}.]+)(\])\s*((?:\p{L}|\d|_|-|\.)+)\s*(?=\() - scope: meta.function.powershell - captures: - 1: storage.modifier.powershell - 2: punctuation.section.brackets.begin.powershell - 3: storage.type.powershell - 4: punctuation.section.brackets.end.powershell - 5: entity.name.function.powershell - push: - - match: (?=\() - pop: true - - include: comment-line - ###[ GROUPS ]################################################################## groups: From 33f0aa45db349e705b2894eb2fb222817dcef279 Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Thu, 4 Dec 2025 18:45:44 -0500 Subject: [PATCH 10/81] Make a heading for operators --- PowerShell.sublime-syntax | 166 +++++++++++++++++++------------------- 1 file changed, 84 insertions(+), 82 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index 8ee4f560..bb886d89 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -125,88 +125,6 @@ contexts: captures: 1: punctuation.definition.parameter.powershell - operators: - # Word operators - - match: \B(-)(?i:as){{kebab_break}} - scope: keyword.operator.cast.powershell - captures: - 1: punctuation.definition.keyword.powershell - - match: \B(-)(?i:[ic]?(?:eq|ne|[gl][te])){{kebab_break}} - scope: keyword.operator.comparison.powershell - captures: - 1: punctuation.definition.keyword.powershell - - match: \B(-)(?i:[ic]?(?:not)?(?:like|match|contains|in)){{kebab_break}} - scope: keyword.operator.logical.powershell - captures: - 1: punctuation.definition.keyword.powershell - - match: \B(-)(?i:join|split|replace){{kebab_break}} - scope: keyword.operator.string.powershell - captures: - 1: punctuation.definition.keyword.powershell - - match: \B(-)(?i:is(?:not)?){{kebab_break}} - scope: keyword.operator.logical.powershell - captures: - 1: punctuation.definition.keyword.powershell - - match: \B(-)(?i:and|or|not|xor){{kebab_break}}|! # <-- note `!` - scope: keyword.operator.logical.powershell - captures: - 1: punctuation.definition.keyword.powershell - - match: \B(-)(?i:band|bor|bnot|bxor|sh[lr]){{kebab_break}} - scope: keyword.operator.bitwise.powershell - captures: - 1: punctuation.definition.keyword.powershell - - match: \B(-)(?i:f){{kebab_break}} - scope: keyword.operator.string-format.powershell - captures: - 1: punctuation.definition.keyword.powershell - # Symbol operators - - match: '[+/*%-]?=' - scope: keyword.operator.assignment.powershell - - match: (?:\+\+|--)(?![ \t]*\d|[[:alpha:]]) - scope: keyword.operator.assignment.powershell - - match: '[+-](?=\.?\d)' # This is sort of heuristic - scope: keyword.operator.unary.powershell - # Be careful about matching arithmetic with tightly following words - - match: '[/+](?![[:alpha:]])' - scope: keyword.operator.arithmetic.powershell - - match: -(?![[:alpha:]-]) - scope: keyword.operator.arithmetic.powershell - - match: \* - scope: keyword.operator.arithmetic.powershell - - match: '%(?!\s*\{)' - scope: keyword.operator.arithmetic.powershell - - match: \|\||&& - scope: keyword.operator.logical.powershell - - match: \| - scope: keyword.operator.logical.pipe.powershell - - match: ; - scope: punctuation.terminator.statement.powershell - - match: \`(?=\n|$) - scope: punctuation.separator.continuation.line.powershell - - match: ',' - scope: punctuation.separator.sequence.powershell - - match: '&|\B\.(?= )' - scope: keyword.operator.other.powershell - - match: \.\.(?=\-?\d|\(|\$) - # This is very imprecise. Is there a syntax for 'must come after...'? - scope: keyword.operator.range.powershell - - redirection: - # https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_redirection - - match: ([2-6*])(>&)(1) - captures: - 1: constant.numeric.decimal.file-descriptor.powershell - 2: keyword.operator.redirection.powershell - 3: constant.numeric.decimal.file-descriptor.powershell - - match: ([1-6*])(>>?) - captures: - 1: constant.numeric.decimal.file-descriptor.powershell - 2: keyword.operator.redirection.powershell - - match: '>>?' - scope: keyword.operator.redirection.powershell - # - match: <+ - # scope: invalid.illegal.powershell - using-directives: - match: \b(?i:(using))\s+(?i:(namespace|module))\s+(?i:((?:\w+(?:\.)?)+)) captures: @@ -365,6 +283,90 @@ contexts: scope: storage.type.powershell - include: types +###[ OPERATORS ]############################################################### + + operators: + # Word operators + - match: \B(-)(?i:as){{kebab_break}} + scope: keyword.operator.cast.powershell + captures: + 1: punctuation.definition.keyword.powershell + - match: \B(-)(?i:[ic]?(?:eq|ne|[gl][te])){{kebab_break}} + scope: keyword.operator.comparison.powershell + captures: + 1: punctuation.definition.keyword.powershell + - match: \B(-)(?i:[ic]?(?:not)?(?:like|match|contains|in)){{kebab_break}} + scope: keyword.operator.logical.powershell + captures: + 1: punctuation.definition.keyword.powershell + - match: \B(-)(?i:join|split|replace){{kebab_break}} + scope: keyword.operator.string.powershell + captures: + 1: punctuation.definition.keyword.powershell + - match: \B(-)(?i:is(?:not)?){{kebab_break}} + scope: keyword.operator.logical.powershell + captures: + 1: punctuation.definition.keyword.powershell + - match: \B(-)(?i:and|or|not|xor){{kebab_break}}|! # <-- note `!` + scope: keyword.operator.logical.powershell + captures: + 1: punctuation.definition.keyword.powershell + - match: \B(-)(?i:band|bor|bnot|bxor|sh[lr]){{kebab_break}} + scope: keyword.operator.bitwise.powershell + captures: + 1: punctuation.definition.keyword.powershell + - match: \B(-)(?i:f){{kebab_break}} + scope: keyword.operator.string-format.powershell + captures: + 1: punctuation.definition.keyword.powershell + # Symbol operators + - match: '[+/*%-]?=' + scope: keyword.operator.assignment.powershell + - match: (?:\+\+|--)(?![ \t]*\d|[[:alpha:]]) + scope: keyword.operator.assignment.powershell + - match: '[+-](?=\.?\d)' # This is sort of heuristic + scope: keyword.operator.unary.powershell + # Be careful about matching arithmetic with tightly following words + - match: '[/+](?![[:alpha:]])' + scope: keyword.operator.arithmetic.powershell + - match: -(?![[:alpha:]-]) + scope: keyword.operator.arithmetic.powershell + - match: \* + scope: keyword.operator.arithmetic.powershell + - match: '%(?!\s*\{)' + scope: keyword.operator.arithmetic.powershell + - match: \|\||&& + scope: keyword.operator.logical.powershell + - match: \| + scope: keyword.operator.logical.pipe.powershell + - match: ; + scope: punctuation.terminator.statement.powershell + - match: \`(?=\n|$) + scope: punctuation.separator.continuation.line.powershell + - match: ',' + scope: punctuation.separator.sequence.powershell + - match: '&|\B\.(?= )' + scope: keyword.operator.other.powershell + - match: \.\.(?=\-?\d|\(|\$) + # This is very imprecise. Is there a syntax for 'must come after...'? + scope: keyword.operator.range.powershell + + redirection: + # https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_redirection + - match: ([2-6*])(>&)(1) + captures: + 1: constant.numeric.decimal.file-descriptor.powershell + 2: keyword.operator.redirection.powershell + 3: constant.numeric.decimal.file-descriptor.powershell + - match: ([1-6*])(>>?) + captures: + 1: constant.numeric.decimal.file-descriptor.powershell + 2: keyword.operator.redirection.powershell + - match: '>>?' + scope: keyword.operator.redirection.powershell + # - match: <+ + # scope: invalid.illegal.powershell + ###[ CLASSES ]################################################################# classes: From 12407796f55766985832a8e8b1c4f5b2e7b65aae Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Thu, 4 Dec 2025 19:18:46 -0500 Subject: [PATCH 11/81] Switch to pop: 1 --- PowerShell.sublime-syntax | 48 +++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index bb886d89..315bbf9d 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -152,13 +152,13 @@ contexts: - meta_scope: meta.attribute.powershell - match: \] scope: punctuation.section.brackets.end.powershell - pop: true + pop: 1 - match: \( scope: punctuation.section.group.begin.powershell push: - match: \) scope: punctuation.section.group.end.powershell - pop: true + pop: 1 - match: |- (?xi: \b( @@ -212,7 +212,7 @@ contexts: members: # - meta_content_scope: debug.in.members - match: (?=\.\.) - pop: true + pop: 1 - match: \.(?=\w) scope: punctuation.accessor.dot.powershell - match: (\w+)(\() @@ -223,7 +223,7 @@ contexts: - meta_content_scope: meta.function-call.arguments.powershell - match: \) scope: meta.function-call.arguments.powershell punctuation.section.arguments.end.powershell - pop: true + pop: 1 - include: expressions - match: \w+ scope: variable.other.member.powershell @@ -233,10 +233,10 @@ contexts: - meta_scope: meta.brackets.indexer.powershell - match: \] scope: punctuation.section.brackets.end.powershell - pop: true + pop: 1 - include: expressions - match: '' - pop: true + pop: 1 functions: - match: ^(?:\s*)(?i)(function|filter|configuration|workflow)\s+(?:(global|local|script|private):)?((?:\p{L}|\d|_|-|\.)+) @@ -247,7 +247,7 @@ contexts: 3: entity.name.function.powershell push: - match: (?=\{|\() - pop: true + pop: 1 - include: comment-line script-blocks: @@ -259,7 +259,7 @@ contexts: - meta_scope: meta.block.powershell - match: \} scope: punctuation.section.braces.end.powershell - pop: true + pop: 1 # TODO: Fix classes, so this doesn't nest here. - include: class-methods @@ -278,7 +278,7 @@ contexts: set: static-members - match: \] scope: punctuation.section.brackets.end.powershell - pop: true + pop: 1 - match: (?!\d+|\.)[\p{L}\p{N}.]+ scope: storage.type.powershell - include: types @@ -386,7 +386,7 @@ contexts: 5: entity.name.function.powershell push: - match: (?=\() - pop: true + pop: 1 - include: comment-line ###[ VARIABLES ]############################################################### @@ -560,7 +560,7 @@ contexts: - meta_scope: meta.group.powershell - match: \) scope: punctuation.section.group.end.powershell - pop: true + pop: 1 - include: expressions arrays: @@ -572,7 +572,7 @@ contexts: - meta_scope: meta.group.array-expression.powershell - match: \) scope: punctuation.section.group.end.powershell - pop: true + pop: 1 - include: expressions hashtables: @@ -584,7 +584,7 @@ contexts: - meta_scope: meta.hashtable.powershell - match: \} scope: punctuation.section.braces.end.powershell - pop: true + pop: 1 - match: \b(['"]?)(\w+)(['"]?)\s*(=)\s* scope: meta.hashtable.assignment.powershell captures: @@ -603,7 +603,7 @@ contexts: - meta_scope: meta.group.complex.subexpression.powershell - match: \) scope: punctuation.section.group.end.powershell - pop: true + pop: 1 - include: expressions ###[ CONSTANTS ]############################################################### @@ -645,7 +645,7 @@ contexts: scope: constant.character.escape.powershell - match: \' scope: punctuation.definition.string.end.powershell - pop: true + pop: 1 double-quoted-strings: - match: '"' @@ -660,7 +660,7 @@ contexts: - include: escape-sequences - match: '"' scope: punctuation.definition.string.end.powershell - pop: true + pop: 1 # # Silently eat email addresses # - match: '(?i)\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,64}\b' - include: string-interpolations @@ -675,7 +675,7 @@ contexts: - meta_scope: meta.string.powershell string.quoted.single.heredoc.powershell - match: ^'@ scope: punctuation.definition.string.end.powershell - pop: true + pop: 1 - match: "''" scope: constant.character.escape.powershell @@ -687,7 +687,7 @@ contexts: - meta_scope: meta.string.powershell string.quoted.double.heredoc.powershell - match: ^"@ scope: punctuation.definition.string.end.powershell - pop: true + pop: 1 - include: escape-sequences - include: string-interpolations @@ -700,7 +700,7 @@ contexts: - meta_content_scope: source.powershell.embedded - match: \) scope: punctuation.section.interpolation.end.powershell - pop: true + pop: 1 - include: expressions - match: (?=\$) push: @@ -782,7 +782,7 @@ contexts: - meta_scope: comment.block.powershell - match: '#>' scope: punctuation.definition.comment.block.end.powershell - pop: true + pop: 1 - include: comment-embedded-docs comment-embedded-docs: @@ -864,19 +864,19 @@ contexts: pop-eol: - match: $ - pop: true + pop: 1 pop-before-eol: - match: (?=$) - pop: true + pop: 1 immediately-pop: - match: '' - pop: true + pop: 1 else-pop: - match: (?=\S) - pop: true + pop: 1 ############################################################################### From 9ab0460be61c2b3b49a999657fb24f662abecdf4 Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Thu, 4 Dec 2025 19:21:17 -0500 Subject: [PATCH 12/81] Move redirection to statements --- PowerShell.sublime-syntax | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index 315bbf9d..6d0b389b 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -24,6 +24,7 @@ contexts: - include: statements statements: + - include: redirection - include: classes - include: expressions - include: functions @@ -86,7 +87,6 @@ contexts: # BUG: When we figure out what's wrong with `prototype`, remove this. - include: comments - - include: redirection - include: commands - include: constants - include: variables From 2b743d1dfdbdfd23d9d8db595d715354382bdfce Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Thu, 4 Dec 2025 19:31:44 -0500 Subject: [PATCH 13/81] Move the source function up to statements --- PowerShell.sublime-syntax | 4 +++- Tests/syntax_test_PowerShell.ps1 | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index 6d0b389b..4d4ac400 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -28,6 +28,8 @@ contexts: - include: classes - include: expressions - include: functions + - match: \B\.(?= ) + scope: support.function.source.powershell # Exceptions - match: \b(?i:throw){{kebab_break}} scope: keyword.control.exception.raise.powershell @@ -345,7 +347,7 @@ contexts: scope: punctuation.separator.continuation.line.powershell - match: ',' scope: punctuation.separator.sequence.powershell - - match: '&|\B\.(?= )' + - match: '&' scope: keyword.operator.other.powershell - match: \.\.(?=\-?\d|\(|\$) # This is very imprecise. Is there a syntax for 'must come after...'? diff --git a/Tests/syntax_test_PowerShell.ps1 b/Tests/syntax_test_PowerShell.ps1 index 85ba6d93..83ece94d 100644 --- a/Tests/syntax_test_PowerShell.ps1 +++ b/Tests/syntax_test_PowerShell.ps1 @@ -893,7 +893,7 @@ ls *.ps1 -recurse # Commands (executable files) . .\scripts\myscript.ps1 -parameter 'value' -# <- keyword.operator.other +# <- support.function.source.powershell # ^ punctuation.definition.parameter # ^^^^^^^^^^ variable.parameter.option # ^^^^^^^ string.quoted.single From 14cfb9f29ab069643a6f72c6fc293c50bf903523 Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Thu, 4 Dec 2025 22:03:20 -0500 Subject: [PATCH 14/81] Move begin/process/end/clean to script blocks --- PowerShell.sublime-syntax | 20 +++++++++++--------- Tests/syntax_test_Function.ps1 | 6 ++++++ Tests/syntax_test_PowerShell.ps1 | 4 ---- 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index 4d4ac400..c52d5035 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -39,15 +39,6 @@ contexts: scope: keyword.control.exception.catch.powershell - match: \b(?i:finally){{kebab_break}} scope: keyword.control.exception.finally.powershell - # Begin/End - - match: \b(?i:begin){{kebab_break}} - scope: keyword.context.block.begin.powershell - - match: \b(?i:process){{kebab_break}} - scope: keyword.context.block.process.powershell - - match: \b(?i:end){{kebab_break}} - scope: keyword.context.block.end.powershell - - match: \b(?i:clean){{kebab_break}} - scope: keyword.context.block.clean.powershell # Loops - match: \b(?i:for|foreach(?!-object)){{kebab_break}} scope: keyword.control.loop.for.powershell @@ -268,6 +259,17 @@ contexts: - match: \b(?i:hidden|static)\b scope: storage.modifier.powershell + # TODO: Fix functions, so this doesn't nest here. + # Begin/Process/End/Clean + - match: \b(?i:begin){{kebab_break}} + scope: keyword.context.block.begin.powershell + - match: \b(?i:process){{kebab_break}} + scope: keyword.context.block.process.powershell + - match: \b(?i:end){{kebab_break}} + scope: keyword.context.block.end.powershell + - match: \b(?i:clean){{kebab_break}} + scope: keyword.context.block.clean.powershell + - include: statements types: diff --git a/Tests/syntax_test_Function.ps1 b/Tests/syntax_test_Function.ps1 index f79bfdc7..220cd382 100644 --- a/Tests/syntax_test_Function.ps1 +++ b/Tests/syntax_test_Function.ps1 @@ -399,4 +399,10 @@ function Verb-Noun { #^^^ keyword.context.block.end } + clean { } +#^^^^^^^^^^^^ meta.block.powershell +# ^^^^^ keyword.context.block.clean.powershell +# ^^^ meta.block.powershell +# ^ punctuation.section.braces.begin.powershell +# ^ punctuation.section.braces.end.powershell } diff --git a/Tests/syntax_test_PowerShell.ps1 b/Tests/syntax_test_PowerShell.ps1 index 83ece94d..39a349a2 100644 --- a/Tests/syntax_test_PowerShell.ps1 +++ b/Tests/syntax_test_PowerShell.ps1 @@ -1338,10 +1338,6 @@ catch { } # <- keyword.control # ^ punctuation.section.braces.begin # ^ punctuation.section.braces.end -clean { } -# <- keyword.context.block.clean -# ^ punctuation.section.braces.begin -# ^ punctuation.section.braces.end # Reserved words Configuration Crazyness { From 9f928fc7757755cf2cb40316ba7c95e889b079ed Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Thu, 4 Dec 2025 22:12:57 -0500 Subject: [PATCH 15/81] Move attributes into groups and script blocks for Param and function metadata respectively --- PowerShell.sublime-syntax | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index c52d5035..04d04146 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -83,7 +83,6 @@ contexts: - include: commands - include: constants - include: variables - - include: attributes - include: using-directives - include: types - include: hashtables @@ -259,7 +258,8 @@ contexts: - match: \b(?i:hidden|static)\b scope: storage.modifier.powershell - # TODO: Fix functions, so this doesn't nest here. + # TODO: Fix functions, so these don't nest here. + - include: attributes # Begin/Process/End/Clean - match: \b(?i:begin){{kebab_break}} scope: keyword.context.block.begin.powershell @@ -565,6 +565,7 @@ contexts: - match: \) scope: punctuation.section.group.end.powershell pop: 1 + - include: attributes - include: expressions arrays: From c2274d2d299cc6c74e832b217d53fcf7bf4c1a5b Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Thu, 4 Dec 2025 22:16:14 -0500 Subject: [PATCH 16/81] Add some formatting --- PowerShell.sublime-syntax | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index 04d04146..f82312eb 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -28,8 +28,11 @@ contexts: - include: classes - include: expressions - include: functions + + # TODO: Continue into a command statement - match: \B\.(?= ) scope: support.function.source.powershell + # Exceptions - match: \b(?i:throw){{kebab_break}} scope: keyword.control.exception.raise.powershell @@ -39,6 +42,7 @@ contexts: scope: keyword.control.exception.catch.powershell - match: \b(?i:finally){{kebab_break}} scope: keyword.control.exception.finally.powershell + # Loops - match: \b(?i:for|foreach(?!-object)){{kebab_break}} scope: keyword.control.loop.for.powershell @@ -48,6 +52,7 @@ contexts: scope: keyword.control.loop.while.powershell - match: \b(?i:until){{kebab_break}} scope: keyword.control.loop.repeat-until.powershell + # Flow - match: \b(?i:break){{kebab_break}} scope: keyword.control.flow.break.powershell @@ -57,6 +62,7 @@ contexts: scope: keyword.control.flow.exit.powershell - match: \b(?i:return){{kebab_break}} scope: keyword.control.flow.return.powershell + # Conditionals - match: \b(?i:if){{kebab_break}} scope: keyword.control.conditional.if.powershell @@ -70,7 +76,8 @@ contexts: scope: keyword.control.conditional.select.powershell - match: \b(?i:where(?!-object)){{kebab_break}} scope: keyword.control.conditional.select.powershell - # Declaration + + # Declarations - match: \b(?i:var){{kebab_break}} scope: keyword.declaration.variable.powershell - match: \b(?i:(?:dynamic)?param){{kebab_break}} @@ -95,14 +102,18 @@ contexts: - include: subexpressions - match: \b[\w.-]+\.(?i:exe|com|cmd|bat)\b scope: variable.function.powershell + # Consume a string with a trailing dot # to prevent members with particular names from being recognized as keywords. - match: \b[\w-]+(?=\.) scope: variable.other.object.powershell push: members + # Uncategorized keywords - match: \b(?i:data|default|define|from|in|inlinescript|parallel|sequence){{kebab_break}} scope: keyword.control.powershell + + # Make everything afterward a literal - match: \B--%\B scope: keyword.control.powershell push: @@ -196,13 +207,11 @@ contexts: scope: support.function.powershell static-members: - # - meta_content_scope: debug.in.static-members - match: '::' scope: punctuation.accessor.double-colon.powershell set: members members: - # - meta_content_scope: debug.in.members - match: (?=\.\.) pop: 1 - match: \.(?=\w) @@ -270,6 +279,7 @@ contexts: - match: \b(?i:clean){{kebab_break}} scope: keyword.context.block.clean.powershell + # Back to normal stuff - include: statements types: From 4ea88b4d73aefc5d2a08946f87fb59c6a3262ecb Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Thu, 4 Dec 2025 22:34:47 -0500 Subject: [PATCH 17/81] Finish named contexts for string content --- PowerShell.sublime-syntax | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index f82312eb..d598da43 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -655,6 +655,7 @@ contexts: push: inside-single-quoted-string inside-single-quoted-string: + - meta_include_prototype: false - meta_scope: meta.string.powershell string.quoted.single.powershell - match: "''" scope: constant.character.escape.powershell @@ -685,26 +686,30 @@ contexts: single-quoted-heredoc-strings: - match: \@'(?=$) scope: punctuation.definition.string.begin.powershell - push: - - meta_include_prototype: false - - meta_scope: meta.string.powershell string.quoted.single.heredoc.powershell - - match: ^'@ - scope: punctuation.definition.string.end.powershell - pop: 1 - - match: "''" - scope: constant.character.escape.powershell + push: inside-single-quoted-heredoc-string + + inside-single-quoted-heredoc-string: + - meta_include_prototype: false + - meta_scope: meta.string.powershell string.quoted.single.heredoc.powershell + - match: ^'@ + scope: punctuation.definition.string.end.powershell + pop: 1 + - match: "''" + scope: constant.character.escape.powershell double-quoted-heredoc-strings: - match: \@"(?=$) scope: punctuation.definition.string.begin.powershell - push: - - meta_include_prototype: false - - meta_scope: meta.string.powershell string.quoted.double.heredoc.powershell - - match: ^"@ - scope: punctuation.definition.string.end.powershell - pop: 1 - - include: escape-sequences - - include: string-interpolations + push: inside-double-quoted-heredoc-string + + inside-double-quoted-heredoc-string: + - meta_include_prototype: false + - meta_scope: meta.string.powershell string.quoted.double.heredoc.powershell + - match: ^"@ + scope: punctuation.definition.string.end.powershell + pop: 1 + - include: escape-sequences + - include: string-interpolations string-interpolations: - match: \$\( From 43f59db63e7636ce72b238d6b4563e7eaa708630 Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Thu, 4 Dec 2025 22:46:39 -0500 Subject: [PATCH 18/81] Activate the prototype context Thanks, @keith-hall --- PowerShell.sublime-syntax | 74 +++++++++++++++++++-------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index d598da43..6de5d525 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -84,8 +84,8 @@ contexts: scope: keyword.declaration.parameter.powershell # This scope is not standard expressions: - # BUG: When we figure out what's wrong with `prototype`, remove this. - - include: comments + - include: regions + - include: requires-directives - include: commands - include: constants @@ -117,6 +117,7 @@ contexts: - match: \B--%\B scope: keyword.control.powershell push: + - meta_include_prototype: false - meta_content_scope: string.unquoted.powershell - include: pop-before-eol @@ -135,6 +136,37 @@ contexts: 2: keyword.other.powershell 3: variable.parameter.powershell + requires-directives: + - match: (#)((?i:requires))\s + captures: + 1: punctuation.definition.keyword.powershell + 2: keyword.control.import.require.powershell + push: + - meta_scope: meta.requires.powershell + - include: pop-eol + - include: hashtables + - match: (-)(?i:Modules|PSSnapin|RunAsAdministrator|ShellId|Version) + scope: variable.parameter.option.powershell + captures: + 1: punctuation.definition.variable.powershell + - match: ',' + scope: punctuation.separator.powershell + + regions: + - match: ^\s*((#)\s*(region\b)(?:\s*(\S.*))?(\n?)) + captures: + 1: comment.line.powershell + 2: punctuation.definition.comment.powershell + 3: keyword.other.region.begin.powershell + 4: meta.toc-list.powershell entity.name.section.powershell + 5: meta.fold.begin.powershell + - match: ^\s*((#)\s*(endregion\b).*(\n?)) + captures: + 1: comment.line.powershell + 2: punctuation.definition.comment.powershell + 3: keyword.other.region.end.powershell + 4: meta.fold.end.powershell + attributes: - match: |- (?xi: @@ -716,6 +748,7 @@ contexts: scope: punctuation.section.interpolation.begin.powershell push: - clear_scopes: 1 + - meta_include_prototype: false - meta_scope: meta.interpolation.powershell - meta_content_scope: source.powershell.embedded - match: \) @@ -725,6 +758,7 @@ contexts: - match: (?=\$) push: - clear_scopes: 1 + - meta_include_prototype: false - meta_scope: meta.interpolation.powershell - include: variables-without-property - include: variables @@ -790,8 +824,6 @@ contexts: ###[ COMMENTS ]################################################################ comments: - - include: regions - - include: requires-directives - include: comment-block - include: comment-line @@ -835,45 +867,13 @@ contexts: 3: markup.underline.link.powershell comment-line: - - match: '#' + - match: '#(?!(?i:requires|(?:end)?region)\b)' scope: punctuation.definition.comment.powershell push: - meta_scope: comment.line.powershell - include: pop-eol - include: comment-embedded-docs - regions: - - match: ^\s*((#)\s*(region\b)(?:\s*(\S.*))?(\n?)) - captures: - 1: comment.line.powershell - 2: punctuation.definition.comment.powershell - 3: keyword.other.region.begin.powershell - 4: meta.toc-list.powershell entity.name.section.powershell - 5: meta.fold.begin.powershell - - match: ^\s*((#)\s*(endregion\b).*(\n?)) - captures: - 1: comment.line.powershell - 2: punctuation.definition.comment.powershell - 3: keyword.other.region.end.powershell - 4: meta.fold.end.powershell - - requires-directives: - # TODO: add back `(?<=#)`-equivalent match - - match: (#)((?i:requires))\s - captures: - 1: punctuation.definition.keyword.powershell - 2: keyword.control.import.require.powershell - push: - - meta_scope: meta.requires.powershell - - include: pop-eol - - include: hashtables - - match: (-)(?i:Modules|PSSnapin|RunAsAdministrator|ShellId|Version) - scope: variable.parameter.option.powershell - captures: - 1: punctuation.definition.variable.powershell - - match: ',' - scope: punctuation.separator.powershell - ###[ COMPONENTS ]############################################################## escape-sequences: From c81c02c29cde4e654772dfb5820661c755a7129e Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Fri, 5 Dec 2025 10:21:16 -0500 Subject: [PATCH 19/81] Extract string tests to their own file --- Tests/syntax_test_PowerShell.ps1 | 209 +----------------------------- Tests/syntax_test_strings.ps1 | 212 +++++++++++++++++++++++++++++++ 2 files changed, 213 insertions(+), 208 deletions(-) create mode 100644 Tests/syntax_test_strings.ps1 diff --git a/Tests/syntax_test_PowerShell.ps1 b/Tests/syntax_test_PowerShell.ps1 index 39a349a2..8ed1bb43 100644 --- a/Tests/syntax_test_PowerShell.ps1 +++ b/Tests/syntax_test_PowerShell.ps1 @@ -171,72 +171,6 @@ $variable.Name.Method( ) # ^^^^^^^^^^^^^^^ - variable.other.readwrite # ^ - meta.function-call -# In double-quoted strings, only the variable should be highlighted, not the property -"This is my $variable.Name!" -# <- punctuation.definition.string.begin -#^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string -#^^^^^^^^^^^ string.quoted.double -# ^^^^^^^^^ meta.interpolation variable.other.readwrite - string -# ^ punctuation.definition.variable -# ^^^^^^ string.quoted.double - meta.interpolation - variable - punctuation -# ^ punctuation.definition.string.end - -# When used in a subexpression, both should be highlighted -"This is my $($variable.Name)!" -# <- punctuation.definition.string.begin -#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string -#^^^^^^^^^^^ string.quoted.double -# ^^^^^^^^^^^^^^^^^ meta.interpolation - string -# ^^ string.quoted.double - meta.interpolation -# ^^ punctuation.section.interpolation.begin -# ^^^^^^^^^ variable.other.readwrite -# ^ punctuation.definition.variable -# ^ punctuation.accessor.dot -# ^^^^ variable.other.member -# ^ punctuation.section.interpolation.end -# ^ punctuation.definition.string.end - -# $ENV:ComputerName should be highlighted -"This is the name of my computer: $ENV:ComputerName" -# <- punctuation.definition.string.begin -#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string -#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ string.quoted.double -# ^^^^^^^^^^^^^^^^^ meta.interpolation - string -# ^ punctuation.definition.variable -# ^^^^ support.variable.drive -# ^^^^^^^^^^^^ variable.other.readwrite -# ^ punctuation.definition.string.end - -# Here as well -"This is the name of my computer: ${ENV:ComputerName}" -# <- punctuation.definition.string.begin -#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string -#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ string.quoted.double -# ^^^^^^^^^^^^^^^^^^^ meta.interpolation - string -# ^ punctuation.definition.variable -# ^ punctuation.section.braces.begin -# ^^^^ support.variable.drive -# ^^^^^^^^^^^^ variable.other.readwrite -# ^ punctuation.definition.string.end - -# The @splat references only work in argument mode, should not highlight in strings -"This is a @double quoted string." -# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string string.quoted.double -# ^ - punctuation.definition.variable -# ^^^^^^^ - variable - -# double check scopes for automatic variables in strings -"$_ $$ $Pwd" -#^^ variable.language -# ^^ variable.language -# ^^^^ variable.language - -# Single quotes string -'This is a string' -# <- punctuation.definition.string.begin -#^^^^^^^^^^^^^^^^^ meta.string string.quoted.single -# ^ punctuation.definition.string.end - # Hashtable $properties = @{ # <- punctuation.definition.variable @@ -426,66 +360,6 @@ $a3[1..2] # ^ punctuation.section.brackets.end # ^^^^^^^^^^^^^^^ meta.brackets.indexer -# Single quoted strings - 'This is a single quoted string.' -# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string string.quoted.single - '$This is a single ''quoted'' string.' -# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string string.quoted.single -# ^^ constant.character.escape -# ^^ constant.character.escape - 'This is a - single quoted string.' -# ^^^^^^^^^^^^^^^^^^^^^^ meta.string string.quoted.single - 'This #also' -# ^^^^^^^^^^^^ meta.string string.quoted.single - '$(Invoke-Something)' -# ^^^^^^^^^^^^^^^^^^^^^ meta.string string.quoted.single - meta.interpolation - variable - support - 'This "string" is nice.' -# ^^^^^^^^^^^^^^^^^^^^^^^^ meta.string string.quoted.single - -# Double quoted strings - "This is a double quoted string." -# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string string.quoted.double - "$This is a double ""quoted"" string." -# ^ meta.string string.quoted.double -# ^^^^^ meta.string meta.interpolation variable.language - string -# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string string.quoted.double - meta.interpolation -# ^^ constant.character.escape -# ^^ constant.character.escape - "This is a - double quoted string." -# ^^^^^^^^^^^^^^^^^^^^^^ meta.string string.quoted.double - "This #also" -# ^^^^^^^^^^^^ meta.string string.quoted.double - "$(Invoke-Something)" -# ^ meta.string string.quoted.double -# ^^^^^^^^^^^^^^^^^^^ meta.string meta.interpolation - string -# ^^ punctuation.section.interpolation.begin -# ^^^^^^^^^^^^^^^^ support.function -# ^ punctuation.section.interpolation.end -# @@@@@@@@@@@@@@@@ reference - "This 'string' is nice." -# ^^^^^^^^^^^^^^^^^^^^^^^^ meta.string string.quoted.double - -# Double quoted here-string -@" -# <- string.quoted.double.heredoc - # <- string.quoted.double.heredoc -$This is a 'double quoted' -# <- punctuation.definition.variable -#^^^^ variable.language -Isn't it "nice"?? -There is no @platting here! -# ^^^^^^^^^ - variable - punctuation -"@ -# <- string.quoted.double.heredoc - # <- string.quoted.double.heredoc -@' -#<- meta.string string.quoted.single.heredoc punctuation.definition.string.begin -A 'single quoted' "heredoc" -'@ -#<- meta.string string.quoted.single.heredoc punctuation.definition.string.end - # Numeric constants -3 +3 3 3l 3lm 3lmb @@ -1487,75 +1361,6 @@ $b -cLike $c "HEY" -ile "hey" # ^^^^ keyword.operator.comparison -# format - "{0:N2}" -f $a -# ^^^^^^^^ string.quoted.double -# ^^ keyword.operator.string-format - "{0:D8}" -f $a -# ^^^^^^^^ string.quoted.double -# ^^ keyword.operator.string-format - "{0:C2}" -f $a -# ^^^^^^^^ string.quoted.double -# ^^ keyword.operator.string-format - "{0:P0}" -f $a -# ^^^^^^^^ string.quoted.double -# ^^ keyword.operator.string-format - "{0:X0}" -f $a -# ^^^^^^^^ string.quoted.double -# ^^ keyword.operator.string-format - (1.11).ToString("#.#") -# ^ punctuation.section.group.begin -# ^^^^ meta.number.float.decimal constant.numeric.value -# ^ punctuation.section.group.begin -# ^ string.quoted.double - "{1,10} {0,10} {2,10:x}" -f "First", "Second", 255 -# ^^^^^^^^^^^^^^^^^^^^^^^^ string.quoted.double -# ^^ keyword.operator.string-format -# ^^^ meta.number.integer.decimal constant.numeric.value - ("{0,6}" -f 4.99), ("{0,6:##.00}" -f 15.9) -# ^^ keyword.operator.string-format -# ^^^^ meta.number.float.decimal constant.numeric.value -# ^^^^^^^^^^^^^ string.quoted.double -# ^^ keyword.operator.string-format - "{0:R}" -f (1mb/2.0) -# ^ keyword.operator.string-format -# ^ meta.number.integer.decimal constant.numeric.value -# ^^ meta.number.integer.decimal constant.numeric.suffix - "{0:00.0}" -f 4.12341234 -# ^ keyword.operator.string-format - "{0:##.#}" -f 4.12341234 -# ^ string.quoted.double -# ^ keyword.operator.string-format -# ^^^^^^^^^^ meta.number.float.decimal constant.numeric.value - "{0:#,#.#}" -f 1234.121234 -# ^ string.quoted.double -# ^ keyword.operator.string-format - "{0:##,,.000}" -f 1048576 -# ^ string.quoted.double -# ^ keyword.operator.string-format - "{this is not a #comment}" -# ^ - comment - "{0:##.#E000}" -f 2.71828 -# ^ string.quoted.double -# ^ keyword.operator.string-format - "{0:#.00'##'}" -f 2.71828 -# ^ string.quoted.double -# ^ keyword.operator.string-format - "{0:POS;NEG;ZERO}" -f -14 -# ^ string.quoted.double -# ^ keyword.operator.string-format - "{0:$## Please}" -f 14 -# ^ string.quoted.double -# ^ keyword.operator.string-format - "{0,-8:P1}" -f 1.75 -# ^ string.quoted.double -# ^ keyword.operator.string-format - "{0,10:N3}{1,10:N3}{2,10:N3}{3,10:N3}" -f 0.2, 0.3, 0.45, 0.91 -# ^ keyword.operator.string-format - '{0:00000.000}' -f 7.125 -# ^ string.quoted.single -# ^ keyword.operator.string-format - function Test-Function {} # @@@@@@@@@@@@@ definition function New-Object {} @@ -1653,19 +1458,7 @@ function Out-WithYou {} # ^ constant.language # ^ punctuation.definition.comment # ^^^^^^^^^ comment.line -"Escaped chars: `", `n, `$, `b, `t, `e, `u{10ffff}, `"" -#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ string.quoted.double -# ^^ constant.character.escape -# ^^ constant.character.escape -# ^^ constant.character.escape -# ^^ constant.character.escape -# ^^ constant.character.escape -# ^^ constant.character.escape -# ^^^^^^^^^^ constant.character.escape -# ^^ constant.character.escape -'But here they''re not escape chars: `", `n, `$, `b, `"' -# ^^ constant.character.escape -# ^^^^^^^^^^^^^^^^^^^ - constant + function get-number {} # @@@@@@@@@@ definition "When you call a method: $( get-number | %{ invoke-command $( [string]::format("Like (this{0})","what?") ) $var } )" diff --git a/Tests/syntax_test_strings.ps1 b/Tests/syntax_test_strings.ps1 new file mode 100644 index 00000000..56f617fb --- /dev/null +++ b/Tests/syntax_test_strings.ps1 @@ -0,0 +1,212 @@ +# SYNTAX TEST "Packages/PowerShell/PowerShell.sublime-syntax" + +# In double-quoted strings, only the variable should be highlighted, not the property +"This is my $variable.Name!" +# <- punctuation.definition.string.begin +#^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string +#^^^^^^^^^^^ string.quoted.double +# ^^^^^^^^^ meta.interpolation variable.other.readwrite - string +# ^ punctuation.definition.variable +# ^^^^^^ string.quoted.double - meta.interpolation - variable - punctuation +# ^ punctuation.definition.string.end + +# When used in a subexpression, both should be highlighted +"This is my $($variable.Name)!" +# <- punctuation.definition.string.begin +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string +#^^^^^^^^^^^ string.quoted.double +# ^^^^^^^^^^^^^^^^^ meta.interpolation - string +# ^^ string.quoted.double - meta.interpolation +# ^^ punctuation.section.interpolation.begin +# ^^^^^^^^^ variable.other.readwrite +# ^ punctuation.definition.variable +# ^ punctuation.accessor.dot +# ^^^^ variable.other.member +# ^ punctuation.section.interpolation.end +# ^ punctuation.definition.string.end + +# $ENV:ComputerName should be highlighted +"This is the name of my computer: $ENV:ComputerName" +# <- punctuation.definition.string.begin +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ string.quoted.double +# ^^^^^^^^^^^^^^^^^ meta.interpolation - string +# ^ punctuation.definition.variable +# ^^^^ support.variable.drive +# ^^^^^^^^^^^^ variable.other.readwrite +# ^ punctuation.definition.string.end + +# Here as well +"This is the name of my computer: ${ENV:ComputerName}" +# <- punctuation.definition.string.begin +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ string.quoted.double +# ^^^^^^^^^^^^^^^^^^^ meta.interpolation - string +# ^ punctuation.definition.variable +# ^ punctuation.section.braces.begin +# ^^^^ support.variable.drive +# ^^^^^^^^^^^^ variable.other.readwrite +# ^ punctuation.definition.string.end + +# The @splat references only work in argument mode, should not highlight in strings +"This is a @double quoted string." +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string string.quoted.double +# ^ - punctuation.definition.variable +# ^^^^^^^ - variable + +# double check scopes for automatic variables in strings +"$_ $$ $Pwd" +#^^ variable.language +# ^^ variable.language +# ^^^^ variable.language + +# Single quotes string +'This is a string' +# <- punctuation.definition.string.begin +#^^^^^^^^^^^^^^^^^ meta.string string.quoted.single +# ^ punctuation.definition.string.end + + +# Single quoted strings + 'This is a single quoted string.' +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string string.quoted.single + '$This is a single ''quoted'' string.' +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string string.quoted.single +# ^^ constant.character.escape +# ^^ constant.character.escape + 'This is a + single quoted string.' +# ^^^^^^^^^^^^^^^^^^^^^^ meta.string string.quoted.single + 'This #also' +# ^^^^^^^^^^^^ meta.string string.quoted.single + '$(Invoke-Something)' +# ^^^^^^^^^^^^^^^^^^^^^ meta.string string.quoted.single - meta.interpolation - variable - support + 'This "string" is nice.' +# ^^^^^^^^^^^^^^^^^^^^^^^^ meta.string string.quoted.single + +# Double quoted strings + "This is a double quoted string." +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string string.quoted.double + "$This is a double ""quoted"" string." +# ^ meta.string string.quoted.double +# ^^^^^ meta.string meta.interpolation variable.language - string +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string string.quoted.double - meta.interpolation +# ^^ constant.character.escape +# ^^ constant.character.escape + "This is a + double quoted string." +# ^^^^^^^^^^^^^^^^^^^^^^ meta.string string.quoted.double + "This #also" +# ^^^^^^^^^^^^ meta.string string.quoted.double + "$(Invoke-Something)" +# ^ meta.string string.quoted.double +# ^^^^^^^^^^^^^^^^^^^ meta.string meta.interpolation - string +# ^^ punctuation.section.interpolation.begin +# ^^^^^^^^^^^^^^^^ support.function +# ^ punctuation.section.interpolation.end +# @@@@@@@@@@@@@@@@ reference + "This 'string' is nice." +# ^^^^^^^^^^^^^^^^^^^^^^^^ meta.string string.quoted.double + +# Double quoted here-string +@" +# <- string.quoted.double.heredoc + # <- string.quoted.double.heredoc +$This is a 'double quoted' +# <- punctuation.definition.variable +#^^^^ variable.language +Isn't it "nice"?? +There is no @platting here! +# ^^^^^^^^^ - variable - punctuation +"@ +# <- string.quoted.double.heredoc + # <- string.quoted.double.heredoc +@' +#<- meta.string string.quoted.single.heredoc punctuation.definition.string.begin +A 'single quoted' "heredoc" +'@ +#<- meta.string string.quoted.single.heredoc punctuation.definition.string.end + + +# format + "{0:N2}" -f $a +# ^^^^^^^^ string.quoted.double +# ^^ keyword.operator.string-format + "{0:D8}" -f $a +# ^^^^^^^^ string.quoted.double +# ^^ keyword.operator.string-format + "{0:C2}" -f $a +# ^^^^^^^^ string.quoted.double +# ^^ keyword.operator.string-format + "{0:P0}" -f $a +# ^^^^^^^^ string.quoted.double +# ^^ keyword.operator.string-format + "{0:X0}" -f $a +# ^^^^^^^^ string.quoted.double +# ^^ keyword.operator.string-format + (1.11).ToString("#.#") +# ^ punctuation.section.group.begin +# ^^^^ meta.number.float.decimal constant.numeric.value +# ^ punctuation.section.group.begin +# ^ string.quoted.double + "{1,10} {0,10} {2,10:x}" -f "First", "Second", 255 +# ^^^^^^^^^^^^^^^^^^^^^^^^ string.quoted.double +# ^^ keyword.operator.string-format +# ^^^ meta.number.integer.decimal constant.numeric.value + ("{0,6}" -f 4.99), ("{0,6:##.00}" -f 15.9) +# ^^ keyword.operator.string-format +# ^^^^ meta.number.float.decimal constant.numeric.value +# ^^^^^^^^^^^^^ string.quoted.double +# ^^ keyword.operator.string-format + "{0:R}" -f (1mb/2.0) +# ^ keyword.operator.string-format +# ^ meta.number.integer.decimal constant.numeric.value +# ^^ meta.number.integer.decimal constant.numeric.suffix + "{0:00.0}" -f 4.12341234 +# ^ keyword.operator.string-format + "{0:##.#}" -f 4.12341234 +# ^ string.quoted.double +# ^ keyword.operator.string-format +# ^^^^^^^^^^ meta.number.float.decimal constant.numeric.value + "{0:#,#.#}" -f 1234.121234 +# ^ string.quoted.double +# ^ keyword.operator.string-format + "{0:##,,.000}" -f 1048576 +# ^ string.quoted.double +# ^ keyword.operator.string-format + "{this is not a #comment}" +# ^ - comment + "{0:##.#E000}" -f 2.71828 +# ^ string.quoted.double +# ^ keyword.operator.string-format + "{0:#.00'##'}" -f 2.71828 +# ^ string.quoted.double +# ^ keyword.operator.string-format + "{0:POS;NEG;ZERO}" -f -14 +# ^ string.quoted.double +# ^ keyword.operator.string-format + "{0:$## Please}" -f 14 +# ^ string.quoted.double +# ^ keyword.operator.string-format + "{0,-8:P1}" -f 1.75 +# ^ string.quoted.double +# ^ keyword.operator.string-format + "{0,10:N3}{1,10:N3}{2,10:N3}{3,10:N3}" -f 0.2, 0.3, 0.45, 0.91 +# ^ keyword.operator.string-format + '{0:00000.000}' -f 7.125 +# ^ string.quoted.single +# ^ keyword.operator.string-format + +"Escaped chars: `", `n, `$, `b, `t, `e, `u{10ffff}, `"" +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ string.quoted.double +# ^^ constant.character.escape +# ^^ constant.character.escape +# ^^ constant.character.escape +# ^^ constant.character.escape +# ^^ constant.character.escape +# ^^ constant.character.escape +# ^^^^^^^^^^ constant.character.escape +# ^^ constant.character.escape +'But here they''re not escape chars: `", `n, `$, `b, `"' +# ^^ constant.character.escape +# ^^^^^^^^^^^^^^^^^^^ - constant From b572a9b7d85d164e01fc6f6fc66f5d8c4f711048 Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Fri, 5 Dec 2025 10:51:00 -0500 Subject: [PATCH 20/81] Fully qualify the string test assertions --- PowerShell.sublime-syntax | 4 +- Tests/syntax_test_strings.ps1 | 544 +++++++++++++++++++++++----------- 2 files changed, 380 insertions(+), 168 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index 6de5d525..067cf704 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -702,7 +702,7 @@ contexts: inside-double-quoted-string: - meta_include_prototype: false - - meta_scope: meta.string.powershell string.quoted.double.powershell + - meta_scope: meta.string.interpolated.powershell string.quoted.double.powershell - match: '""' scope: constant.character.escape.powershell - include: escape-sequences @@ -736,7 +736,7 @@ contexts: inside-double-quoted-heredoc-string: - meta_include_prototype: false - - meta_scope: meta.string.powershell string.quoted.double.heredoc.powershell + - meta_scope: meta.string.interpolated.powershell string.quoted.double.heredoc.powershell - match: ^"@ scope: punctuation.definition.string.end.powershell pop: 1 diff --git a/Tests/syntax_test_strings.ps1 b/Tests/syntax_test_strings.ps1 index 56f617fb..f6f020d6 100644 --- a/Tests/syntax_test_strings.ps1 +++ b/Tests/syntax_test_strings.ps1 @@ -1,103 +1,156 @@ # SYNTAX TEST "Packages/PowerShell/PowerShell.sublime-syntax" -# In double-quoted strings, only the variable should be highlighted, not the property -"This is my $variable.Name!" -# <- punctuation.definition.string.begin -#^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string -#^^^^^^^^^^^ string.quoted.double -# ^^^^^^^^^ meta.interpolation variable.other.readwrite - string -# ^ punctuation.definition.variable -# ^^^^^^ string.quoted.double - meta.interpolation - variable - punctuation -# ^ punctuation.definition.string.end - -# When used in a subexpression, both should be highlighted -"This is my $($variable.Name)!" -# <- punctuation.definition.string.begin -#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string -#^^^^^^^^^^^ string.quoted.double -# ^^^^^^^^^^^^^^^^^ meta.interpolation - string -# ^^ string.quoted.double - meta.interpolation -# ^^ punctuation.section.interpolation.begin -# ^^^^^^^^^ variable.other.readwrite -# ^ punctuation.definition.variable -# ^ punctuation.accessor.dot -# ^^^^ variable.other.member -# ^ punctuation.section.interpolation.end -# ^ punctuation.definition.string.end - -# $ENV:ComputerName should be highlighted -"This is the name of my computer: $ENV:ComputerName" -# <- punctuation.definition.string.begin -#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string -#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ string.quoted.double -# ^^^^^^^^^^^^^^^^^ meta.interpolation - string -# ^ punctuation.definition.variable -# ^^^^ support.variable.drive -# ^^^^^^^^^^^^ variable.other.readwrite -# ^ punctuation.definition.string.end - -# Here as well -"This is the name of my computer: ${ENV:ComputerName}" -# <- punctuation.definition.string.begin -#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string -#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ string.quoted.double -# ^^^^^^^^^^^^^^^^^^^ meta.interpolation - string -# ^ punctuation.definition.variable -# ^ punctuation.section.braces.begin -# ^^^^ support.variable.drive -# ^^^^^^^^^^^^ variable.other.readwrite -# ^ punctuation.definition.string.end - -# The @splat references only work in argument mode, should not highlight in strings -"This is a @double quoted string." -# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string string.quoted.double -# ^ - punctuation.definition.variable -# ^^^^^^^ - variable - -# double check scopes for automatic variables in strings -"$_ $$ $Pwd" -#^^ variable.language -# ^^ variable.language -# ^^^^ variable.language - -# Single quotes string -'This is a string' -# <- punctuation.definition.string.begin -#^^^^^^^^^^^^^^^^^ meta.string string.quoted.single -# ^ punctuation.definition.string.end - - -# Single quoted strings +###[ Single Quoted Strings ]################################################### + 'This is a single quoted string.' -# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string string.quoted.single - '$This is a single ''quoted'' string.' -# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string string.quoted.single -# ^^ constant.character.escape -# ^^ constant.character.escape +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string.powershell string.quoted.single.powershell - meta.string.interpolated +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell + 'This is a +# ^^^^^^^^^^ meta.string.powershell string.quoted.single.powershell - meta.string.interpolated +# ^ punctuation.definition.string.begin.powershell single quoted string.' -# ^^^^^^^^^^^^^^^^^^^^^^ meta.string string.quoted.single +#^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string.powershell string.quoted.single.powershell - meta.string.interpolated +# ^ punctuation.definition.string.end.powershell + 'This #also' -# ^^^^^^^^^^^^ meta.string string.quoted.single - '$(Invoke-Something)' -# ^^^^^^^^^^^^^^^^^^^^^ meta.string string.quoted.single - meta.interpolation - variable - support +# ^^^^^^^^^^^^ meta.string.powershell string.quoted.single.powershell - comment +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell + 'This "string" is nice.' -# ^^^^^^^^^^^^^^^^^^^^^^^^ meta.string string.quoted.single +# ^^^^^^^^^^^^^^^^^^^^^^^^ meta.string.powershell string.quoted.single.powershell - constant +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell + + '$This is a single ''quoted'' string.' +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string.powershell string.quoted.single.powershell - meta.string.interpolated +# ^ punctuation.definition.string.begin.powershell +# ^^ constant.character.escape.powershell +# ^^ constant.character.escape.powershell +# ^ punctuation.definition.string.end.powershell + + '$(Invoke-Something)' +# ^^^^^^^^^^^^^^^^^^^^^ meta.string.powershell string.quoted.single.powershell - meta.interpolation - variable - support +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell + + 'Not escape chars: `", `n, `$, `b, `"' +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string.powershell string.quoted.single.powershell - constant +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell + + @' +# ^^ meta.string.powershell string.quoted.single.heredoc.powershell punctuation.definition.string.begin.powershell - meta.string.interpolated + A 'single quoted' "heredoc" +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string.powershell string.quoted.single.heredoc.powershell - punctuation + '@ +#^^^^^ meta.string.powershell string.quoted.single.heredoc.powershell - punctuation +'@ +#^ meta.string.powershell string.quoted.single.heredoc.powershell punctuation.definition.string.end.powershell + + +###[ Double Quoted Strings ]################################################### -# Double quoted strings "This is a double quoted string." -# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string string.quoted.double +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell + + "This is a +# ^^^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell + double quoted string." +#^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.end.powershell + + "This #also" +# ^^^^^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell - comment +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell + + "This 'string' is nice." +# ^^^^^^^^^^^^^^^^^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell - constant +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell + "$This is a double ""quoted"" string." # ^ meta.string string.quoted.double # ^^^^^ meta.string meta.interpolation variable.language - string # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string string.quoted.double - meta.interpolation # ^^ constant.character.escape # ^^ constant.character.escape - "This is a - double quoted string." -# ^^^^^^^^^^^^^^^^^^^^^^ meta.string string.quoted.double - "This #also" -# ^^^^^^^^^^^^ meta.string string.quoted.double + + # In double-quoted strings, only the variable should be highlighted, not the property + "This is my $variable.Name!" +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string.interpolated.powershell +# ^^^^^^^^^^^^ string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^^^^^^^^^ meta.interpolation.powershell variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^^^^^^^ string.quoted.double.powershell - meta.interpolation - variable - punctuation.accessor +# ^ punctuation.definition.string.end.powershell + + # When used in a subexpression, both should be highlighted + "This is my $($variable.Name)!" +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string.interpolated.powershell +# ^^^^^^^^^^^^ string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^^^^^^^^^^^^^^^^^ meta.interpolation.powershell - string +# ^^ punctuation.section.interpolation.begin.powershell +# ^^^^^^^^^^^^^^ source.powershell.embedded +# ^^^^^^^^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^ punctuation.accessor.dot.powershell +# ^^^^ variable.other.member.powershell +# ^ punctuation.section.interpolation.end.powershell +# ^^ string.quoted.double.powershell - meta.interpolation +# ^ punctuation.definition.string.end.powershell + + # $ENV:ComputerName should be highlighted + "This is the name of my computer: $ENV:ComputerName" +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string.interpolated.powershell +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^^^^^^^^^^^^^^^^^ meta.interpolation.powershell variable.other.readwrite.powershell - string +# ^ punctuation.definition.variable.powershell +# ^^^^ support.variable.drive.powershell +# ^ string.quoted.double.powershell punctuation.definition.string.end.powershell + + # Here as well + "This is the name of my computer: ${ENV:ComputerName}" +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string.interpolated.powershell +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^^^^^^^^^^^^^^^^^^^ meta.interpolation.powershell - string +# ^ punctuation.definition.variable.powershell +# ^ punctuation.section.braces.begin +# ^^^^ support.variable.drive.powershell +# ^^^^^^^^^^^^ variable.other.readwrite.powershell +# ^ punctuation.section.braces.end +# ^ string.quoted.double.powershell punctuation.definition.string.end.powershell + + # The @splat references only work in argument mode, should not highlight in strings + "This is a @double quoted string." +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell - variable - punctuation.definition.variable +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell + + # Double check scopes for automatic variables in strings + "$_ $$ $Pwd" +# ^^^^^^^^^^^^ meta.string.interpolated.powershell +# ^ string.quoted.double.powershell punctuation.definition.string.begin.powershell +# ^^ meta.interpolation.powershell variable.language.powershell - string +# ^ punctuation.definition.variable.powershell +# ^ string.quoted.double.powershell +# ^^ meta.interpolation.powershell variable.language.powershell - string +# ^ punctuation.definition.variable.powershell +# ^ string.quoted.double.powershell +# ^^^^ meta.interpolation.powershell variable.language.powershell - string +# ^ punctuation.definition.variable.powershell +# ^ string.quoted.double.powershell punctuation.definition.string.end.powershell + "$(Invoke-Something)" # ^ meta.string string.quoted.double # ^^^^^^^^^^^^^^^^^^^ meta.string meta.interpolation - string @@ -105,108 +158,267 @@ # ^^^^^^^^^^^^^^^^ support.function # ^ punctuation.section.interpolation.end # @@@@@@@@@@@@@@@@ reference - "This 'string' is nice." -# ^^^^^^^^^^^^^^^^^^^^^^^^ meta.string string.quoted.double - -# Double quoted here-string -@" -# <- string.quoted.double.heredoc - # <- string.quoted.double.heredoc -$This is a 'double quoted' -# <- punctuation.definition.variable -#^^^^ variable.language -Isn't it "nice"?? -There is no @platting here! -# ^^^^^^^^^ - variable - punctuation + + # Double quoted here-string + @" +# ^^ meta.string.interpolated.powershell string.quoted.double.heredoc.powershell punctuation.definition.string.begin.powershell + $This is a 'double quoted' +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string.interpolated.powershell +#^^^ string.quoted.double.heredoc.powershell +# ^^^^^ meta.interpolation.powershell variable.language.powershell +# ^ punctuation.definition.variable.powershell +# ^^^^^^^^^^^^^^^^^^^^^ string.quoted.double.heredoc.powershell + Isn't it "nice"?? +#^^^^^^^^^^^^^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.heredoc.powershell - punctuation + There is no @splatting here! +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.heredoc.powershell + "@ +#^^^^^ meta.string.interpolated.powershell string.quoted.double.heredoc.powershell - punctuation "@ -# <- string.quoted.double.heredoc - # <- string.quoted.double.heredoc -@' -#<- meta.string string.quoted.single.heredoc punctuation.definition.string.begin -A 'single quoted' "heredoc" -'@ -#<- meta.string string.quoted.single.heredoc punctuation.definition.string.end +#^ meta.string.interpolated.powershell string.quoted.double.heredoc.powershell punctuation.definition.string.end.powershell + + "Escaped chars: `", `n, `$, `b, `t, `e, `u{10ffff}, `"" +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^^ constant.character.escape.powershell +# ^^ constant.character.escape.powershell +# ^^ constant.character.escape.powershell +# ^^ constant.character.escape.powershell +# ^^ constant.character.escape.powershell +# ^^ constant.character.escape.powershell +# ^^^^^^^^^^ constant.character.escape.powershell +# ^^ constant.character.escape.powershell +# ^ punctuation.definition.string.end.powershell + + +###[ String Formatting ]####################################################### -# format "{0:N2}" -f $a -# ^^^^^^^^ string.quoted.double -# ^^ keyword.operator.string-format +# ^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^^ keyword.operator.string-format.powershell +# ^ punctuation.definition.keyword.powershell +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell + "{0:D8}" -f $a -# ^^^^^^^^ string.quoted.double -# ^^ keyword.operator.string-format +# ^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^^ keyword.operator.string-format.powershell +# ^ punctuation.definition.keyword.powershell +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell + "{0:C2}" -f $a -# ^^^^^^^^ string.quoted.double -# ^^ keyword.operator.string-format +# ^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^^ keyword.operator.string-format.powershell +# ^ punctuation.definition.keyword.powershell +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell + "{0:P0}" -f $a -# ^^^^^^^^ string.quoted.double -# ^^ keyword.operator.string-format +# ^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^^ keyword.operator.string-format.powershell +# ^ punctuation.definition.keyword.powershell +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell + "{0:X0}" -f $a -# ^^^^^^^^ string.quoted.double -# ^^ keyword.operator.string-format +# ^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^^ keyword.operator.string-format.powershell +# ^ punctuation.definition.keyword.powershell +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell + + # TODO: Mark ToString as a function (1.11).ToString("#.#") -# ^ punctuation.section.group.begin -# ^^^^ meta.number.float.decimal constant.numeric.value -# ^ punctuation.section.group.begin -# ^ string.quoted.double +# ^^^^^^ meta.group.powershell +# ^ punctuation.section.group.begin.powershell +# ^^^^ meta.number.float.decimal.powershell constant.numeric.value.powershell +# ^ punctuation.separator.decimal.powershell +# ^ punctuation.section.group.end.powershell +# ^^^^^^^ meta.group.powershell +# ^ punctuation.section.group.begin.powershell +# ^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell - comment +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^ punctuation.section.group.end.powershell + "{1,10} {0,10} {2,10:x}" -f "First", "Second", 255 -# ^^^^^^^^^^^^^^^^^^^^^^^^ string.quoted.double -# ^^ keyword.operator.string-format -# ^^^ meta.number.integer.decimal constant.numeric.value +# ^^^^^^^^^^^^^^^^^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^^ keyword.operator.string-format.powershell +# ^ punctuation.definition.keyword.powershell +# ^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^ punctuation.separator.sequence.powershell +# ^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^ punctuation.separator.sequence.powershell +# ^^^ meta.number.integer.decimal.powershell constant.numeric.value.powershell + ("{0,6}" -f 4.99), ("{0,6:##.00}" -f 15.9) -# ^^ keyword.operator.string-format -# ^^^^ meta.number.float.decimal constant.numeric.value -# ^^^^^^^^^^^^^ string.quoted.double -# ^^ keyword.operator.string-format +# ^^^^^^^^^^^^^^^^^ meta.group.powershell +# ^ punctuation.section.group.begin.powershell +# ^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^^ keyword.operator.string-format.powershell +# ^ punctuation.definition.keyword.powershell +# ^^^^ meta.number.float.decimal.powershell constant.numeric.value.powershell +# ^ punctuation.separator.decimal.powershell +# ^ punctuation.section.group.end.powershell +# ^ punctuation.separator.sequence.powershell +# ^^^^^^^^^^^^^^^^^^^^^^^ meta.group.powershell +# ^ punctuation.section.group.begin.powershell +# ^^^^^^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^^ keyword.operator.string-format.powershell +# ^ punctuation.definition.keyword.powershell +# ^^^^ meta.number.float.decimal.powershell constant.numeric.value.powershell +# ^ punctuation.separator.decimal.powershell +# ^ punctuation.section.group.end.powershell + "{0:R}" -f (1mb/2.0) -# ^ keyword.operator.string-format -# ^ meta.number.integer.decimal constant.numeric.value -# ^^ meta.number.integer.decimal constant.numeric.suffix +# ^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^^ keyword.operator.string-format.powershell +# ^ punctuation.definition.keyword.powershell +# ^^^^^^^^^ meta.group.powershell +# ^ punctuation.section.group.begin.powershell +# ^^^ meta.number.integer.decimal.powershell +# ^ constant.numeric.value.powershell +# ^^ constant.numeric.suffix.powershell +# ^ keyword.operator.arithmetic.powershell +# ^^^ meta.number.float.decimal.powershell constant.numeric.value.powershell +# ^ punctuation.separator.decimal.powershell +# ^ punctuation.section.group.end.powershell + "{0:00.0}" -f 4.12341234 -# ^ keyword.operator.string-format +# ^^^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^^ keyword.operator.string-format.powershell +# ^ punctuation.definition.keyword.powershell +# ^^^^^^^^^^ meta.number.float.decimal.powershell constant.numeric.value.powershell +# ^ punctuation.separator.decimal.powershell + "{0:##.#}" -f 4.12341234 -# ^ string.quoted.double -# ^ keyword.operator.string-format -# ^^^^^^^^^^ meta.number.float.decimal constant.numeric.value +# ^^^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^^ keyword.operator.string-format.powershell +# ^ punctuation.definition.keyword.powershell +# ^^^^^^^^^^ meta.number.float.decimal.powershell constant.numeric.value.powershell +# ^ punctuation.separator.decimal.powershell + "{0:#,#.#}" -f 1234.121234 -# ^ string.quoted.double -# ^ keyword.operator.string-format +# ^^^^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^^ keyword.operator.string-format.powershell +# ^ punctuation.definition.keyword.powershell +# ^^^^^^^^^^^ meta.number.float.decimal.powershell constant.numeric.value.powershell +# ^ punctuation.separator.decimal.powershell + "{0:##,,.000}" -f 1048576 -# ^ string.quoted.double -# ^ keyword.operator.string-format +# ^^^^^^^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^^ keyword.operator.string-format.powershell +# ^ punctuation.definition.keyword.powershell +# ^^^^^^^ meta.number.integer.decimal.powershell constant.numeric.value.powershell + "{this is not a #comment}" -# ^ - comment +# ^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell - comment +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell + "{0:##.#E000}" -f 2.71828 -# ^ string.quoted.double -# ^ keyword.operator.string-format +# ^^^^^^^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^^ keyword.operator.string-format.powershell +# ^ punctuation.definition.keyword.powershell +# ^^^^^^^ meta.number.float.decimal.powershell constant.numeric.value.powershell +# ^ punctuation.separator.decimal.powershell + "{0:#.00'##'}" -f 2.71828 -# ^ string.quoted.double -# ^ keyword.operator.string-format +# ^^^^^^^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^^ keyword.operator.string-format.powershell +# ^ punctuation.definition.keyword.powershell +# ^^^^^^^ meta.number.float.decimal.powershell constant.numeric.value.powershell +# ^ punctuation.separator.decimal.powershell + "{0:POS;NEG;ZERO}" -f -14 -# ^ string.quoted.double -# ^ keyword.operator.string-format +# ^^^^^^^^^^^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^^ keyword.operator.string-format.powershell +# ^ punctuation.definition.keyword.powershell +# ^ keyword.operator.unary.powershell +# ^^ meta.number.integer.decimal.powershell constant.numeric.value.powershell + "{0:$## Please}" -f 14 -# ^ string.quoted.double -# ^ keyword.operator.string-format +# ^^^^^^^^^^^^^^^^ meta.string.interpolated.powershell +# ^^^^ string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ meta.interpolation.powershell +# ^^^^^^^^^^^ string.quoted.double.powershell +# ^ punctuation.definition.string.end.powershell +# ^^ keyword.operator.string-format.powershell +# ^ punctuation.definition.keyword.powershell +# ^^ meta.number.integer.decimal.powershell constant.numeric.value.powershell + "{0,-8:P1}" -f 1.75 -# ^ string.quoted.double -# ^ keyword.operator.string-format +# ^^^^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^^ keyword.operator.string-format.powershell +# ^ punctuation.definition.keyword.powershell +# ^^^^ meta.number.float.decimal.powershell constant.numeric.value.powershell +# ^ punctuation.separator.decimal.powershell + "{0,10:N3}{1,10:N3}{2,10:N3}{3,10:N3}" -f 0.2, 0.3, 0.45, 0.91 -# ^ keyword.operator.string-format +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^^ keyword.operator.string-format.powershell +# ^ punctuation.definition.keyword.powershell +# ^^^ meta.number.float.decimal.powershell constant.numeric.value.powershell +# ^ punctuation.separator.decimal.powershell +# ^ punctuation.separator.sequence.powershell +# ^^^ meta.number.float.decimal.powershell constant.numeric.value.powershell +# ^ punctuation.separator.decimal.powershell +# ^ punctuation.separator.sequence.powershell +# ^^^^ meta.number.float.decimal.powershell constant.numeric.value.powershell +# ^ punctuation.separator.decimal.powershell +# ^ punctuation.separator.sequence.powershell +# ^^^^ meta.number.float.decimal.powershell constant.numeric.value.powershell +# ^ punctuation.separator.decimal.powershell + + # Single-quoted format string '{0:00000.000}' -f 7.125 -# ^ string.quoted.single -# ^ keyword.operator.string-format - -"Escaped chars: `", `n, `$, `b, `t, `e, `u{10ffff}, `"" -#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ string.quoted.double -# ^^ constant.character.escape -# ^^ constant.character.escape -# ^^ constant.character.escape -# ^^ constant.character.escape -# ^^ constant.character.escape -# ^^ constant.character.escape -# ^^^^^^^^^^ constant.character.escape -# ^^ constant.character.escape -'But here they''re not escape chars: `", `n, `$, `b, `"' -# ^^ constant.character.escape -# ^^^^^^^^^^^^^^^^^^^ - constant +# ^^^^^^^^^^^^^^^ meta.string.powershell string.quoted.single.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^^ keyword.operator.string-format.powershell +# ^ punctuation.definition.keyword.powershell +# ^^^^^ meta.number.float.decimal.powershell constant.numeric.value.powershell +# ^ punctuation.separator.decimal.powershell From 3c79c99030c19bbdff7980498324e04aedc1466c Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Fri, 5 Dec 2025 10:57:53 -0500 Subject: [PATCH 21/81] Test constants --- Tests/syntax_test_PowerShell.ps1 | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/Tests/syntax_test_PowerShell.ps1 b/Tests/syntax_test_PowerShell.ps1 index 8ed1bb43..6ae44605 100644 --- a/Tests/syntax_test_PowerShell.ps1 +++ b/Tests/syntax_test_PowerShell.ps1 @@ -103,6 +103,37 @@ throw "Do not run this file!" # ^ variable.parameter.option punctuation.definition.parameter # ^^^^^^^^^^^ variable.parameter.option + # Constants + $true +# ^^^^^ constant.language.boolean.true.powershell +# ^ punctuation.definition.variable.powershell + $True +# ^^^^^ constant.language.boolean.true.powershell +# ^ punctuation.definition.variable.powershell + $TRUE +# ^^^^^ constant.language.boolean.true.powershell +# ^ punctuation.definition.variable.powershell + + $false +# ^^^^^^ constant.language.boolean.false.powershell +# ^ punctuation.definition.variable.powershell + $False +# ^^^^^^ constant.language.boolean.false.powershell +# ^ punctuation.definition.variable.powershell + $FALSE +# ^^^^^^ constant.language.boolean.false.powershell +# ^ punctuation.definition.variable.powershell + + $null +# ^^^^^ constant.language.null.powershell +# ^ punctuation.definition.variable.powershell + $Null +# ^^^^^ constant.language.null.powershell +# ^ punctuation.definition.variable.powershell + $NULL +# ^^^^^ constant.language.null.powershell +# ^ punctuation.definition.variable.powershell + # Automatic variables $_, $$, $^, $? # <- punctuation.definition.variable From a1b56193af2cb8dd2ba42aa7f4015402a875e20e Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Fri, 5 Dec 2025 11:03:11 -0500 Subject: [PATCH 22/81] Call & a "background" operator --- PowerShell.sublime-syntax | 2 +- Tests/syntax_test_PowerShell.ps1 | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index 067cf704..90b18955 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -392,7 +392,7 @@ contexts: - match: ',' scope: punctuation.separator.sequence.powershell - match: '&' - scope: keyword.operator.other.powershell + scope: keyword.operator.background.powershell - match: \.\.(?=\-?\d|\(|\$) # This is very imprecise. Is there a syntax for 'must come after...'? scope: keyword.operator.range.powershell diff --git a/Tests/syntax_test_PowerShell.ps1 b/Tests/syntax_test_PowerShell.ps1 index 6ae44605..f6ad3a50 100644 --- a/Tests/syntax_test_PowerShell.ps1 +++ b/Tests/syntax_test_PowerShell.ps1 @@ -83,7 +83,7 @@ throw "Do not run this file!" # Stop parsing & tool.exe /arg1 'value' /arg2 $value --% /arg3 $value /arg4 "value" # Comment -# <- keyword.operator.other +# <- keyword.operator.background # ^^^^^^^^ variable.function # ^ punctuation.definition.parameter # ^^^^^ variable.parameter.option @@ -93,7 +93,7 @@ throw "Do not run this file!" # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ string.unquoted - constant - variable - comment & gnutool.exe -s 'short option' --long-option --very_long_option value +plus-option -#<- keyword.operator.other +#<- keyword.operator.background # ^^^^^^^^^^^ variable.function # ^ variable.parameter.option punctuation.definition.parameter # ^ variable.parameter.option @@ -803,7 +803,7 @@ ls *.ps1 -recurse # ^^^^^^^^^^ variable.parameter.option # ^^^^^^^ string.quoted.single & tool.exe -# <- keyword.operator.other +# <- keyword.operator.background # ^^^^^^^^ variable.function something.cmd #^^^^^^^^^^^^ variable.function From 3a05c4073e0c3b9803088f6ba35ae8c03b4b0425 Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Fri, 5 Dec 2025 11:03:24 -0500 Subject: [PATCH 23/81] Move ! to symbol operators --- PowerShell.sublime-syntax | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index 90b18955..875002b5 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -353,7 +353,7 @@ contexts: scope: keyword.operator.logical.powershell captures: 1: punctuation.definition.keyword.powershell - - match: \B(-)(?i:and|or|not|xor){{kebab_break}}|! # <-- note `!` + - match: \B(-)(?i:and|or|not|xor){{kebab_break}} scope: keyword.operator.logical.powershell captures: 1: punctuation.definition.keyword.powershell @@ -365,7 +365,10 @@ contexts: scope: keyword.operator.string-format.powershell captures: 1: punctuation.definition.keyword.powershell + # Symbol operators + - match: \! + scope: keyword.operator.logical.powershell - match: '[+/*%-]?=' scope: keyword.operator.assignment.powershell - match: (?:\+\+|--)(?![ \t]*\d|[[:alpha:]]) From 0ed644269bbd3457acfba35f236eb918c5a6987f Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Fri, 5 Dec 2025 11:31:56 -0500 Subject: [PATCH 24/81] Improve type scopes --- PowerShell.sublime-syntax | 35 ++++++--- Tests/syntax_test_PowerShell.ps1 | 125 ++++++++++++++++++++----------- 2 files changed, 105 insertions(+), 55 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index 875002b5..c8352e79 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -314,20 +314,35 @@ contexts: # Back to normal stuff - include: statements +###[ TYPES ]################################################################### + types: # TODO: push a maybe-static-members context - match: \[ scope: punctuation.section.brackets.begin.powershell - push: - - match: \](?=::) - scope: punctuation.section.brackets.end.powershell - set: static-members - - match: \] - scope: punctuation.section.brackets.end.powershell - pop: 1 - - match: (?!\d+|\.)[\p{L}\p{N}.]+ - scope: storage.type.powershell - - include: types + push: inside-type + + inside-type: + - meta_include_prototype: false + - match: \](?=::) + scope: punctuation.section.brackets.end.powershell + set: static-members + - match: \] + scope: punctuation.section.brackets.end.powershell + pop: 1 + - match: \p{L}[\p{L}\p{N}]+(\.) + scope: meta.generic-name.powershell + captures: + 1: punctuation.accessor.dot.powershell + - match: \b(?:void|null|object|bool|char|string|int(?:32|64)?|long|byte|float|double|decimal)\b + scope: storage.type.powershell + - match: (?!\d+|\.)[\p{L}\p{N}.]+ + scope: support.type.powershell + - include: types + - match: \, + scope: punctuation.separator.sequence.powershell + - match: \+ + scope: punctuation.accessor.plus.powershell ###[ OPERATORS ]############################################################### diff --git a/Tests/syntax_test_PowerShell.ps1 b/Tests/syntax_test_PowerShell.ps1 index f6ad3a50..989a584e 100644 --- a/Tests/syntax_test_PowerShell.ps1 +++ b/Tests/syntax_test_PowerShell.ps1 @@ -654,51 +654,86 @@ $a3[1..2] # ^^ constant.numeric.value # ^^ constant.numeric.suffix -# Types -[string] -# <- punctuation.section.brackets.begin -# ^ storage.type -# ^ punctuation.section.brackets.end -[string[]] -# <- punctuation.section.brackets.begin -# ^ storage.type -# ^ punctuation.section.brackets.begin -# ^^ punctuation.section.brackets.end -[int32] -# <- punctuation.section.brackets.begin -# ^^^^ storage.type -# ^ punctuation.section.brackets.end -[System.Collections.Generic.Dictionary[[System.String, mscorlib],[System.Management.Automation.ParameterMetadata,System.Management.Automation]]] -# <- punctuation.section.brackets.begin -# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ storage.type -# ^^ punctuation.section.brackets.begin -# ^^^^^^^^^^^^^ storage.type -# ^^^^^^^^ storage.type -# ^ punctuation.section.brackets.end -# ^ punctuation.section.brackets.begin -# ^^^^^^^^^^^^^^^^ storage.type -# ^^^ punctuation.section.brackets.end -[System.Array+SZArrayEnumerator] -# <- punctuation.section.brackets.begin -# ^^^^^^^^^^^ storage.type -# ^^^^^^^^^^^^^^^^^ storage.type -# ^ punctuation.section.brackets.end -[int]::MinValue -# <- punctuation.section.brackets.begin -# ^ storage.type -# ^ punctuation.section.brackets.end -# ^^ punctuation.accessor.double-colon -# ^^^^^^^^ variable.other.member -[System.DateTime]::Parse('2016/09/21') -# <- punctuation.section.brackets.begin -# ^^^^^^^^^^^^^^ storage.type -# ^ punctuation.section.brackets.end -# ^^ punctuation.accessor.double-colon -# ^^^^^ meta.function-call variable.function -# @@@@@ reference -# ^^^^^^^^^^^^^^ meta.function-call.arguments -# ^ punctuation.section.arguments.begin -# ^ punctuation.section.arguments.end + +###[ Types ]################################################################### + + [string] +# ^ punctuation.section.brackets.begin.powershell +# ^^^^^^ storage.type.powershell +# ^ punctuation.section.brackets.end.powershell + + [string[]] +# ^ punctuation.section.brackets.begin.powershell +# ^^^^^^ storage.type.powershell +# ^ punctuation.section.brackets.begin.powershell +# ^^ punctuation.section.brackets.end.powershell + + [int32] +# ^ punctuation.section.brackets.begin.powershell +# ^^^^^ storage.type.powershell +# ^ punctuation.section.brackets.end.powershell + + [System.Collections.Generic.Dictionary[[System.String, mscorlib],[System.Management.Automation.ParameterMetadata,System.Management.Automation]]] +# ^ punctuation.section.brackets.begin.powershell +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.generic-name.powershell +# ^ punctuation.accessor.dot.powershell +# ^ punctuation.accessor.dot.powershell +# ^ punctuation.accessor.dot.powershell +# ^^^^^^^^^^ support.type.powershell +# ^^ punctuation.section.brackets.begin.powershell +# ^^^^^^^ meta.generic-name.powershell +# ^ punctuation.accessor.dot.powershell +# ^^^^^^ support.type.powershell +# ^ punctuation.separator.sequence.powershell +# ^^^^^^^^ support.type.powershell +# ^ punctuation.section.brackets.end.powershell +# ^ punctuation.separator.sequence.powershell +# ^ punctuation.section.brackets.begin.powershell +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.generic-name.powershell +# ^ punctuation.accessor.dot.powershell +# ^ punctuation.accessor.dot.powershell +# ^ punctuation.accessor.dot.powershell +# ^^^^^^^^^^^^^^^^^ support.type.powershell +# ^ punctuation.separator.sequence.powershell +# ^^^^^^^^^^^^^^^^^^ meta.generic-name.powershell +# ^ punctuation.accessor.dot.powershell +# ^ punctuation.accessor.dot.powershell +# ^^^^^^^^^^ support.type.powershell +# ^^^ punctuation.section.brackets.end.powershell + + [System.Array+SZArrayEnumerator] +# ^ punctuation.section.brackets.begin.powershell +# ^^^^^^^ meta.generic-name.powershell +# ^ punctuation.accessor.dot.powershell +# ^^^^^ support.type.powershell +# ^ punctuation.accessor.plus.powershell +# ^^^^^^^^^^^^^^^^^ support.type.powershell +# ^ punctuation.section.brackets.end.powershell + + [int]::MinValue +# ^ punctuation.section.brackets.begin.powershell +# ^^^ storage.type.powershell +# ^ punctuation.section.brackets.end.powershell +# ^^ punctuation.accessor.double-colon.powershell +# ^^^^^^^^ variable.other.member.powershell + + [System.DateTime]::Parse('2016/09/21') +# ^ punctuation.section.brackets.begin.powershell +# ^^^^^^^ meta.generic-name.powershell +# ^ punctuation.accessor.dot.powershell +# ^^^^^^^^ support.type.powershell +# ^ punctuation.section.brackets.end.powershell +# ^^ punctuation.accessor.double-colon.powershell +# ^^^^^ meta.function-call.powershell variable.function.powershell +# ^^^^^^^^^^^^^^ meta.function-call.arguments.powershell +# ^ punctuation.section.arguments.begin.powershell +# ^^^^^^^^^^^^ meta.string.powershell string.quoted.single.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^ punctuation.section.arguments.end.powershell + + +###[ Commands ]################################################################ # Commands (functions) Invoke-Something -foobar From a2a771196528a2dcd74ba3d3e7526a096dbacc80 Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Fri, 5 Dec 2025 11:52:42 -0500 Subject: [PATCH 25/81] Refactor types --- PowerShell.sublime-syntax | 33 ++++++++++++------ Tests/syntax_test_Class.ps1 | 52 ++++++++++++++-------------- Tests/syntax_test_Function.ps1 | 39 ++++++++++++--------- Tests/syntax_test_PowerShell.ps1 | 59 +++++++++++++++++++++++++------- 4 files changed, 116 insertions(+), 67 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index c8352e79..b593a43c 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -238,11 +238,6 @@ contexts: - match: \b(?i:(?:foreach|where|sort|tee)-object)\b scope: support.function.powershell - static-members: - - match: '::' - scope: punctuation.accessor.double-colon.powershell - set: members - members: - match: (?=\.\.) pop: 1 @@ -317,16 +312,17 @@ contexts: ###[ TYPES ]################################################################### types: - # TODO: push a maybe-static-members context + - match: \[ + scope: punctuation.section.brackets.begin.powershell + push: [maybe-static-member, inside-type] + + types-without-members: - match: \[ scope: punctuation.section.brackets.begin.powershell push: inside-type inside-type: - meta_include_prototype: false - - match: \](?=::) - scope: punctuation.section.brackets.end.powershell - set: static-members - match: \] scope: punctuation.section.brackets.end.powershell pop: 1 @@ -334,16 +330,25 @@ contexts: scope: meta.generic-name.powershell captures: 1: punctuation.accessor.dot.powershell - - match: \b(?:void|null|object|bool|char|string|int(?:32|64)?|long|byte|float|double|decimal)\b + - match: '{{builtin_types}}' scope: storage.type.powershell - match: (?!\d+|\.)[\p{L}\p{N}.]+ scope: support.type.powershell - - include: types + - include: types-without-members - match: \, scope: punctuation.separator.sequence.powershell - match: \+ scope: punctuation.accessor.plus.powershell + static-members: + - match: '::' + scope: punctuation.accessor.double-colon.powershell + set: members + + maybe-static-member: + - include: static-members + - include: immediately-pop + ###[ OPERATORS ]############################################################### operators: @@ -925,3 +930,9 @@ variables: int_suffix: (?i:u[lsy]?|[lnsy]) unit_suffix: (?i:[kmgtp]b\b) kebab_break: (?![\w-]) + builtin_types: |- + \b(?x: + void | null | object | bool | char | string + | int (?:32|64)? | long | byte | float | double | decimal + | array | hashtable + )\b diff --git a/Tests/syntax_test_Class.ps1 b/Tests/syntax_test_Class.ps1 index fe41a23c..22904748 100644 --- a/Tests/syntax_test_Class.ps1 +++ b/Tests/syntax_test_Class.ps1 @@ -90,39 +90,37 @@ class TypeName # ^ variable.other.readwrite # ^ punctuation.section.group.end [TypeName]::P2 = $h - # <- punctuation.section.brackets.begin - # ^ storage.type - # ^ punctuation.section.brackets.end - # ^^ punctuation.accessor.double-colon - # ^^ variable.other.member - # ^ keyword.operator.assignment - # ^ punctuation.definition.variable - # ^ variable.other.readwrite +#^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.block.powershell meta.block.powershell +# ^ punctuation.section.brackets.begin.powershell +# ^^^^^^^^ support.type.powershell +# ^ punctuation.section.brackets.end.powershell +# ^^ punctuation.accessor.double-colon.powershell +# ^^ variable.other.member.powershell +# ^ keyword.operator.assignment.powershell +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell } # Instance method # <- punctuation.definition.comment # ^^^^^^^^^^^^^^^ comment.line [int] MemberMethod2([int] $i) { - # <- punctuation.section.brackets.begin - # ^ storage.type - # ^ punctuation.section.brackets.end - # ^^^^^^^^^^^^^ entity.name.function - # @@@@@@@@@@@@@ definition - # ^ punctuation.section.group.begin - # ^ punctuation.section.brackets.begin - # ^^^ storage.type - # ^ punctuation.section.brackets.end - # ^ punctuation.definition.variable - # ^ variable.other.readwrite - # ^ punctuation.section.group.end - $this.P3 = $i - # <- punctuation.definition.variable - # ^^^ variable.language - # ^^ variable.other.member - # ^ keyword.operator.assignment - # ^ punctuation.definition.variable - # ^ variable.other.readwrite +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.block.powershell +#^^^^^^^^^^^^^^^^^^^^^^ meta.function.powershell +# ^ punctuation.section.brackets.begin.powershell +# ^^^ storage.type.powershell +# ^ punctuation.section.brackets.end.powershell +# ^^^^^^^^^^^^^ entity.name.function.powershell +# @@@@@@@@@@@@@ definition +# ^^^^^^^^^^ meta.group.powershell +# ^ punctuation.section.group.begin.powershell +# ^ punctuation.section.brackets.begin.powershell +# ^^^ storage.type.powershell +# ^ punctuation.section.brackets.end.powershell +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^ punctuation.section.group.end.powershell +# ^ meta.block.powershell punctuation.section.braces.begin.powershell return $this.P3 # <- keyword.control # ^ punctuation.definition.variable diff --git a/Tests/syntax_test_Function.ps1 b/Tests/syntax_test_Function.ps1 index 220cd382..d8991122 100644 --- a/Tests/syntax_test_Function.ps1 +++ b/Tests/syntax_test_Function.ps1 @@ -93,14 +93,16 @@ function Verb-Noun { # ^ meta.attribute punctuation.section.group.end # ^ meta.attribute punctuation.section.brackets.end [OutputType([String])] - # <- meta.attribute punctuation.section.brackets.begin - # ^ meta.attribute support.function.attribute - # ^ meta.attribute punctuation.section.group.begin - # ^ meta.attribute punctuation.section.brackets.begin - # ^^^^^^ meta.attribute storage.type - # ^ meta.attribute punctuation.section.brackets.end - # ^ meta.attribute punctuation.section.group.end - # ^ meta.attribute punctuation.section.brackets.end +#^^^^^^^^^^^^^^^^^^^^^^^^^ meta.block.powershell +# ^^^^^^^^^^^^^^^^^^^^^^ meta.attribute.powershell +# ^ punctuation.section.brackets.begin.powershell +# ^^^^^^^^^^ support.function.attribute.powershell +# ^ punctuation.section.group.begin.powershell +# ^ punctuation.section.brackets.begin.powershell +# ^^^^^^ support.type.powershell +# ^ punctuation.section.brackets.end.powershell +# ^ punctuation.section.group.end.powershell +# ^ punctuation.section.brackets.end.powershell Param #^^^^^ keyword.declaration.parameter ( @@ -302,9 +304,10 @@ function Verb-Noun { # ^ meta.attribute punctuation.section.group.end # ^ meta.attribute punctuation.section.brackets.end [String] - # <- punctuation.section.brackets.begin - #^^^^^^ storage.type - # ^ punctuation.section.brackets.end +#^^^^^^^^^^^^^^^ meta.block.powershell meta.group.powershell +# ^ punctuation.section.brackets.begin.powershell +# ^^^^^^ support.type.powershell +# ^ punctuation.section.brackets.end.powershell $Param3, # <- punctuation.definition.variable #^^^^^^ variable.other.readwrite @@ -335,9 +338,10 @@ function Verb-Noun { # ^ meta.attribute punctuation.section.group.end # ^ meta.attribute punctuation.section.brackets.end [string] - # <- punctuation.section.brackets.begin - # ^ storage.type - # ^ punctuation.section.brackets.end +#^^^^^^^^^^^^^^^ meta.block.powershell meta.group.powershell +# ^ punctuation.section.brackets.begin.powershell +# ^^^^^^ storage.type.powershell +# ^ punctuation.section.brackets.end.powershell $Param4, # <- punctuation.definition.variable # ^ variable.other.readwrite @@ -365,9 +369,10 @@ function Verb-Noun { # ^ comment.line punctuation.definition.comment # ^ comment.line [string] - # <- punctuation.section.brackets.begin - # ^ storage.type - # ^ punctuation.section.brackets.end +#^^^^^^^^^^^^^^^ meta.block.powershell meta.group.powershell +# ^ punctuation.section.brackets.begin.powershell +# ^^^^^^ storage.type.powershell +# ^ punctuation.section.brackets.end.powershell $Param5 # <- punctuation.definition.variable # ^ variable.other.readwrite diff --git a/Tests/syntax_test_PowerShell.ps1 b/Tests/syntax_test_PowerShell.ps1 index 989a584e..ec7948a5 100644 --- a/Tests/syntax_test_PowerShell.ps1 +++ b/Tests/syntax_test_PowerShell.ps1 @@ -725,6 +725,7 @@ $a3[1..2] # ^ punctuation.section.brackets.end.powershell # ^^ punctuation.accessor.double-colon.powershell # ^^^^^ meta.function-call.powershell variable.function.powershell +# @@@@@ reference # ^^^^^^^^^^^^^^ meta.function-call.arguments.powershell # ^ punctuation.section.arguments.begin.powershell # ^^^^^^^^^^^^ meta.string.powershell string.quoted.single.powershell @@ -1359,14 +1360,26 @@ $a -ceq 4 -and $a -ine $d -or # ^^^^ keyword.operator.comparison # ^^^ keyword.operator.logical $c -is [Type] -# ^^^ keyword.operator.logical -# ^ storage.type +#^ variable.other.readwrite.powershell +# ^^^ keyword.operator.logical.powershell +# ^ punctuation.definition.keyword.powershell +# ^ punctuation.section.brackets.begin.powershell +# ^^^^ support.type.powershell +# ^ punctuation.section.brackets.end.powershell $c -isnot [Type] -# ^^^^^^ keyword.operator.logical -# ^ storage.type +#^ variable.other.readwrite.powershell +# ^^^^^^ keyword.operator.logical.powershell +# ^ punctuation.definition.keyword.powershell +# ^ punctuation.section.brackets.begin.powershell +# ^^^^ support.type.powershell +# ^ punctuation.section.brackets.end.powershell $c -as [Type] -# ^^^ keyword.operator.cast -# ^ storage.type +#^ variable.other.readwrite.powershell +# ^^^ keyword.operator.cast.powershell +# ^ punctuation.definition.keyword.powershell +# ^ punctuation.section.brackets.begin.powershell +# ^^^^ support.type.powershell +# ^ punctuation.section.brackets.end.powershell $k = $y -bor $k # ^ keyword.operator.assignment # ^ keyword.operator.bitwise @@ -1474,17 +1487,39 @@ echo `"test`" # ^ meta.group.array-expression # ^ keyword.control # ^ meta.block + function join-path {} # @@@@@@@@@ definition + $file = join-path $env:SystemDrive "$([System.io.path]::GetRandomFileName()).ps1" -# <- punctuation.definition.variable +#^^^^ variable.other.readwrite.powershell +# ^ keyword.operator.assignment.powershell +# ^^^^^^^^^ meta.function-call.powershell support.function.powershell # @@@@@@@@@ reference -# ^ support.function -# ^ support.variable.drive -# ^ variable.other.readwrite -# ^^ meta.string meta.interpolation punctuation.section.interpolation.begin -# ^ storage.type +# ^^^^^^^^^^^^^^^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^^^^ support.variable.drive.powershell +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string.interpolated.powershell +# ^ string.quoted.double.powershell punctuation.definition.string.begin.powershell +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.interpolation.powershell +# ^^ punctuation.section.interpolation.begin.powershell +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ source.powershell.embedded +# ^ punctuation.section.brackets.begin.powershell +# ^^^^^^^^^^ meta.generic-name.powershell +# ^ punctuation.accessor.dot.powershell +# ^ punctuation.accessor.dot.powershell +# ^^^^ support.type.powershell +# ^ punctuation.section.brackets.end.powershell +# ^^ punctuation.accessor.double-colon.powershell +# ^^^^^^^^^^^^^^^^^ meta.function-call.powershell variable.function.powershell # @@@@@@@@@@@@@@@@@ reference +# ^^ meta.function-call.arguments.powershell +# ^ punctuation.section.arguments.begin.powershell +# ^ punctuation.section.arguments.end.powershell +# ^ punctuation.section.interpolation.end.powershell +# ^^^^^ string.quoted.double.powershell +# ^ punctuation.definition.string.end.powershell + function out-file {} # @@@@@@@@ definition $ScriptBlock | Out-File $file -Force From ea64e6386904b43e7417c49692c367594938de82 Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Fri, 5 Dec 2025 12:18:38 -0500 Subject: [PATCH 26/81] Extract variable name lists --- PowerShell.sublime-syntax | 146 +++++++++++++------------------------- 1 file changed, 48 insertions(+), 98 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index b593a43c..be80c46e 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -461,66 +461,23 @@ contexts: ###[ VARIABLES ]############################################################### variables: - - match: |- - (?xi: - (\$) - (?: - ExecutionContext | Host | Home | IsCoreCLR | IsLinux | IsWindows - | IsMacOS | PID | Profile | PsCommandPath | PsHome | PsScriptRoot - | PsUiCulture | PsVersionTable | ShellID - ) - ) + - match: (\$){{var_constants}} scope: support.constant.variable.powershell captures: 1: punctuation.definition.variable.powershell push: members - - match: |- - (?xi: - (\$) - (?: - [$^?_] - | (?: - Args | ConsoleFileName | Error | Event | EventArgs - | EventSubscriber | ForEach | Input | LastExitCode | Matches - | MyInvocation | NestedPromptLevel | PsBoundParameters | PsCmdlet - | PsCulture | PsDebugContext | PsItem | Pwd | Sender | SourceArgs - | SourceEventArgs | StackTrace | Switch | This - )\b - ) - ) + - match: (\$){{var_language}} scope: variable.language.powershell captures: 1: punctuation.definition.variable.powershell push: members - - match: |- - (?xi: - (\$) - (?: - (?: - Confirm | Debug | ErrorAction | Information | Progress | Verbose # *Preference - | Warning | WhatIf - ) - Preference - | Maximum(?:Alias|Drive|Error|Function|History|Variable)Count # Maximum*Count - | Log(?:Command|Engine|Provider)(?:Health|Lifecycle)Event # Log*Event - | PsDebugContext | PsDefaultParameterValues | PsEmailServer - | PsModuleAutoloadingPreference | PsSenderInfo - | PsSessionApplicationName | PsSessionConfigurationName - | PsSessionOption | ErrorView | FormatEnumerationLimit | OFS - | OutputEncoding - ) - ) - scope: variable.language.powershell - captures: - 1: punctuation.definition.variable.powershell - push: members - - match: ((\$|@)(?i:(global|local|private|script|using|workflow):\w+)) + - match: ((\$|@)(?i:({{var_scope_mod}}):\w+)) captures: 1: variable.other.readwrite.powershell 2: punctuation.definition.variable.powershell 3: storage.modifier.scope.powershell push: members - - match: ((\$)(\{)((?i:global|local|private|script|using|workflow)):([^}]*[^}`])(\})) + - match: ((\$)(\{)({{var_scope_mod}}):([^}]*[^}`])(\})) captures: 1: variable.other.readwrite.powershell 2: punctuation.definition.variable.powershell @@ -545,62 +502,20 @@ contexts: push: members variables-without-property: - - match: |- - (?xi: - (\$) - (?: - ExecutionContext | Host | Home | IsCoreCLR | IsLinux | IsWindows - | IsMacOS | PID | Profile | PsCommandPath | PsHome | PsScriptRoot - | PsUiCulture | PsVersionTable | ShellID - ) - ) + - match: (\$){{var_constants}} scope: support.constant.variable.powershell captures: 1: punctuation.definition.variable.powershell - - match: |- - (?xi: - (\$) - (?: - [$^?_] - | (?: - Args | ConsoleFileName | Error | Event | EventArgs - | EventSubscriber | ForEach | Input | LastExitCode | Matches - | MyInvocation | NestedPromptLevel | PsBoundParameters | PsCmdlet - | PsCulture | PsDebugContext | PsItem | Pwd | Sender | SourceArgs - | SourceEventArgs | StackTrace | Switch | This - )\b - ) - ) - scope: variable.language.powershell - captures: - 1: punctuation.definition.variable.powershell - - match: |- - (?xi: - (\$) - (?: - (?: - Confirm | Debug | ErrorAction | Information | Progress | Verbose # *Preference - | Warning | WhatIf - ) - Preference - | Maximum(?:Alias|Drive|Error|Function|History|Variable)Count # Maximum*Count - | Log(?:Command|Engine|Provider)(?:Health|Lifecycle)Event # Log*Event - | PsDebugContext | PsDefaultParameterValues | PsEmailServer - | PsModuleAutoloadingPreference | PsSenderInfo - | PsSessionApplicationName | PsSessionConfigurationName - | PsSessionOption | ErrorView | FormatEnumerationLimit | OFS - | OutputEncoding - ) - ) + - match: (\$){{var_language}} scope: variable.language.powershell captures: 1: punctuation.definition.variable.powershell - - match: (?i:(\$|@)(global|local|private|script|using|workflow):(\w+)) + - match: (?i:(\$|@)({{var_scope_mod}}):(\w+)) captures: 1: punctuation.definition.variable.powershell 2: storage.modifier.scope.powershell 3: variable.other.readwrite.powershell - - match: (?i:(\$)(\{)(global|local|private|script|using|workflow):([^}]*[^}`])(\})) + - match: (?i:(\$)(\{)({{var_scope_mod}}):([^}]*[^}`])(\})) captures: 1: punctuation.definition.variable.powershell 2: punctuation.section.braces.begin @@ -924,11 +839,6 @@ contexts: ############################################################################### variables: - dec_exponent: (?:[eE][-+]?\d*) - dec_suffix: '[dD]' - float_suffix: '[dDlL]' - int_suffix: (?i:u[lsy]?|[lnsy]) - unit_suffix: (?i:[kmgtp]b\b) kebab_break: (?![\w-]) builtin_types: |- \b(?x: @@ -936,3 +846,43 @@ variables: | int (?:32|64)? | long | byte | float | double | decimal | array | hashtable )\b + + # Numbers + dec_exponent: (?:[eE][-+]?\d*) + dec_suffix: '[dD]' + float_suffix: '[dDlL]' + int_suffix: (?i:u[lsy]?|[lnsy]) + unit_suffix: (?i:[kmgtp]b\b) + + # Variables + var_constants: |- + \b(?xi: + (?: + ExecutionContext | Host | Home | IsCoreCLR | IsLinux | IsWindows + | IsMacOS | PID | Profile | PsCommandPath | PsHome | PsScriptRoot + | PsUiCulture | PsVersionTable | ShellID + ) + )\b + var_language: |- + (?xi: + [$^?_] + | \b(?: + Args | ConsoleFileName | Error | Event | EventArgs + | EventSubscriber | ForEach | Input | LastExitCode | Matches + | MyInvocation | NestedPromptLevel | PsBoundParameters | PsCmdlet + | PsCulture | PsDebugContext | PsItem | Pwd | Sender | SourceArgs + | SourceEventArgs | StackTrace | Switch | This + | (?: + Confirm | Debug | ErrorAction | Information | Progress # *Preference + | Verbose | Warning | WhatIf + ) Preference + | Maximum (?: Alias | Drive | Error | Function | History | Variable ) Count # Maximum*Count + | Log (?: Command | Engine | Provider ) (?: Health | Lifecycle ) Event # Log*Event + | PsDebugContext | PsDefaultParameterValues | PsEmailServer + | PsModuleAutoloadingPreference | PsSenderInfo + | PsSessionApplicationName | PsSessionConfigurationName + | PsSessionOption | ErrorView | FormatEnumerationLimit | OFS + | OutputEncoding + )\b + ) + var_scope_mod: (?i:global|local|private|script|using|workflow) From 76c79efc995d3637d526ebf10383050e3e2ac89a Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Fri, 5 Dec 2025 12:21:09 -0500 Subject: [PATCH 27/81] Move the members context --- PowerShell.sublime-syntax | 55 +++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index be80c46e..5f2fb692 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -238,34 +238,6 @@ contexts: - match: \b(?i:(?:foreach|where|sort|tee)-object)\b scope: support.function.powershell - members: - - match: (?=\.\.) - pop: 1 - - match: \.(?=\w) - scope: punctuation.accessor.dot.powershell - - match: (\w+)(\() - captures: - 1: meta.function-call.powershell variable.function.powershell - 2: meta.function-call.arguments.powershell punctuation.section.arguments.begin.powershell - push: - - meta_content_scope: meta.function-call.arguments.powershell - - match: \) - scope: meta.function-call.arguments.powershell punctuation.section.arguments.end.powershell - pop: 1 - - include: expressions - - match: \w+ - scope: variable.other.member.powershell - - match: \[ - scope: punctuation.section.brackets.begin.powershell - push: - - meta_scope: meta.brackets.indexer.powershell - - match: \] - scope: punctuation.section.brackets.end.powershell - pop: 1 - - include: expressions - - match: '' - pop: 1 - functions: - match: ^(?:\s*)(?i)(function|filter|configuration|workflow)\s+(?:(global|local|script|private):)?((?:\p{L}|\d|_|-|\.)+) scope: meta.function.powershell @@ -535,6 +507,33 @@ contexts: 4: variable.other.readwrite.powershell 5: punctuation.section.braces.end + members: + - match: (?=\.\.) + pop: 1 + - match: \.(?=\w) + scope: punctuation.accessor.dot.powershell + - match: (\w+)(\() + captures: + 1: meta.function-call.powershell variable.function.powershell + 2: meta.function-call.arguments.powershell punctuation.section.arguments.begin.powershell + push: + - meta_content_scope: meta.function-call.arguments.powershell + - match: \) + scope: meta.function-call.arguments.powershell punctuation.section.arguments.end.powershell + pop: 1 + - include: expressions + - match: \w+ + scope: variable.other.member.powershell + - match: \[ + scope: punctuation.section.brackets.begin.powershell + push: + - meta_scope: meta.brackets.indexer.powershell + - match: \] + scope: punctuation.section.brackets.end.powershell + pop: 1 + - include: expressions + - include: immediately-pop + ###[ GROUPS ]################################################################## groups: From cb44dd9a85e92cb94c41390d042847523897d806 Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Fri, 5 Dec 2025 12:44:24 -0500 Subject: [PATCH 28/81] Extract approved verbs to a variable --- PowerShell.sublime-syntax | 47 +++++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index 5f2fb692..4f162439 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -210,26 +210,11 @@ contexts: - include: expressions commands: - # "Verb-Noun pattern:" + # The "Verb-Noun" pattern - match: |- (?x: (?:[\w\\:-]*\\)? # Path stuff - \b(?i: - Add | Approve | Assert | Backup | Block | Build | Checkpoint # "Official" Verbs - | 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 - ) + {{command_verbs}} # Approved verbs \-\w+? # Any "noun" (?:\.(?i:exe|cmd|bat|ps1))?\b # More path stuff ) @@ -885,3 +870,31 @@ variables: )\b ) var_scope_mod: (?i:global|local|private|script|using|workflow) + + # The "Approved Verbs" list + # https://learn.microsoft.com/en-us/powershell/scripting/developer/cmdlet/approved-verbs-for-windows-powershell-commands + command_verbs: |- + \b(?xi: + # Common verbs + Add | Clear | Close | Copy | Enter | Exit | Find | Format | Get | Hide + | Join | Lock | Move | New | Open | Optimize | Pop | Push | Redo | Remove + | Rename | Reset | Resize | Search | Select | Set | Show | Skip | Split + | Step | Switch | Undo | Unlock | Watch + # Communications verbs + | Connect | Disconnect | Read | Receive | Send | Write + # Data verbs + | Backup | Checkpoint | Compare | Compress | Convert | ConvertFrom + | ConvertTo | Dismount | Edit | Expand | Export | Group | Import + | Initialize | Limit | Merge | Mount | Out | Publish | Restore | Save + | Sync | Unpublish | Update + # Diagnostic verbs + | Debug | Measure | Ping | Repair | Resolve | Test | Trace + # Lifecycle verbs + | Approve | Assert | Build | Complete | Confirm | Deny | Deploy | Disable + | Enable | Install | Invoke | Register | Request | Restart | Resume | Start + | Stop | Submit | Suspend | Uninstall | Unregister | Wait + # Security verbs + | Block | Grant | Protect | Revoke | Unblock | Unprotect + # Other verbs + | Use + )\b From 22907c4340d9cda64111538bf2d153b2565b29a0 Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Fri, 5 Dec 2025 13:03:10 -0500 Subject: [PATCH 29/81] Sort function contexts --- PowerShell.sublime-syntax | 135 ++++++++++++++++++++------------------ 1 file changed, 70 insertions(+), 65 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index 4f162439..c836405e 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -80,8 +80,6 @@ contexts: # Declarations - match: \b(?i:var){{kebab_break}} scope: keyword.declaration.variable.powershell - - match: \b(?i:(?:dynamic)?param){{kebab_break}} - scope: keyword.declaration.parameter.powershell # This scope is not standard expressions: - include: regions @@ -167,48 +165,6 @@ contexts: 3: keyword.other.region.end.powershell 4: meta.fold.end.powershell - attributes: - - match: |- - (?xi: - (\[)\s* - ( - CmdletBinding | Alias | OutputType | Parameter - | Validate - (?: - Count | NotNull(?:OrEmpty)? | Range | Pattern | Length | Set - | Script) - | Allow(?: Null | Empty(?: Collection | String )) - )\b - ) - captures: - 1: punctuation.section.brackets.begin.powershell - 2: support.function.attribute.powershell - push: - - meta_scope: meta.attribute.powershell - - match: \] - scope: punctuation.section.brackets.end.powershell - pop: 1 - - match: \( - scope: punctuation.section.group.begin.powershell - push: - - match: \) - scope: punctuation.section.group.end.powershell - pop: 1 - - match: |- - (?xi: - \b( - Mandatory | ValueFromPipeline(?:ByPropertyName)? - | ValueFromRemainingArguments | Position(?:alBinding)? - | (?:Default)?ParameterSetName | SupportsShouldProcess | SupportsPaging - | HelpUri | ConfirmImpact | HelpMessage - )\b - \s*(=)? - ) - captures: - 1: variable.parameter.attribute.powershell - 2: keyword.operator.assignment.powershell - - include: expressions - commands: # The "Verb-Noun" pattern - match: |- @@ -223,18 +179,6 @@ contexts: - match: \b(?i:(?:foreach|where|sort|tee)-object)\b scope: support.function.powershell - functions: - - match: ^(?:\s*)(?i)(function|filter|configuration|workflow)\s+(?:(global|local|script|private):)?((?:\p{L}|\d|_|-|\.)+) - scope: meta.function.powershell - captures: - 1: storage.type.powershell - 2: storage.modifier.scope.powershell - 3: entity.name.function.powershell - push: - - match: (?=\{|\() - pop: 1 - - include: comment-line - script-blocks: - match: (%)?(\{) captures: @@ -252,20 +196,65 @@ contexts: scope: storage.modifier.powershell # TODO: Fix functions, so these don't nest here. + - include: function-sections - include: attributes - # Begin/Process/End/Clean - - match: \b(?i:begin){{kebab_break}} - scope: keyword.context.block.begin.powershell - - match: \b(?i:process){{kebab_break}} - scope: keyword.context.block.process.powershell - - match: \b(?i:end){{kebab_break}} - scope: keyword.context.block.end.powershell - - match: \b(?i:clean){{kebab_break}} - scope: keyword.context.block.clean.powershell # Back to normal stuff - include: statements +###[ FUNCTIONS ]############################################################### + + functions: + - match: ^(?:\s*)(?i)(function|filter|configuration|workflow)\s+(?:(global|local|script|private):)?((?:\p{L}|\d|_|-|\.)+) + scope: meta.function.powershell + captures: + 1: storage.type.powershell + 2: storage.modifier.scope.powershell + 3: entity.name.function.powershell + push: + - match: (?=\{|\() + pop: 1 + - include: comment-line + + function-sections: + - match: \b(?i:(?:dynamic)?param){{kebab_break}} + scope: keyword.declaration.parameter.powershell # This scope is not standard + # Begin/Process/End/Clean + - match: \b(?i:begin){{kebab_break}} + scope: keyword.context.block.begin.powershell + - match: \b(?i:process){{kebab_break}} + scope: keyword.context.block.process.powershell + - match: \b(?i:end){{kebab_break}} + scope: keyword.context.block.end.powershell + - match: \b(?i:clean){{kebab_break}} + scope: keyword.context.block.clean.powershell + + attributes: + - match: (\[)\s*({{attributes}}) + captures: + 1: punctuation.section.brackets.begin.powershell + 2: support.function.attribute.powershell + push: inside-attribute + + inside-attribute: + - meta_scope: meta.attribute.powershell + - match: \] + scope: punctuation.section.brackets.end.powershell + pop: 1 + - match: \( + scope: punctuation.section.group.begin.powershell + push: inside-attribute-parameters + + inside-attribute-parameters: + - match: \) + scope: punctuation.section.group.end.powershell + pop: 1 + - match: ({{attribute_parameters}})\s*(=)? + captures: + 1: variable.parameter.attribute.powershell + 2: keyword.operator.assignment.powershell + - include: expressions + ###[ TYPES ]################################################################### types: @@ -831,6 +820,22 @@ variables: | array | hashtable )\b + # Attributes + attributes: |- + \b(?xi: + CmdletBinding | Alias | OutputType | Parameter + | Validate + (?: Count | NotNull (?:OrEmpty)? | Range | Pattern | Length | Set | Script) + | Allow (?: Null | Empty (?: Collection | String )) + )\b + attribute_parameters: |- + \b(?xi: + Mandatory | ValueFromPipeline (?:ByPropertyName)? + | ValueFromRemainingArguments | Position(?:alBinding)? + | (?:Default)? ParameterSetName | SupportsShouldProcess | SupportsPaging + | HelpUri | ConfirmImpact | HelpMessage + )\b + # Numbers dec_exponent: (?:[eE][-+]?\d*) dec_suffix: '[dD]' From a1423b1ac77c2e21fd36d1fd28a14a607fdc6974 Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Fri, 5 Dec 2025 13:48:30 -0500 Subject: [PATCH 30/81] Add a dedicated using context and don't return to it when you leave. Also, make a context for shebang. Fixes #198 --- PowerShell.sublime-syntax | 70 +++++++++++++++++++++++++++----- Tests/syntax_test_Class.ps1 | 8 ++-- Tests/syntax_test_Function.ps1 | 8 ++-- Tests/syntax_test_PowerShell.ps1 | 9 ++-- 4 files changed, 75 insertions(+), 20 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index c836405e..c33581d5 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -12,7 +12,7 @@ file_extensions: first_line_match: |- (?x: - ^\#!.*\b(?:pwsh|powershell)\b + ^\#!.*{{shebang_language}} | ^\# \s* -\*- [^*]* mode: \s* powershell [^*]* -\*- ) @@ -21,7 +21,28 @@ contexts: - include: comments main: - - include: statements + - meta_include_prototype: false + - match: '' + push: [statements, imports, shebang] + + shebang: + - meta_include_prototype: false + - match: ^\s*(\#!) + captures: + 1: punctuation.definition.comment.powershell + set: shebang-body + - include: else-pop + + shebang-body: + - meta_include_prototype: false + - meta_scope: comment.line.shebang.powershell + - match: '{{shebang_language}}' + scope: constant.language.shebang.powershell + - include: pop-eol + + imports: + - include: using-directives + - include: else-pop statements: - include: redirection @@ -88,7 +109,6 @@ contexts: - include: commands - include: constants - include: variables - - include: using-directives - include: types - include: hashtables - include: strings @@ -127,13 +147,6 @@ contexts: captures: 1: punctuation.definition.parameter.powershell - using-directives: - - match: \b(?i:(using))\s+(?i:(namespace|module))\s+(?i:((?:\w+(?:\.)?)+)) - captures: - 1: keyword.control.using.powershell - 2: keyword.other.powershell - 3: variable.parameter.powershell - requires-directives: - match: (#)((?i:requires))\s captures: @@ -202,6 +215,40 @@ contexts: # Back to normal stuff - include: statements +###[ USINGS ]################################################################## + + using-directives: + - match: \b(?i)using(?=\s) + scope: keyword.control.import.powershell + push: inside-using + + inside-using: + - match: \bnamespace(?=\s) + scope: keyword.control.import.powershell + set: inside-using-namespace + - match: \bmodule(?=\s) + scope: keyword.control.import.powershell + set: inside-using-module + - include: else-pop + + inside-using-namespace: + - include: pop-eol + - match: \p{L}[\p{L}\p{N}]+(\.) + scope: meta.path.powershell + captures: + 1: punctuation.accessor.dot.powershell + - match: \p{L}[\p{L}\p{N}]+ + scope: meta.path.powershell + + inside-using-module: + - include: pop-eol + - match: \p{L}[\p{L}\p{N}]+(\.) + scope: meta.path.powershell + captures: + 1: punctuation.accessor.dot.powershell + - match: \p{L}[\p{L}\p{N}]+ + scope: meta.path.powershell support.type.powershell + ###[ FUNCTIONS ]############################################################### functions: @@ -278,7 +325,7 @@ contexts: 1: punctuation.accessor.dot.powershell - match: '{{builtin_types}}' scope: storage.type.powershell - - match: (?!\d+|\.)[\p{L}\p{N}.]+ + - match: \p{L}[\p{L}\p{N}]+ scope: support.type.powershell - include: types-without-members - match: \, @@ -819,6 +866,7 @@ variables: | int (?:32|64)? | long | byte | float | double | decimal | array | hashtable )\b + shebang_language: \b(?:pwsh|powershell)\b # Attributes attributes: |- diff --git a/Tests/syntax_test_Class.ps1 b/Tests/syntax_test_Class.ps1 index 22904748..8e94d1d9 100644 --- a/Tests/syntax_test_Class.ps1 +++ b/Tests/syntax_test_Class.ps1 @@ -1,8 +1,10 @@ # SYNTAX TEST "Packages/PowerShell/PowerShell.sublime-syntax" using namespace system.management.automation -# <- keyword.control.using -# ^^^^^^^^^ keyword.other -# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ variable.parameter +#^^^^ keyword.control.import.powershell +# ^^^^^^^^^ keyword.control.import.powershell +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.path.powershell +# ^ punctuation.accessor.dot.powershell +# ^ punctuation.accessor.dot.powershell # Define a class class TypeName diff --git a/Tests/syntax_test_Function.ps1 b/Tests/syntax_test_Function.ps1 index d8991122..747e13a8 100644 --- a/Tests/syntax_test_Function.ps1 +++ b/Tests/syntax_test_Function.ps1 @@ -1,9 +1,11 @@ # SYNTAX TEST "Packages/PowerShell/PowerShell.sublime-syntax" using module Microsoft.Management -# <- keyword.control.using -# ^ keyword.other -# ^ variable.parameter +#^^^^ keyword.control.import.powershell +# ^^^^^^ keyword.control.import.powershell +# ^^^^^^^^^^^^^^^^^^^^ meta.path.powershell +# ^ punctuation.accessor.dot.powershell +# ^^^^^^^^^^ support.type.powershell function Test-Path {} # @@@@@@@@@ definition diff --git a/Tests/syntax_test_PowerShell.ps1 b/Tests/syntax_test_PowerShell.ps1 index ec7948a5..78b31d89 100644 --- a/Tests/syntax_test_PowerShell.ps1 +++ b/Tests/syntax_test_PowerShell.ps1 @@ -1,8 +1,11 @@ # SYNTAX TEST "Packages/PowerShell/PowerShell.sublime-syntax" using namespace System.Management.Automation -# <- keyword.control.using -# ^ keyword.other -# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ variable.parameter +#^^^^ keyword.control.import.powershell +# ^^^^^^^^^ keyword.control.import.powershell +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.path.powershell +# ^ punctuation.accessor.dot.powershell +# ^ punctuation.accessor.dot.powershell + #Requires -PSSnapin DiskSnapin -Version 1.2 # <- punctuation.definition.keyword #^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.requires From c35c6f0cdcf7f970c8ac64e7db005433bdf023a4 Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Fri, 5 Dec 2025 13:57:37 -0500 Subject: [PATCH 31/81] Delete TODO for Atom --- Tests/syntax_test_PowerShell.ps1 | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Tests/syntax_test_PowerShell.ps1 b/Tests/syntax_test_PowerShell.ps1 index 78b31d89..77223232 100644 --- a/Tests/syntax_test_PowerShell.ps1 +++ b/Tests/syntax_test_PowerShell.ps1 @@ -217,8 +217,12 @@ $properties = @{ # ^ meta.hashtable meta.hashtable.assignment keyword.operator.assignment # ^ meta.hashtable string.quoted.single Something = $else - # <- meta.hashtable meta.hashtable.assignment variable.other.readwrite - # Atom-grammar-test is not tokenizing this correctly... Need to test in Atom - TODO +#^^^^^^^^^^^^^^^^^^^^ meta.hashtable.powershell +# ^^^^^^^^^^^^ meta.hashtable.assignment.powershell +# ^^^^^^^^^ variable.other.readwrite.powershell +# ^ keyword.operator.assignment.powershell +# ^^^^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell Number = 16 # <- meta.hashtable meta.hashtable.assignment variable.other.readwrite # ^ meta.hashtable meta.hashtable.assignment keyword.operator.assignment From 46cfcfd289d8b439d8d0529470e1b2b099629ddb Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Fri, 5 Dec 2025 14:09:37 -0500 Subject: [PATCH 32/81] Group commands contexts --- PowerShell.sublime-syntax | 44 ++++++++++++++++++++------------ Tests/syntax_test_PowerShell.ps1 | 13 ++++++---- 2 files changed, 35 insertions(+), 22 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index c33581d5..f3d78c59 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -50,7 +50,6 @@ contexts: - include: expressions - include: functions - # TODO: Continue into a command statement - match: \B\.(?= ) scope: support.function.source.powershell @@ -118,8 +117,6 @@ contexts: - include: groups - include: arrays - include: subexpressions - - match: \b[\w.-]+\.(?i:exe|com|cmd|bat)\b - scope: variable.function.powershell # Consume a string with a trailing dot # to prevent members with particular names from being recognized as keywords. @@ -178,20 +175,6 @@ contexts: 3: keyword.other.region.end.powershell 4: meta.fold.end.powershell - commands: - # The "Verb-Noun" pattern - - match: |- - (?x: - (?:[\w\\:-]*\\)? # Path stuff - {{command_verbs}} # Approved verbs - \-\w+? # Any "noun" - (?:\.(?i:exe|cmd|bat|ps1))?\b # More path stuff - ) - scope: meta.function-call.powershell support.function.powershell - # Builtin cmdlets with reserved verbs - - match: \b(?i:(?:foreach|where|sort|tee)-object)\b - scope: support.function.powershell - script-blocks: - match: (%)?(\{) captures: @@ -215,6 +198,33 @@ contexts: # Back to normal stuff - include: statements +###[ COMMANDS ]################################################################ + + commands: + - include: commands-verb-noun + - include: commands-reserved + - include: script-invocation + + commands-verb-noun: + # The "Verb-Noun" pattern + - match: |- + (?x: + (?:[.\w\\/:-]*[\\/])? # Path stuff + {{command_verbs}} # Approved verbs + \-\w+? # Any "noun" + (?:\.(?i:exe|cmd|bat|ps1))?\b # More path stuff + ) + scope: meta.function-call.powershell support.function.powershell + + commands-reserved: + # Builtin cmdlets with reserved verbs + - match: \b(?i:(?:foreach|where|sort|tee)-object)\b + scope: support.function.powershell + + script-invocation: + - match: \b[\w.\\/-]+\.(?i:exe|com|cmd|bat|ps1)\b + scope: variable.function.powershell + ###[ USINGS ]################################################################## using-directives: diff --git a/Tests/syntax_test_PowerShell.ps1 b/Tests/syntax_test_PowerShell.ps1 index 77223232..4403147a 100644 --- a/Tests/syntax_test_PowerShell.ps1 +++ b/Tests/syntax_test_PowerShell.ps1 @@ -840,11 +840,14 @@ ls *.ps1 -recurse # ^^^^^^^^ variable.parameter.option # Commands (executable files) -. .\scripts\myscript.ps1 -parameter 'value' -# <- support.function.source.powershell -# ^ punctuation.definition.parameter -# ^^^^^^^^^^ variable.parameter.option -# ^^^^^^^ string.quoted.single +. .\scripts\Test-Foo.ps1 -parameter 'value' +# ^^^^^^^^^^^^^^^^^^^^^^ meta.function-call.powershell support.function.powershell +# @@@@@@@@@@@@@@@@@@@@@@ reference +# ^^^^^^^^^^ variable.parameter.option.powershell +# ^ punctuation.definition.parameter.powershell +# ^^^^^^^ meta.string.powershell string.quoted.single.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell & tool.exe # <- keyword.operator.background # ^^^^^^^^ variable.function From d20ddfc34d14382f7eab82596171b8a3063fc198 Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Fri, 5 Dec 2025 14:31:19 -0500 Subject: [PATCH 33/81] Add supplemental scopes to some documentation --- PowerShell.sublime-syntax | 40 +++++++++++++++++++++------------- Tests/syntax_test_Function.ps1 | 17 +++++++++++++++ 2 files changed, 42 insertions(+), 15 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index f3d78c59..2c767847 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -806,33 +806,30 @@ contexts: - include: comment-embedded-docs comment-embedded-docs: - # TODO # https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_comment_based_help - - match: |- - (?xi: - ^\s*(\.) - ( - Component | Description | Example | ExternalHelp | ForwardHelpCategory | ForwardHelpTargetName - | Functionality | Inputs | Link | Notes | Outputs | Parameter | RemoteHelpRunSpace - | Role | Synopsis - ) - ) - scope: comment.documentation.embedded.powershell - captures: - 1: punctuation.definition.keyword.documentation.powershell - 2: keyword.other.documentation.powershell - match: ^\s*(\.)(?i:(Parameter)\s+([a-z0-9-_]+)) scope: comment.documentation.embedded.powershell captures: 1: punctuation.definition.keyword.documentation.powershell 2: keyword.other.documentation.param.powershell 3: variable.parameter.powershell - - match: ^\s*(\.)(?i:(ForwardHelpTargetName|ForwardHelpCategory|ExternalHelp|Link)\s+([a-z0-9-_]+)) + - match: ^\s*(\.)(?i:(ForwardHelpTargetName|ExternalHelp|Link)\s+([a-z0-9-_:/.&]+)) scope: comment.documentation.embedded.powershell captures: 1: punctuation.definition.keyword.documentation.powershell 2: keyword.other.documentation.powershell 3: markup.underline.link.powershell + - match: ^\s*(\.)(?i:(ForwardHelpCategory)\s+({{doc_fwdhelp_cat}})) + scope: comment.documentation.embedded.powershell + captures: + 1: punctuation.definition.keyword.documentation.powershell + 2: keyword.other.documentation.powershell + 3: support.type.powershell + - match: ^\s*(\.)({{doc}}) + scope: comment.documentation.embedded.powershell + captures: + 1: punctuation.definition.keyword.documentation.powershell + 2: keyword.other.documentation.powershell comment-line: - match: '#(?!(?i:requires|(?:end)?region)\b)' @@ -961,3 +958,16 @@ variables: # Other verbs | Use )\b + + # Documentation + doc: |- + (?xi: + Component | Description | Example | ExternalHelp | ForwardHelpCategory + | ForwardHelpTargetName | Functionality | Inputs | Link | Notes | Outputs + | Parameter | RemoteHelpRunSpace | Role | Synopsis + ) + doc_fwdhelp_cat: |- + (?x: + Alias | Cmdlet | HelpFile | Function | Provider | General | FAQ + | Glossary | ScriptCommand | ExternalScript | Filter | All + ) diff --git a/Tests/syntax_test_Function.ps1 b/Tests/syntax_test_Function.ps1 index 747e13a8..ba922156 100644 --- a/Tests/syntax_test_Function.ps1 +++ b/Tests/syntax_test_Function.ps1 @@ -51,6 +51,23 @@ function Test-Path {} # <- punctuation.definition.keyword # ^ keyword.other.documentation The functionality that best describes this cmdlet + .ForwardHelpCategory Alias +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ comment.block.powershell comment.documentation.embedded.powershell +# ^ punctuation.definition.keyword.documentation.powershell +# ^^^^^^^^^^^^^^^^^^^ keyword.other.documentation.powershell +# ^^^^^ support.type.powershell + + .parameter foo +#^^^^^^^^^^^^^^^^^ comment.block.powershell comment.documentation.embedded.powershell +# ^ punctuation.definition.keyword.documentation.powershell +# ^^^^^^^^^ keyword.other.documentation.param.powershell +# ^^^ variable.parameter.powershell + + .LINK https://example.com +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^ comment.block.powershell comment.documentation.embedded.powershell +# ^ punctuation.definition.keyword.documentation.powershell +# ^^^^ keyword.other.documentation.powershell +# ^^^^^^^^^^^^^^^^^^^ markup.underline.link.powershell This should not be considered documentaton -> .role # ^ - keyword.operator.documentation From 624178650b33bc4da5464de138fb99192a8aa5d1 Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Fri, 5 Dec 2025 15:00:00 -0500 Subject: [PATCH 34/81] Embed C# in Add-Type strings Fixes #201 --- PowerShell.sublime-syntax | 31 ++++++++++++++++++++++++++++++- Tests/syntax_test_Add-Type.ps1 | 24 ++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 Tests/syntax_test_Add-Type.ps1 diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index 2c767847..28e01506 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -137,7 +137,9 @@ contexts: - include: pop-before-eol - include: operators + - include: parameters + parameters: # Flags/Options/Parameters - match: \B(--?|[/+])\p{L}(?:[\w-]*\w)? scope: variable.parameter.option.powershell @@ -201,6 +203,7 @@ contexts: ###[ COMMANDS ]################################################################ commands: + - include: commands-add-type - include: commands-verb-noun - include: commands-reserved - include: script-invocation @@ -218,13 +221,39 @@ contexts: commands-reserved: # Builtin cmdlets with reserved verbs - - match: \b(?i:(?:foreach|where|sort|tee)-object)\b + - match: \b(?i:(?:ForEach|Where|Sort|Tee)-Object)\b scope: support.function.powershell script-invocation: - match: \b[\w.\\/-]+\.(?i:exe|com|cmd|bat|ps1)\b scope: variable.function.powershell + commands-add-type: + - match: \b(?i:Add-Type)\b + scope: support.function.powershell + push: inside-add-type + + inside-add-type: + - include: pop-eol + + - match: '@"' + scope: meta.string.interpolated.powershell string.quoted.double.powershell punctuation.definition.string.begin.powershell + embed: scope:source.cs + embed_scope: meta.string.interpolated.powershell string.quoted.double.powershell source.cs.embedded + escape: ("@) + escape_captures: + 1: meta.string.powershell string.quoted.double.powershell punctuation.definition.string.end.powershell + + - match: "@'" + scope: meta.string.powershell string.quoted.single.powershell punctuation.definition.string.begin.powershell + embed: scope:source.cs + embed_scope: meta.string.powershell string.quoted.single.powershell source.cs.embedded + escape: ('@) + escape_captures: + 1: meta.string.powershell string.quoted.single.powershell punctuation.definition.string.end.powershell + + - include: expressions + ###[ USINGS ]################################################################## using-directives: diff --git a/Tests/syntax_test_Add-Type.ps1 b/Tests/syntax_test_Add-Type.ps1 new file mode 100644 index 00000000..0107efb2 --- /dev/null +++ b/Tests/syntax_test_Add-Type.ps1 @@ -0,0 +1,24 @@ +# SYNTAX TEST "Packages/PowerShell/PowerShell.sublime-syntax" + + + Add-Type -Language CSharp @" +# ^^^^^^^^ support.function.powershell +# ^^^^^^^^^ variable.parameter.option.powershell +# ^ punctuation.definition.parameter.powershell +# ^^ meta.string.interpolated.powershell string.quoted.double.powershell punctuation.definition.string.begin.powershell + using System; +#^^^^^^^^^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell source.cs.embedded +# ^^^^^ keyword.control.import.cs +# ^^^^^^ meta.path.cs + using System.Runtime.InteropServices; + public class ClassGetForegroundWindow { +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell source.cs.embedded +# ^^^^^^ storage.modifier.access.cs +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.class.cs +# ^^^^^^^^^^^^^^^^^^^^^^^^ entity.name.class.cs +# ^ meta.class.body.cs meta.block.cs punctuation.section.block.begin.cs + [DllImport("user32.dll")] + public static extern IntPtr GetForegroundWindow(); + } +"@ +#^ meta.string.powershell string.quoted.double.powershell punctuation.definition.string.end.powershell - source.cs From 23ec46be5bd5e5f4703fa096f442e543364b31d2 Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Fri, 5 Dec 2025 17:30:22 -0500 Subject: [PATCH 35/81] Add context-sensitive functions --- PowerShell.sublime-syntax | 107 ++++++++++++---- Tests/syntax_test_Function.ps1 | 93 ++++++++------ Tests/syntax_test_PowerShell.ps1 | 211 +++++++++++++++++-------------- 3 files changed, 255 insertions(+), 156 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index 28e01506..f331ed40 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -192,9 +192,6 @@ contexts: - include: class-methods - match: \b(?i:hidden|static)\b scope: storage.modifier.powershell - - # TODO: Fix functions, so these don't nest here. - - include: function-sections - include: attributes # Back to normal stuff @@ -291,29 +288,86 @@ contexts: ###[ FUNCTIONS ]############################################################### functions: - - match: ^(?:\s*)(?i)(function|filter|configuration|workflow)\s+(?:(global|local|script|private):)?((?:\p{L}|\d|_|-|\.)+) - scope: meta.function.powershell + - match: ^\s*(?i)(function|filter|configuration|workflow)(?=\s) captures: - 1: storage.type.powershell - 2: storage.modifier.scope.powershell - 3: entity.name.function.powershell - push: - - match: (?=\{|\() - pop: 1 - - include: comment-line + 1: keyword.declaration.function.powershell + push: [function-body, function-inline-params, function-name] + + function-name: + - match: (?:(global|local|script|private):)?((?:\p{L}|\d|_|-|\.)+) + captures: + 1: storage.modifier.scope.powershell + 2: entity.name.function.powershell + - match: (?=[{(]) + pop: 1 + + function-inline-params: + - match: \( + scope: punctuation.section.parameters.begin.powershell + push: inside-function-inline-params + - include: else-pop + + inside-function-inline-params: + - match: \) + scope: punctuation.section.parameters.end.powershell + pop: 1 + - include: comma-separators + - include: types + - match: (\$)\p{L}[\p{L}\p{N}]* + scope: variable.parameter.powershell + captures: + 1: punctuation.definition.variable.begin.powershell + + function-body: + - meta_scope: meta.function.powershell + - match: \{ + scope: punctuation.section.block.begin.powershell + push: inside-function-body + - include: else-pop + + inside-function-body: + - match: \} + scope: punctuation.section.block.end.powershell + pop: 1 + + - include: attributes - function-sections: - - match: \b(?i:(?:dynamic)?param){{kebab_break}} + - match: \b(?i:(?:Dynamic)?Param){{kebab_break}} scope: keyword.declaration.parameter.powershell # This scope is not standard - # Begin/Process/End/Clean - - match: \b(?i:begin){{kebab_break}} - scope: keyword.context.block.begin.powershell - - match: \b(?i:process){{kebab_break}} - scope: keyword.context.block.process.powershell - - match: \b(?i:end){{kebab_break}} - scope: keyword.context.block.end.powershell - - match: \b(?i:clean){{kebab_break}} - scope: keyword.context.block.clean.powershell + push: expect-param-context + + - match: \b(?i:Begin|Process|End|Clean){{kebab_break}} + scope: keyword.context.block.powershell + push: expect-function-context + + - include: statements + + expect-function-context: + - match: \{ + scope: punctuation.section.block.begin.powershell + push: inside-function-context + - include: else-pop + + inside-function-context: + - match: \} + scope: punctuation.section.block.end.powershell + pop: 1 + - include: statements + + expect-param-context: + - match: \( + scope: punctuation.section.block.begin.powershell + push: inside-param-context + - include: else-pop + + inside-param-context: + - match: \) + scope: punctuation.section.block.end.powershell + pop: 1 + - include: comma-separators + - include: attributes + - include: types + - include: variables-without-property attributes: - match: (\[)\s*({{attributes}}) @@ -444,8 +498,7 @@ contexts: scope: punctuation.terminator.statement.powershell - match: \`(?=\n|$) scope: punctuation.separator.continuation.line.powershell - - match: ',' - scope: punctuation.separator.sequence.powershell + - include: comma-separators - match: '&' scope: keyword.operator.background.powershell - match: \.\.(?=\-?\d|\(|\$) @@ -870,6 +923,10 @@ contexts: ###[ COMPONENTS ]############################################################## + comma-separators: + - match: ',' + scope: punctuation.separator.sequence.powershell + escape-sequences: - match: '`[0abenfrvt"''$`]' scope: constant.character.escape.powershell diff --git a/Tests/syntax_test_Function.ps1 b/Tests/syntax_test_Function.ps1 index ba922156..a76d4cec 100644 --- a/Tests/syntax_test_Function.ps1 +++ b/Tests/syntax_test_Function.ps1 @@ -74,10 +74,11 @@ function Test-Path {} #> # <- punctuation.definition.comment.block.end function Verb-Noun { -#^^^^^^^^^^^^^^^^^ meta.function -#^^^^^^^ storage.type -# ^^^^^^^^^ entity.name.function +#^^^^^^^^^^^^^^^^^^^ meta.function.powershell +#^^^^^^^ keyword.declaration.function.powershell +# ^^^^^^^^^ entity.name.function.powershell # @@@@@@@@@ definition +# ^ punctuation.section.block.begin.powershell [CmdletBinding(DefaultParameterSetName = 'Parameter Set 1', # <- meta.attribute punctuation.section.brackets.begin # ^ meta.attribute support.function.attribute @@ -112,7 +113,7 @@ function Verb-Noun { # ^ meta.attribute punctuation.section.group.end # ^ meta.attribute punctuation.section.brackets.end [OutputType([String])] -#^^^^^^^^^^^^^^^^^^^^^^^^^ meta.block.powershell +#^^^^^^^^^^^^^^^^^^^^^^^^^ meta.function.powershell # ^^^^^^^^^^^^^^^^^^^^^^ meta.attribute.powershell # ^ punctuation.section.brackets.begin.powershell # ^^^^^^^^^^ support.function.attribute.powershell @@ -123,9 +124,11 @@ function Verb-Noun { # ^ punctuation.section.group.end.powershell # ^ punctuation.section.brackets.end.powershell Param - #^^^^^ keyword.declaration.parameter +#^^^^^^^^ meta.function.powershell +# ^^^^^ keyword.declaration.parameter.powershell ( - # <- punctuation.section.group.begin +#^^^^ meta.function.powershell +# ^ punctuation.section.block.begin.powershell # Param1 help description # <- comment.line punctuation.definition.comment # ^^^^^^^^^^^^^^^^^^^^^^^ comment.line @@ -285,13 +288,15 @@ function Verb-Noun { # ^ punctuation.section.group.end # ^ punctuation.section.brackets.end [int32] - # <- punctuation.section.brackets.begin - #^^^^^ storage.type - # ^ punctuation.section.brackets.end +#^^^^^^^^^^^^^^ meta.function.powershell +# ^ punctuation.section.brackets.begin.powershell +# ^^^^^ storage.type.powershell +# ^ punctuation.section.brackets.end.powershell $Param2, - # <- punctuation.definition.variable - # ^ variable.other.readwrite - # ^ punctuation.separator +#^^^^^^^^^^^^^^^ meta.function.powershell +# ^^^^^^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^ punctuation.separator.sequence.powershell # Param3 help description # <- comment.line punctuation.definition.comment @@ -323,7 +328,7 @@ function Verb-Noun { # ^ meta.attribute punctuation.section.group.end # ^ meta.attribute punctuation.section.brackets.end [String] -#^^^^^^^^^^^^^^^ meta.block.powershell meta.group.powershell +#^^^^^^^^^^^^^^^ meta.function.powershell # ^ punctuation.section.brackets.begin.powershell # ^^^^^^ support.type.powershell # ^ punctuation.section.brackets.end.powershell @@ -357,7 +362,7 @@ function Verb-Noun { # ^ meta.attribute punctuation.section.group.end # ^ meta.attribute punctuation.section.brackets.end [string] -#^^^^^^^^^^^^^^^ meta.block.powershell meta.group.powershell +#^^^^^^^^^^^^^^^ meta.function.powershell # ^ punctuation.section.brackets.begin.powershell # ^^^^^^ storage.type.powershell # ^ punctuation.section.brackets.end.powershell @@ -388,7 +393,7 @@ function Verb-Noun { # ^ comment.line punctuation.definition.comment # ^ comment.line [string] -#^^^^^^^^^^^^^^^ meta.block.powershell meta.group.powershell +#^^^^^^^^^^^^^^^ meta.function.powershell # ^ punctuation.section.brackets.begin.powershell # ^^^^^^ storage.type.powershell # ^ punctuation.section.brackets.end.powershell @@ -396,37 +401,53 @@ function Verb-Noun { # <- punctuation.definition.variable # ^ variable.other.readwrite ) - # <- punctuation.section.group.end +#^^^^^^^^ meta.function.powershell +# ^ punctuation.section.block.end.powershell Begin - #^^^^^ keyword.context.block.begin +#^^^^^^^^ meta.function.powershell +# ^^^^^ keyword.context.block.powershell { +#^^^^ meta.function.powershell +# ^ punctuation.section.block.begin.powershell } Process { - # <- keyword.context.block.process +#^^^^^^^^^^^^ meta.function.powershell +# ^^^^^^^ keyword.context.block.powershell +# ^ punctuation.section.block.begin.powershell if ($pscmdlet.ShouldProcess("Target", "Operation")) { - # <- keyword.control - # ^ punctuation.section.group.begin - # ^ punctuation.definition.variable - # ^^^^^^^^ variable.language - # ^^^^^^^^^^^^^ variable.function - # @@@@@@@@@@@@@ reference - # ^ punctuation.section.arguments.begin - # ^^^^^^^^ string.quoted.double - # ^ punctuation.separator - # ^^^^^^^^^^^ string.quoted.double - # ^ punctuation.section.arguments.end - # ^ punctuation.section.group.end +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.function.powershell +# ^^ keyword.control.conditional.if.powershell +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.group.powershell +# ^ punctuation.section.group.begin.powershell +# ^^^^^^^^^ variable.language.powershell +# ^ punctuation.definition.variable.powershell +# ^ punctuation.accessor.dot.powershell +# ^^^^^^^^^^^^^ meta.function-call.powershell variable.function.powershell +# @@@@@@@@@@@@@ reference +# ^^^^^^^^^^^^^^^^^^^^^^^ meta.function-call.arguments.powershell +# ^ punctuation.section.arguments.begin.powershell +# ^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^ punctuation.separator.sequence.powershell +# ^^^^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^ punctuation.section.arguments.end.powershell +# ^ punctuation.section.group.end.powershell +# ^ meta.block.powershell punctuation.section.braces.begin.powershell } } End { - #^^^ keyword.context.block.end +#^^^^^^^^ meta.function.powershell +# ^^^ keyword.context.block.powershell +# ^ punctuation.section.block.begin.powershell } clean { } -#^^^^^^^^^^^^ meta.block.powershell -# ^^^^^ keyword.context.block.clean.powershell -# ^^^ meta.block.powershell -# ^ punctuation.section.braces.begin.powershell -# ^ punctuation.section.braces.end.powershell +#^^^^^^^^^^^^ meta.function.powershell +# ^^^^^ keyword.context.block.powershell +# ^ punctuation.section.block.begin.powershell +# ^ punctuation.section.block.end.powershell } diff --git a/Tests/syntax_test_PowerShell.ps1 b/Tests/syntax_test_PowerShell.ps1 index 4403147a..2af1c3ce 100644 --- a/Tests/syntax_test_PowerShell.ps1 +++ b/Tests/syntax_test_PowerShell.ps1 @@ -976,121 +976,134 @@ switch ('this') { # Functions and filters functioN MyFunction{} -# <- storage.type -# ^^^^^^^^^^ entity.name.function +#^^^^^^^^^^^^^^^^^^^^ meta.function.powershell +#^^^^^^^ keyword.declaration.function.powershell +# ^^^^^^^^^^ entity.name.function.powershell # @@@@@@@@@@ definition -# ^ punctuation.section.braces.begin -# ^ punctuation.section.braces.end +# ^ punctuation.section.block.begin.powershell +# ^ punctuation.section.block.end.powershell function My-Function {} -# <- storage.type -# ^^^^^^^^^^^ entity.name.function +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.function.powershell +#^^^^^^^ keyword.declaration.function.powershell +# ^^^^^^^^^^^ entity.name.function.powershell # @@@@@@@@@@@ definition -# ^ punctuation.section.braces.begin -# ^ punctuation.section.braces.end +# ^ punctuation.section.block.begin.powershell +# ^ punctuation.section.block.end.powershell Function My.Function{} -# <- storage.type -# ^^^^^^^^^^^ entity.name.function +#^^^^^^^^^^^^^^^^^^^^^ meta.function.powershell +#^^^^^^^ keyword.declaration.function.powershell +# ^^^^^^^^^^^ entity.name.function.powershell # @@@@@@@@@@@ definition -# ^ punctuation.section.braces.begin -# ^ punctuation.section.braces.end +# ^ punctuation.section.block.begin.powershell +# ^ punctuation.section.block.end.powershell function My-Function.Other{} -# <- storage.type -# ^^^^^^^^^^^^^^^^^ entity.name.function +#^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.function.powershell +#^^^^^^^ keyword.declaration.function.powershell +# ^^^^^^^^^^^^^^^^^ entity.name.function.powershell # @@@@@@@@@@@@@@@@@ definition -# ^ punctuation.section.braces.begin -# ^ punctuation.section.braces.end +# ^ punctuation.section.block.begin.powershell +# ^ punctuation.section.block.end.powershell function Some.other.function{} -# <- storage.type -# ^^^^^^^^^^^^^^^^^^^ entity.name.function +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.function.powershell +#^^^^^^^ keyword.declaration.function.powershell +# ^^^^^^^^^^^^^^^^^^^ entity.name.function.powershell # @@@@@@@@@@@@@@@@@@@ definition -# ^ punctuation.section.braces.begin -# ^ punctuation.section.braces.end +# ^ punctuation.section.block.begin.powershell +# ^ punctuation.section.block.end.powershell FUNCTION MyFunction2 {} -# <- storage.type -# ^^^^^^^^^^^ entity.name.function +#^^^^^^^^^^^^^^^^^^^^^^ meta.function.powershell +#^^^^^^^ keyword.declaration.function.powershell +# ^^^^^^^^^^^ entity.name.function.powershell # @@@@@@@@@@@ definition -# ^ punctuation.section.braces.begin -# ^ punctuation.section.braces.end +# ^ punctuation.section.block.begin.powershell +# ^ punctuation.section.block.end.powershell function New-File { } -# <- storage.type -# ^^^^^^^^ entity.name.function +#^^^^^^^^^^^^^^^^^^^^ meta.function.powershell +#^^^^^^^ keyword.declaration.function.powershell +# ^^^^^^^^ entity.name.function.powershell # @@@@@@@@ definition -# ^ punctuation.section.braces.begin -# ^ punctuation.section.braces.end +# ^ punctuation.section.block.begin.powershell +# ^ punctuation.section.block.end.powershell function New-File ($Name) { } -# <- storage.type -# ^^^^^^^^ entity.name.function +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.function.powershell +#^^^^^^^ keyword.declaration.function.powershell +# ^^^^^^^^ entity.name.function.powershell # @@@@@@@@ definition -# ^ punctuation.section.braces.begin -# ^ punctuation.section.braces.end New-File -#^^^^^^^^ meta.function-call support.function +#^^^^^^^^ meta.function-call.powershell support.function.powershell #@@@@@@@@ reference function NewFile($Name) { } -# <- storage.type -# ^^^^^^^ entity.name.function +#^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.function.powershell +#^^^^^^^ keyword.declaration.function.powershell +# ^^^^^^^ entity.name.function.powershell # @@@@@@@ definition -# ^ punctuation.section.group.begin -# ^ punctuation.definition.variable -# ^ variable.other.readwrite -# ^ punctuation.section.group.end -# ^ punctuation.section.braces.begin -# ^ punctuation.section.braces.end +# ^ punctuation.section.parameters.begin.powershell +# ^^^^^ variable.parameter.powershell +# ^ punctuation.definition.variable.begin.powershell +# ^ punctuation.section.parameters.end.powershell +# ^ punctuation.section.block.begin.powershell +# ^ punctuation.section.block.end.powershell filter myfilter($param) {} -# <- storage.type -# ^^^^^^^^ entity.name.function +#^^^^^^^^^^^^^^^^^^^^^^^^^ meta.function.powershell +#^^^^^ keyword.declaration.function.powershell +# ^^^^^^^^ entity.name.function.powershell # @@@@@@@@ definition -# ^ punctuation.section.group.begin -# ^ punctuation.definition.variable -# ^ variable.other.readwrite -# ^ punctuation.section.group.end -# ^ punctuation.section.braces.begin -# ^ punctuation.section.braces.end +# ^ punctuation.section.parameters.begin.powershell +# ^^^^^^ variable.parameter.powershell +# ^ punctuation.definition.variable.begin.powershell +# ^ punctuation.section.parameters.end.powershell +# ^ punctuation.section.block.begin.powershell +# ^ punctuation.section.block.end.powershell Filter my-Filter ($param){} -# <- storage.type -# ^^^^^^^^^ entity.name.function +#^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.function.powershell +#^^^^^ keyword.declaration.function.powershell +# ^^^^^^^^^ entity.name.function.powershell # @@@@@@@@@ definition -# ^ punctuation.section.group.begin -# ^ punctuation.definition.variable -# ^ variable.other.readwrite -# ^ punctuation.section.group.end -# ^ punctuation.section.braces.begin -# ^ punctuation.section.braces.end +# ^ punctuation.section.parameters.begin.powershell +# ^^^^^^ variable.parameter.powershell +# ^ punctuation.definition.variable.begin.powershell +# ^ punctuation.section.parameters.end.powershell +# ^ punctuation.section.block.begin.powershell +# ^ punctuation.section.block.end.powershell # Note that the # in the path should highlight as a comment! function Test-Drive([string]$roman) { -# <- storage.type -# ^^^^^^^^^^ entity.name.function +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.function.powershell +#^^^^^^^ keyword.declaration.function.powershell +# ^^^^^^^^^^ entity.name.function.powershell # @@@@@@@@@@ definition -# ^ punctuation.section.group.begin -# ^ punctuation.section.brackets.begin -# ^^^^^^ storage.type -# ^ punctuation.section.brackets.end -# ^ punctuation.definition.variable -# ^ variable.other.readwrite -# ^ punctuation.section.group.end -# ^ punctuation.section.braces.begin +# ^ punctuation.section.parameters.begin.powershell +# ^ punctuation.section.brackets.begin.powershell +# ^^^^^^ storage.type.powershell +# ^ punctuation.section.brackets.end.powershell +# ^^^^^^ variable.parameter.powershell +# ^ punctuation.definition.variable.begin.powershell +# ^ punctuation.section.parameters.end.powershell +# ^ punctuation.section.block.begin.powershell $roman | c:\users\Me\Documents\Programming\F#\test.exe $roman # ^ punctuation.definition.variable # ^ variable.other.readwrite # ^ keyword.operator.logical.pipe # ^ punctuation.definition.comment # ^^^^ comment.line -} -# <- punctuation.section.braces.end + } +#^^^^ meta.function.powershell +# ^ punctuation.section.block.end.powershell function Verb-Noun -#^^^^^^^^^^^^^^^^^ meta.function -#^^^^^^^ storage.type -# ^^^^^^^^^ meta.function entity.name.function +#^^^^^^^^^^^^^^^^^ meta.function.powershell +#^^^^^^^ keyword.declaration.function.powershell +# ^^^^^^^^^ entity.name.function.powershell # @@@@@@@@@ definition -{ -# <- punctuation.section.braces.begin + { +#^^^^ meta.function.powershell +# ^ punctuation.section.block.begin.powershell Param #^^^^^ keyword.declaration.parameter ( - # <- punctuation.section.group.begin +#^^^^ meta.function.powershell +# ^ punctuation.section.block.begin.powershell # Param1 help description # <- comment.line punctuation.definition.comment # ^^^^^^^^^^^^^^^^^^^^^^^ comment.line @@ -1198,12 +1211,14 @@ function Verb-Noun # <- punctuation.definition.variable # ^ variable.other.readwrite ) - # <- punctuation.section.group.end +#^^^^ meta.function.powershell +# ^ punctuation.section.block.end.powershell # Do Something.... -} -# <- punctuation.section.braces.end + } +#^^^^ meta.function.powershell +# ^ punctuation.section.block.end.powershell # Class class Vehicle { @@ -1292,16 +1307,19 @@ catch { } # Reserved words Configuration Crazyness { -# <- storage.type -# ^^^^^^^^^ entity.name.function +#^^^^^^^^^^^^^^^^^^^^^^^^ meta.function.powershell +#^^^^^^^^^^^^ keyword.declaration.function.powershell +# ^^^^^^^^^ entity.name.function.powershell # @@@@@@@@@ definition -# ^ punctuation.section.braces.begin +# ^ punctuation.section.block.begin.powershell Node Whatever { # ^ punctuation.section.braces.begin } - # <- punctuation.section.braces.end -} -# <- punctuation.section.braces.end +#^^^^ meta.function.powershell meta.block.powershell +# ^ punctuation.section.braces.end.powershell + } +#^^^^ meta.function.powershell +# ^ punctuation.section.block.end.powershell # Redirection notepad.exe > log.txt @@ -1540,20 +1558,23 @@ $ScriptBlock | Out-File $file -Force # ^ punctuation.definition.parameter # ^^^^^^ variable.parameter.option workflow w1 {} -# <- storage.type -# ^^ entity.name.function +#^^^^^^^^^^^^^ meta.function.powershell +#^^^^^^^ keyword.declaration.function.powershell +# ^^ entity.name.function.powershell # @@ definition -# ^ punctuation.section.braces.begin -# ^ punctuation.section.braces.end +# ^ punctuation.section.block.begin.powershell +# ^ punctuation.section.block.end.powershell Workflow work { sequence {} } -# <- storage.type -# ^^^^ entity.name.function +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.function.powershell +#^^^^^^^ keyword.declaration.function.powershell +# ^^^^ entity.name.function.powershell # @@@@ definition -# ^ punctuation.section.braces.begin -# ^^^^^^^^ keyword.control -# ^ punctuation.section.braces.begin -# ^ punctuation.section.braces.end -# ^ punctuation.section.braces.end +# ^ punctuation.section.block.begin.powershell +# ^^^^^^^^ keyword.control.powershell +# ^^ meta.block.powershell +# ^ punctuation.section.braces.begin.powershell +# ^ punctuation.section.braces.end.powershell +# ^ punctuation.section.block.end.powershell function get-something {} # @@@@@@@@@@@@@ definition function Out-WithYou {} From cf2f3c33b677be24ff6ec8f32e0c397cca06cc7d Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Sat, 6 Dec 2025 13:12:33 -0500 Subject: [PATCH 36/81] Add the PowerShell documentation Class samples --- PowerShell.sublime-syntax | 2 +- Tests/syntax_test_Class.ps1 | 281 ++++++++++++++++++++++++++++++++++++ 2 files changed, 282 insertions(+), 1 deletion(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index f331ed40..dd71c00d 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -219,7 +219,7 @@ contexts: commands-reserved: # Builtin cmdlets with reserved verbs - match: \b(?i:(?:ForEach|Where|Sort|Tee)-Object)\b - scope: support.function.powershell + scope: meta.function-call.powershell support.function.powershell script-invocation: - match: \b[\w.\\/-]+\.(?i:exe|com|cmd|bat|ps1)\b diff --git a/Tests/syntax_test_Class.ps1 b/Tests/syntax_test_Class.ps1 index 8e94d1d9..b50af7d9 100644 --- a/Tests/syntax_test_Class.ps1 +++ b/Tests/syntax_test_Class.ps1 @@ -136,3 +136,284 @@ class TypeName $object.MemberMethod2() # @@@@@@@@@@@@@ reference + + +# PowerShell documentation examples +# https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_classes + +# Example 1 - Minimal definition +class Device { +# @@@@@@ definition + [string]$Brand +} + +$dev = [Device]::new() +# @@@ reference +$dev.Brand = "Fabrikam, Inc." +$dev + + +# Example 2 - Class with instance members +class Book { +# @@@@ definition + # Class properties + [string] $Title + [string] $Author + [string] $Synopsis + [string] $Publisher + [datetime] $PublishDate + [int] $PageCount + [string[]] $Tags + # Default constructor + Book() { $this.Init(@{}) } +# @@@@ reference + # Convenience constructor from hashtable + Book([hashtable]$Properties) { $this.Init($Properties) } +# @@@@ reference + # Common constructor for title and author + Book([string]$Title, [string]$Author) { + $this.Init(@{Title = $Title; Author = $Author }) +# @@@@ reference + } + # Shared initializer method + [void] Init([hashtable]$Properties) { +# @@@@ definition + foreach ($Property in $Properties.Keys) { + $this.$Property = $Properties.$Property + } + } + # Method to calculate reading time as 2 minutes per page + [timespan] GetReadingTime() { +# @@@@@@@@@@@@@@ definition + if ($this.PageCount -le 0) { + throw 'Unable to determine reading time from page count.' + } + $Minutes = $this.PageCount * 2 + return [timespan]::new(0, $Minutes, 0) +# @@@ reference + } + # Method to calculate how long ago a book was published + [timespan] GetPublishedAge() { +# @@@@@@@@@@@@@@@ definition + if ( + $null -eq $this.PublishDate -or + $this.PublishDate -eq [datetime]::MinValue + ) { throw 'PublishDate not defined' } + + return (Get-Date) - $this.PublishDate +# @@@@@@@@ reference + } + # Method to return a string representation of the book + [string] ToString() { +# @@@@@@@@ definition + return "$($this.Title) by $($this.Author) ($($this.PublishDate.Year))" + } +} + +[BookList]::Add([Book]::new(@{ +# @@@ reference +# @@@ reference + Title = 'The Fellowship of the Ring' + Author = 'J.R.R. Tolkien' + Publisher = 'George Allen & Unwin' + PublishDate = '1954-07-29' + PageCount = 423 + Tags = @('Fantasy', 'Adventure') +})) + +[BookList]::Find({ +# @@@@ reference + param ($b) + + $b.PublishDate -gt '1950-01-01' +}).Title + +[BookList]::FindAll({ +# @@@@@@@ reference + param($b) + + $b.Author -match 'Tolkien' +}).Title + +[BookList]::Remove($Book) +# @@@@@@ reference +[BookList]::Books.Title + +[BookList]::RemoveBy('Author', 'J.R.R. Tolkien') +# @@@@@@@@ reference +"Titles: $([BookList]::Books.Title)" + +[BookList]::Add($Book) +# @@@ reference +[BookList]::Add($Book) +# @@@ reference + + +# Example 3 - Class with static members +class BookList { +# @@@@@@@@ definition + # Static property to hold the list of books + static [System.Collections.Generic.List[Book]] $Books + # Static method to initialize the list of books. Called in the other + # static methods to avoid needing to explicit initialize the value. + static [void] Initialize() { [BookList]::Initialize($false) } +# @@@@@@@@@@ definition +# @@@@@@@@@@ reference + static [bool] Initialize([bool]$Force) { +# @@@@@@@@@@ definition + if ([BookList]::Books.Count -gt 0 -and -not $Force) { + return $false + } + + [BookList]::Books = [System.Collections.Generic.List[Book]]::new() +# @@@ reference + + return $true + } + # Ensure a book is valid for the list. + static [void] Validate([book]$Book) { +# @@@@@@@@ definition + $Prefix = @( + 'Book validation failed: Book must be defined with the Title,' + 'Author, and PublishDate properties, but' + ) -join ' ' + if ($null -eq $Book) { throw "$Prefix was null" } + if ([string]::IsNullOrEmpty($Book.Title)) { +# @@@@@@@@@@@@@ reference + throw "$Prefix Title wasn't defined" + } + if ([string]::IsNullOrEmpty($Book.Author)) { +# @@@@@@@@@@@@@ reference + throw "$Prefix Author wasn't defined" + } + if ([datetime]::MinValue -eq $Book.PublishDate) { + throw "$Prefix PublishDate wasn't defined" + } + } + # Static methods to manage the list of books. + # Add a book if it's not already in the list. + static [void] Add([Book]$Book) { +# @@@ definition + [BookList]::Initialize() +# @@@@@@@@@@ reference + [BookList]::Validate($Book) +# @@@@@@@@ reference + if ([BookList]::Books.Contains($Book)) { +# @@@@@@@@ reference + throw "Book '$Book' already in list" + } + + $FindPredicate = { + param([Book]$b) + + $b.Title -eq $Book.Title -and + $b.Author -eq $Book.Author -and + $b.PublishDate -eq $Book.PublishDate + }.GetNewClosure() + if ([BookList]::Books.Find($FindPredicate)) { +# @@@@ reference + throw "Book '$Book' already in list" + } + + [BookList]::Books.Add($Book) +# @@@ reference + } + # Clear the list of books. + static [void] Clear() { +# @@@@@ definition + [BookList]::Initialize() +# @@@@@@@@@@ reference + [BookList]::Books.Clear() +# @@@@@ reference + } + # Find a specific book using a filtering scriptblock. + static [Book] Find([scriptblock]$Predicate) { +# @@@@ definition + [BookList]::Initialize() +# @@@@@@@@@@ reference + return [BookList]::Books.Find($Predicate) +# @@@@ reference + } + # Find every book matching the filtering scriptblock. + static [Book[]] FindAll([scriptblock]$Predicate) { + [BookList]::Initialize() +# @@@@@@@@@@ reference + return [BookList]::Books.FindAll($Predicate) +# @@@@@@@ reference + } + # Remove a specific book. + static [void] Remove([Book]$Book) { +# @@@@@@ definition + [BookList]::Initialize() +# @@@@@@@@@@ reference + [BookList]::Books.Remove($Book) +# @@@@@@ reference + } + # Remove a book by property value. + static [void] RemoveBy([string]$Property, [string]$Value) { +# @@@@@@@@ definition + [BookList]::Initialize() +# @@@@@@@@@@ reference + $Index = [BookList]::Books.FindIndex({ +# @@@@@@@@@ reference + param($b) + $b.$Property -eq $Value + }.GetNewClosure()) + if ($Index -ge 0) { + [BookList]::Books.RemoveAt($Index) +# @@@@@@@@ reference + } + } +} + + +# Example 4 - Class definition with and without Runspace affinity + +# Class definition with Runspace affinity (default behavior) +class UnsafeClass { +# @@@@@@@@@@@ definition + static [Object] ShowRunspaceId($Val) { +# @@@@@@@@@@@@@@ definition + return [pscustomobject]@{ + ThreadId = [Threading.Thread]::CurrentThread.ManagedThreadId + RunspaceId = [runspace]::DefaultRunspace.Id + } + } +} + +$unsafe = [UnsafeClass]::new() +# @@@ reference + +while ($true) { + 1..10 | ForEach-Object -Parallel { +# @@@@@@@@@@@@@@ reference + Start-Sleep -ms 100 +# @@@@@@@@@@@ reference + ($Using:unsafe)::ShowRunspaceId($_) + } +} + +# Class definition with NoRunspaceAffinity attribute +[NoRunspaceAffinity()] +class SafeClass { +# @@@@@@@@@ definition + static [Object] ShowRunspaceId($Val) { +# @@@@@@@@@@@@@@ definition + return [pscustomobject]@{ + ThreadId = [Threading.Thread]::CurrentThread.ManagedThreadId + RunspaceId = [runspace]::DefaultRunspace.Id + } + } +} + +$safe = [SafeClass]::new() +# @@@ reference + +while ($true) { + 1..10 | ForEach-Object -Parallel { +# @@@@@@@@@@@@@@ reference + Start-Sleep -ms 100 +# @@@@@@@@@@@ reference + ($Using:safe)::ShowRunspaceId($_) + } +} From 3f3a9639d1f6424f986a34e12f0187f4a86464a5 Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Sat, 6 Dec 2025 17:46:29 -0500 Subject: [PATCH 37/81] Improve variable matches --- PowerShell.sublime-syntax | 83 +++++++++++-------- Tests/syntax_test_PowerShell.ps1 | 138 ++++++++++++++++--------------- Tests/syntax_test_strings.ps1 | 15 ++-- 3 files changed, 128 insertions(+), 108 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index dd71c00d..b2b5c8a0 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -546,79 +546,86 @@ contexts: ###[ VARIABLES ]############################################################### variables: - - match: (\$){{var_constants}} + - match: (\$|@){{var_constants}} scope: support.constant.variable.powershell captures: 1: punctuation.definition.variable.powershell push: members - - match: (\$){{var_language}} + - match: (\$|@){{var_language}} scope: variable.language.powershell captures: 1: punctuation.definition.variable.powershell push: members - - match: ((\$|@)(?i:({{var_scope_mod}}):\w+)) + - match: (\$|@)({{var_scope_mod}})(:){{identifier_simple}} + scope: variable.other.readwrite.powershell captures: - 1: variable.other.readwrite.powershell - 2: punctuation.definition.variable.powershell - 3: storage.modifier.scope.powershell + 1: punctuation.definition.variable.powershell + 2: storage.modifier.scope.powershell + 3: punctuation.separator.sequence.powershell push: members - - match: ((\$)(\{)({{var_scope_mod}}):([^}]*[^}`])(\})) + - match: (\$|@)(\{)({{var_scope_mod}})(:){{identifier_special}}(\}) + scope: variable.other.readwrite.powershell captures: - 1: variable.other.readwrite.powershell - 2: punctuation.definition.variable.powershell - 3: punctuation.section.braces.begin.powershell - 4: storage.modifier.scope.powershell - 6: punctuation.section.braces.end.powershell + 1: punctuation.definition.variable.powershell + 2: punctuation.section.interpolation.begin.powershell + 3: storage.modifier.scope.powershell + 4: punctuation.separator.sequence.powershell + 5: punctuation.section.interpolation.end.powershell push: members - - match: ((?i:(\$|@)(\w+:)?\w+)) + - match: (\$|@)(?:({{identifier_simple}})(:))?{{identifier_simple}} + scope: variable.other.readwrite.powershell captures: - 1: variable.other.readwrite.powershell - 2: punctuation.definition.variable.powershell - 3: support.variable.drive.powershell - 4: variable.other.member.powershell + 1: punctuation.definition.variable.powershell + 2: support.variable.drive.powershell + 3: punctuation.separator.sequence.powershell push: members - - match: ((?i:(\$)(\{)(\w+:)?([^}]*[^}`])(\}))) + - match: (\$|@)(\{)(?:({{identifier_special}})(:))?{{identifier_special}}(\}) + scope: variable.other.readwrite.powershell captures: - 1: variable.other.readwrite.powershell - 2: punctuation.definition.variable.powershell - 3: punctuation.section.braces.begin.powershell - 4: support.variable.drive.powershell - 6: punctuation.section.braces.end.powershell + 1: punctuation.definition.variable.powershell + 2: punctuation.section.interpolation.begin.powershell + 3: support.variable.drive.powershell + 4: punctuation.separator.sequence.powershell + 5: punctuation.section.interpolation.end.powershell push: members variables-without-property: - - match: (\$){{var_constants}} + - match: (\$|@){{var_constants}} scope: support.constant.variable.powershell captures: 1: punctuation.definition.variable.powershell - - match: (\$){{var_language}} + - match: (\$|@){{var_language}} scope: variable.language.powershell captures: 1: punctuation.definition.variable.powershell - - match: (?i:(\$|@)({{var_scope_mod}}):(\w+)) + - match: (\$|@)({{var_scope_mod}})(:){{identifier_simple}} + scope: variable.other.readwrite.powershell captures: 1: punctuation.definition.variable.powershell 2: storage.modifier.scope.powershell - 3: variable.other.readwrite.powershell - - match: (?i:(\$)(\{)({{var_scope_mod}}):([^}]*[^}`])(\})) + 3: punctuation.separator.sequence.powershell + - match: (\$|@)(\{)({{var_scope_mod}})(:){{identifier_special}}(\}) + scope: variable.other.readwrite.powershell captures: 1: punctuation.definition.variable.powershell - 2: punctuation.section.braces.begin + 2: punctuation.section.interpolation.begin.powershell 3: storage.modifier.scope.powershell - 4: variable.other.readwrite.powershell - 5: punctuation.section.braces.end - - match: (?i:(\$)(\w+:)?\w+) + 4: punctuation.separator.sequence.powershell + 5: punctuation.section.interpolation.end.powershell + - match: (\$|@)(?:({{identifier_simple}})(:))?{{identifier_simple}} scope: variable.other.readwrite.powershell captures: 1: punctuation.definition.variable.powershell 2: support.variable.drive.powershell - - match: (?i:(\$)(\{)(\w+:)?([^}]*[^}`])(\})) + 3: punctuation.separator.sequence.powershell + - match: (\$|@)(\{)(?:({{identifier_special}})(:))?{{identifier_special}}(\}) + scope: variable.other.readwrite.powershell captures: 1: punctuation.definition.variable.powershell - 2: punctuation.section.braces.begin + 2: punctuation.section.interpolation.begin.powershell 3: support.variable.drive.powershell - 4: variable.other.readwrite.powershell - 5: punctuation.section.braces.end + 4: punctuation.separator.sequence.powershell + 5: punctuation.section.interpolation.end.powershell members: - match: (?=\.\.) @@ -985,6 +992,10 @@ variables: unit_suffix: (?i:[kmgtp]b\b) # Variables + # https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_variables + identifier_simple: '[\p{Lu}\p{Ll}\p{Lt}\p{Lm}\p{Lo}\p{Nd}_?]+' + identifier_special: '[^}]*[^}`]' + # https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_automatic_variables var_constants: |- \b(?xi: (?: diff --git a/Tests/syntax_test_PowerShell.ps1 b/Tests/syntax_test_PowerShell.ps1 index 2af1c3ce..bfb0d5b5 100644 --- a/Tests/syntax_test_PowerShell.ps1 +++ b/Tests/syntax_test_PowerShell.ps1 @@ -137,73 +137,80 @@ throw "Do not run this file!" # ^^^^^ constant.language.null.powershell # ^ punctuation.definition.variable.powershell -# Automatic variables -$_, $$, $^, $? -# <- punctuation.definition.variable -#^ variable.language -# ^ punctuation.definition.variable -# ^^ variable.language -# ^ punctuation.definition.variable -# ^^ variable.language -# ^ punctuation.definition.variable -# ^^ variable.language -$args -# <- punctuation.definition.variable -#^^^^ variable.language -$error -# <- punctuation.definition.variable -# ^^^^ variable.language -$home -# <- punctuation.definition.variable -# ^^^ support.constant.variable -$foreach -# <- punctuation.definition.variable -#^^^^^^^ variable.language + # Automatic variables + $_, $$, $^, $? +# ^^ variable.language.powershell +# ^ punctuation.definition.variable.powershell +# ^ punctuation.separator.sequence.powershell +# ^^ variable.language.powershell +# ^ punctuation.definition.variable.powershell +# ^ punctuation.separator.sequence.powershell +# ^^ variable.language.powershell +# ^ punctuation.definition.variable.powershell +# ^ punctuation.separator.sequence.powershell +# ^^ variable.language.powershell +# ^ punctuation.definition.variable.powershell + $args +# ^^^^^ variable.language.powershell +# ^ punctuation.definition.variable.powershell + $error +# ^^^^^^ variable.language.powershell +# ^ punctuation.definition.variable.powershell + $home +# ^^^^^ support.constant.variable.powershell +# ^ punctuation.definition.variable.powershell + $foreach +# ^^^^^^^^ variable.language.powershell +# ^ punctuation.definition.variable.powershell -# Normal variables -$variable -# <- punctuation.definition.variable -# ^ variable.other.readwrite -$script:variable -# <- variable.other.readwrite punctuation.definition.variable -# ^ storage.modifier.scope -# ^ variable.other.readwrite -$ENV:ComputerName -# <- variable.other.readwrite punctuation.definition.variable -# ^ support.variable.drive -# ^ variable.other.readwrite -${variable} -# <- variable.other.readwrite punctuation.definition.variable - # <- punctuation.section.braces.begin -# ^^^^^^^^ variable.other.readwrite -# ^ punctuation.section.braces.end -${script:variable} -# <- variable.other.readwrite punctuation.definition.variable - # <- punctuation.section.braces.begin -# ^ storage.modifier.scope -# ^ variable.other.readwrite -# ^ punctuation.section.braces.end -# Variable properties should be highlighted -$variable.Name -# <- variable.other.readwrite punctuation.definition.variable -#^^^^^^^^ variable.other.readwrite -# ^ punctuation.accessor.dot -# ^^^^^ - variable.other.readwrite -# ^^^^ variable.other.member + # Normal variables + $variable +# ^^^^^^^^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell + $script:variable +# ^^^^^^^^^^^^^^^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^^^^^^ storage.modifier.scope.powershell +# ^ punctuation.separator.sequence.powershell + $ENV:ComputerName +# ^^^^^^^^^^^^^^^^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^^^ support.variable.drive.powershell +# ^ punctuation.separator.sequence.powershell + ${variable} +# ^^^^^^^^^^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^ punctuation.section.interpolation.begin.powershell +# ^ punctuation.section.interpolation.end.powershell + ${script:variable} +# ^^^^^^^^^^^^^^^^^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^ punctuation.section.interpolation.begin.powershell +# ^^^^^^ storage.modifier.scope.powershell +# ^ punctuation.separator.sequence.powershell +# ^ punctuation.section.interpolation.end.powershell -# Variable properties should be highlighted -$variable.Name.Method( ) -# <- variable.other.readwrite punctuation.definition.variable -#^^^^^^^^ variable.other.readwrite -# ^ punctuation.accessor.dot -# ^^^^ variable.other.member -# ^ punctuation.accessor.dot -# ^^^^^^ meta.function-call variable.function -# @@@@@@ reference -# ^^^ meta.function-call.arguments -# ^^^^^^^^^^^^^^^ - variable.other.readwrite -# ^ - meta.function-call + + # Variable properties should be highlighted + $variable.Name +# ^^^^^^^^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^ punctuation.accessor.dot.powershell +# ^^^^ variable.other.member.powershell + + # Variable properties should be highlighted + $variable.Name.Method( ) +# ^^^^^^^^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^ punctuation.accessor.dot.powershell +# ^^^^ variable.other.member.powershell +# ^ punctuation.accessor.dot.powershell +# ^^^^^^ meta.function-call.powershell variable.function.powershell +# @@@@@@ reference +# ^^^ meta.function-call.arguments.powershell +# ^ punctuation.section.arguments.begin.powershell +# ^ punctuation.section.arguments.end.powershell # Hashtable $properties = @{ @@ -1526,7 +1533,8 @@ $file = join-path $env:SystemDrive "$([System.io.path]::GetRandomFileName()).ps1 # @@@@@@@@@ reference # ^^^^^^^^^^^^^^^^ variable.other.readwrite.powershell # ^ punctuation.definition.variable.powershell -# ^^^^ support.variable.drive.powershell +# ^^^ support.variable.drive.powershell +# ^ punctuation.separator.sequence.powershell # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string.interpolated.powershell # ^ string.quoted.double.powershell punctuation.definition.string.begin.powershell # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.interpolation.powershell diff --git a/Tests/syntax_test_strings.ps1 b/Tests/syntax_test_strings.ps1 index f6f020d6..4bdb7940 100644 --- a/Tests/syntax_test_strings.ps1 +++ b/Tests/syntax_test_strings.ps1 @@ -113,9 +113,10 @@ # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string.interpolated.powershell # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ string.quoted.double.powershell # ^ punctuation.definition.string.begin.powershell -# ^^^^^^^^^^^^^^^^^ meta.interpolation.powershell variable.other.readwrite.powershell - string +# ^^^^^^^^^^^^^^^^^ meta.interpolation.powershell variable.other.readwrite.powershell # ^ punctuation.definition.variable.powershell -# ^^^^ support.variable.drive.powershell +# ^^^ support.variable.drive.powershell +# ^ punctuation.separator.sequence.powershell # ^ string.quoted.double.powershell punctuation.definition.string.end.powershell # Here as well @@ -123,12 +124,12 @@ # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string.interpolated.powershell # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ string.quoted.double.powershell # ^ punctuation.definition.string.begin.powershell -# ^^^^^^^^^^^^^^^^^^^ meta.interpolation.powershell - string +# ^^^^^^^^^^^^^^^^^^^ meta.interpolation.powershell variable.other.readwrite.powershell # ^ punctuation.definition.variable.powershell -# ^ punctuation.section.braces.begin -# ^^^^ support.variable.drive.powershell -# ^^^^^^^^^^^^ variable.other.readwrite.powershell -# ^ punctuation.section.braces.end +# ^ punctuation.section.interpolation.begin.powershell +# ^^^ support.variable.drive.powershell +# ^ punctuation.separator.sequence.powershell +# ^ punctuation.section.interpolation.end.powershell # ^ string.quoted.double.powershell punctuation.definition.string.end.powershell # The @splat references only work in argument mode, should not highlight in strings From 8b5394f0e3e430966af041d6e9ef754ab92d6f72 Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Sat, 6 Dec 2025 18:01:25 -0500 Subject: [PATCH 38/81] Allow member access of groups --- PowerShell.sublime-syntax | 15 ++++---------- Tests/syntax_test_Class.ps1 | 2 ++ Tests/syntax_test_PowerShell.ps1 | 34 ++++++++++++++++++++++++++++++++ Tests/syntax_test_strings.ps1 | 12 ++++++----- 4 files changed, 47 insertions(+), 16 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index b2b5c8a0..54fefe4e 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -400,7 +400,7 @@ contexts: types: - match: \[ scope: punctuation.section.brackets.begin.powershell - push: [maybe-static-member, inside-type] + push: [members, inside-type] types-without-members: - match: \[ @@ -426,15 +426,6 @@ contexts: - match: \+ scope: punctuation.accessor.plus.powershell - static-members: - - match: '::' - scope: punctuation.accessor.double-colon.powershell - set: members - - maybe-static-member: - - include: static-members - - include: immediately-pop - ###[ OPERATORS ]############################################################### operators: @@ -632,6 +623,8 @@ contexts: pop: 1 - match: \.(?=\w) scope: punctuation.accessor.dot.powershell + - match: ::(?=\w) + scope: punctuation.accessor.double-colon.powershell - match: (\w+)(\() captures: 1: meta.function-call.powershell variable.function.powershell @@ -663,7 +656,7 @@ contexts: - meta_scope: meta.group.powershell - match: \) scope: punctuation.section.group.end.powershell - pop: 1 + set: members - include: attributes - include: expressions diff --git a/Tests/syntax_test_Class.ps1 b/Tests/syntax_test_Class.ps1 index b50af7d9..f202d4d6 100644 --- a/Tests/syntax_test_Class.ps1 +++ b/Tests/syntax_test_Class.ps1 @@ -390,6 +390,7 @@ while ($true) { Start-Sleep -ms 100 # @@@@@@@@@@@ reference ($Using:unsafe)::ShowRunspaceId($_) +# @@@@@@@@@@@@@@ reference } } @@ -415,5 +416,6 @@ while ($true) { Start-Sleep -ms 100 # @@@@@@@@@@@ reference ($Using:safe)::ShowRunspaceId($_) +# @@@@@@@@@@@@@@ reference } } diff --git a/Tests/syntax_test_PowerShell.ps1 b/Tests/syntax_test_PowerShell.ps1 index bfb0d5b5..8a70b5f4 100644 --- a/Tests/syntax_test_PowerShell.ps1 +++ b/Tests/syntax_test_PowerShell.ps1 @@ -1617,6 +1617,40 @@ function get-number {} # ^ meta.group.complex.subexpression punctuation.section.group.end # ^ punctuation.definition.variable # ^ punctuation.section.interpolation.end - source.powershell.embedded + + ([MyType])::Name[2] +# ^^^^^^^^^^ meta.group.powershell +# ^ punctuation.section.group.begin.powershell +# ^ punctuation.section.brackets.begin.powershell +# ^^^^^^ support.type.powershell +# ^ punctuation.section.brackets.end.powershell +# ^ punctuation.section.group.end.powershell +# ^^ punctuation.accessor.double-colon.powershell +# ^^^^ variable.other.member.powershell +# ^^^ meta.brackets.indexer.powershell +# ^ punctuation.section.brackets.begin.powershell +# ^ meta.number.integer.decimal.powershell constant.numeric.value.powershell +# ^ punctuation.section.brackets.end.powershell + ([MyType])::Name.ToString()[2] +# ^^^^^^^^^^ meta.group.powershell +# ^ punctuation.section.group.begin.powershell +# ^ punctuation.section.brackets.begin.powershell +# ^^^^^^ support.type.powershell +# ^ punctuation.section.brackets.end.powershell +# ^ punctuation.section.group.end.powershell +# ^^ punctuation.accessor.double-colon.powershell +# ^^^^ variable.other.member.powershell +# ^ punctuation.accessor.dot.powershell +# ^^^^^^^^ meta.function-call.powershell variable.function.powershell +# @@@@@@@@ reference +# ^^ meta.function-call.arguments.powershell +# ^ punctuation.section.arguments.begin.powershell +# ^ punctuation.section.arguments.end.powershell +# ^^^ meta.brackets.indexer.powershell +# ^ punctuation.section.brackets.begin.powershell +# ^ meta.number.integer.decimal.powershell constant.numeric.value.powershell +# ^ punctuation.section.brackets.end.powershell + "This is the DebugPreference variable: $DebugPreference" #^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string string.quoted.double # ^^^^^^^^^^^^^^^^ meta.string meta.interpolation variable.language - string diff --git a/Tests/syntax_test_strings.ps1 b/Tests/syntax_test_strings.ps1 index 4bdb7940..2b06b7ca 100644 --- a/Tests/syntax_test_strings.ps1 +++ b/Tests/syntax_test_strings.ps1 @@ -240,19 +240,21 @@ # ^^ variable.other.readwrite.powershell # ^ punctuation.definition.variable.powershell - # TODO: Mark ToString as a function (1.11).ToString("#.#") # ^^^^^^ meta.group.powershell # ^ punctuation.section.group.begin.powershell # ^^^^ meta.number.float.decimal.powershell constant.numeric.value.powershell # ^ punctuation.separator.decimal.powershell # ^ punctuation.section.group.end.powershell -# ^^^^^^^ meta.group.powershell -# ^ punctuation.section.group.begin.powershell -# ^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell - comment +# ^ punctuation.accessor.dot.powershell +# ^^^^^^^^ meta.function-call.powershell variable.function.powershell +# @@@@@@@@ reference +# ^^^^^^^ meta.function-call.arguments.powershell +# ^ punctuation.section.arguments.begin.powershell +# ^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell # ^ punctuation.definition.string.begin.powershell # ^ punctuation.definition.string.end.powershell -# ^ punctuation.section.group.end.powershell +# ^ punctuation.section.arguments.end.powershell "{1,10} {0,10} {2,10:x}" -f "First", "Second", 255 # ^^^^^^^^^^^^^^^^^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell From d313f4bccfb173580f743d110a200825ac3245ec Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Sat, 6 Dec 2025 18:33:23 -0500 Subject: [PATCH 39/81] Refactor variables so we can stop synchronizing the with/without members matches We also get to mark escaped chars in the full-unicode var names --- PowerShell.sublime-syntax | 102 ++++++++++++------------------- Tests/syntax_test_PowerShell.ps1 | 17 ++++++ 2 files changed, 57 insertions(+), 62 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index 54fefe4e..72cb907a 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -107,9 +107,9 @@ contexts: - include: commands - include: constants - - include: variables - include: types - include: hashtables + - include: variables - include: strings - include: script-blocks - include: escape-sequences @@ -537,86 +537,64 @@ contexts: ###[ VARIABLES ]############################################################### variables: + - match: (?=[$@](?:[{$^]|{{identifier_simple}})) + push: [members, expect-variable] + + variables-without-property: + - match: (?=[$@](?:[{$^]|{{identifier_simple}})) + push: [expect-variable] + + expect-variable: - match: (\$|@){{var_constants}} scope: support.constant.variable.powershell captures: 1: punctuation.definition.variable.powershell - push: members - match: (\$|@){{var_language}} scope: variable.language.powershell captures: 1: punctuation.definition.variable.powershell - push: members - - match: (\$|@)({{var_scope_mod}})(:){{identifier_simple}} - scope: variable.other.readwrite.powershell - captures: - 1: punctuation.definition.variable.powershell - 2: storage.modifier.scope.powershell - 3: punctuation.separator.sequence.powershell - push: members - - match: (\$|@)(\{)({{var_scope_mod}})(:){{identifier_special}}(\}) - scope: variable.other.readwrite.powershell + - match: (\$)(\{) captures: 1: punctuation.definition.variable.powershell 2: punctuation.section.interpolation.begin.powershell - 3: storage.modifier.scope.powershell - 4: punctuation.separator.sequence.powershell - 5: punctuation.section.interpolation.end.powershell - push: members - - match: (\$|@)(?:({{identifier_simple}})(:))?{{identifier_simple}} - scope: variable.other.readwrite.powershell - captures: - 1: punctuation.definition.variable.powershell - 2: support.variable.drive.powershell - 3: punctuation.separator.sequence.powershell - push: members - - match: (\$|@)(\{)(?:({{identifier_special}})(:))?{{identifier_special}}(\}) - scope: variable.other.readwrite.powershell + push: inside-variable-special-char + - match: (\$|@)(?!\{) captures: 1: punctuation.definition.variable.powershell 2: punctuation.section.interpolation.begin.powershell - 3: support.variable.drive.powershell - 4: punctuation.separator.sequence.powershell - 5: punctuation.section.interpolation.end.powershell - push: members + push: inside-variable-simple + - include: immediately-pop - variables-without-property: - - match: (\$|@){{var_constants}} - scope: support.constant.variable.powershell - captures: - 1: punctuation.definition.variable.powershell - - match: (\$|@){{var_language}} - scope: variable.language.powershell - captures: - 1: punctuation.definition.variable.powershell - - match: (\$|@)({{var_scope_mod}})(:){{identifier_simple}} - scope: variable.other.readwrite.powershell + inside-variable-simple: + - meta_include_prototype: false + - meta_scope: variable.other.readwrite.powershell + - match: ({{var_scope_mod}})(:) captures: - 1: punctuation.definition.variable.powershell - 2: storage.modifier.scope.powershell - 3: punctuation.separator.sequence.powershell - - match: (\$|@)(\{)({{var_scope_mod}})(:){{identifier_special}}(\}) - scope: variable.other.readwrite.powershell + 1: storage.modifier.scope.powershell + 2: punctuation.separator.sequence.powershell + - match: ({{identifier_simple}})(:) captures: - 1: punctuation.definition.variable.powershell - 2: punctuation.section.interpolation.begin.powershell - 3: storage.modifier.scope.powershell - 4: punctuation.separator.sequence.powershell - 5: punctuation.section.interpolation.end.powershell - - match: (\$|@)(?:({{identifier_simple}})(:))?{{identifier_simple}} - scope: variable.other.readwrite.powershell + 1: support.variable.drive.powershell + 2: punctuation.separator.sequence.powershell + - match: '{{identifier_simple}}' + - include: immediately-pop + + inside-variable-special-char: + - meta_include_prototype: false + - meta_scope: variable.other.readwrite.powershell + - match: '`.' + scope: constant.character.escape.powershell + - match: \} + scope: punctuation.section.interpolation.end.powershell + pop: 1 + - match: ({{var_scope_mod}})(:) captures: - 1: punctuation.definition.variable.powershell - 2: support.variable.drive.powershell - 3: punctuation.separator.sequence.powershell - - match: (\$|@)(\{)(?:({{identifier_special}})(:))?{{identifier_special}}(\}) - scope: variable.other.readwrite.powershell + 1: storage.modifier.scope.powershell + 2: punctuation.separator.sequence.powershell + - match: ({{identifier_simple}})(:) captures: - 1: punctuation.definition.variable.powershell - 2: punctuation.section.interpolation.begin.powershell - 3: support.variable.drive.powershell - 4: punctuation.separator.sequence.powershell - 5: punctuation.section.interpolation.end.powershell + 1: support.variable.drive.powershell + 2: punctuation.separator.sequence.powershell members: - match: (?=\.\.) diff --git a/Tests/syntax_test_PowerShell.ps1 b/Tests/syntax_test_PowerShell.ps1 index 8a70b5f4..58d6f1d3 100644 --- a/Tests/syntax_test_PowerShell.ps1 +++ b/Tests/syntax_test_PowerShell.ps1 @@ -183,6 +183,23 @@ throw "Do not run this file!" # ^ punctuation.definition.variable.powershell # ^ punctuation.section.interpolation.begin.powershell # ^ punctuation.section.interpolation.end.powershell + ${vari-able} +# ^^^^^^^^^^^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^ punctuation.section.interpolation.begin.powershell +# ^ punctuation.section.interpolation.end.powershell + ${var`iable} +# ^^^^^^^^^^^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^ punctuation.section.interpolation.begin.powershell +# ^^ constant.character.escape.powershell +# ^ punctuation.section.interpolation.end.powershell + ${variable`}} +# ^^^^^^^^^^^^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^ punctuation.section.interpolation.begin.powershell +# ^^ constant.character.escape.powershell +# ^ punctuation.section.interpolation.end.powershell ${script:variable} # ^^^^^^^^^^^^^^^^^^ variable.other.readwrite.powershell # ^ punctuation.definition.variable.powershell From fa04735f02b0eb3fe6859a67f3d1fad40148dca1 Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Sat, 6 Dec 2025 18:42:18 -0500 Subject: [PATCH 40/81] Rename variables-without-members --- PowerShell.sublime-syntax | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index 72cb907a..24fc24ea 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -367,7 +367,7 @@ contexts: - include: comma-separators - include: attributes - include: types - - include: variables-without-property + - include: variables-without-members attributes: - match: (\[)\s*({{attributes}}) @@ -540,7 +540,7 @@ contexts: - match: (?=[$@](?:[{$^]|{{identifier_simple}})) push: [members, expect-variable] - variables-without-property: + variables-without-members: - match: (?=[$@](?:[{$^]|{{identifier_simple}})) push: [expect-variable] @@ -788,8 +788,7 @@ contexts: - clear_scopes: 1 - meta_include_prototype: false - meta_scope: meta.interpolation.powershell - - include: variables-without-property - - include: variables + - include: variables-without-members - include: immediately-pop numbers: From ada344c57f8b53b603227860f2f9a7de1a19f055 Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Sat, 6 Dec 2025 18:53:42 -0500 Subject: [PATCH 41/81] fixup --- Tests/syntax_test_Function.ps1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Tests/syntax_test_Function.ps1 b/Tests/syntax_test_Function.ps1 index a76d4cec..a01002db 100644 --- a/Tests/syntax_test_Function.ps1 +++ b/Tests/syntax_test_Function.ps1 @@ -400,9 +400,9 @@ function Verb-Noun { $Param5 # <- punctuation.definition.variable # ^ variable.other.readwrite - ) -#^^^^^^^^ meta.function.powershell -# ^ punctuation.section.block.end.powershell + ) +#^^^^ meta.function.powershell +# ^ punctuation.section.block.end.powershell Begin #^^^^^^^^ meta.function.powershell From 90389010a16ea537cc3c36e42bcbf09e0ceb7269 Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Sat, 6 Dec 2025 19:54:07 -0500 Subject: [PATCH 42/81] Add context-sensitive classes --- PowerShell.sublime-syntax | 84 +++++++++------ Tests/syntax_test_Class.ps1 | 174 +++++++++++++++++++------------ Tests/syntax_test_PowerShell.ps1 | 87 +++++++++++----- 3 files changed, 223 insertions(+), 122 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index 24fc24ea..dca9a1e6 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -187,14 +187,6 @@ contexts: - match: \} scope: punctuation.section.braces.end.powershell pop: 1 - - # TODO: Fix classes, so this doesn't nest here. - - include: class-methods - - match: \b(?i:hidden|static)\b - scope: storage.modifier.powershell - - include: attributes - - # Back to normal stuff - include: statements ###[ COMMANDS ]################################################################ @@ -294,7 +286,7 @@ contexts: push: [function-body, function-inline-params, function-name] function-name: - - match: (?:(global|local|script|private):)?((?:\p{L}|\d|_|-|\.)+) + - match: (?:(global|local|script|private):)?({{identifier_function}}+) captures: 1: storage.modifier.scope.powershell 2: entity.name.function.powershell @@ -313,7 +305,7 @@ contexts: pop: 1 - include: comma-separators - include: types - - match: (\$)\p{L}[\p{L}\p{N}]* + - match: (\$){{identifier_simple}} scope: variable.parameter.powershell captures: 1: punctuation.definition.variable.begin.powershell @@ -330,8 +322,6 @@ contexts: scope: punctuation.section.block.end.powershell pop: 1 - - include: attributes - - match: \b(?i:(?:Dynamic)?Param){{kebab_break}} scope: keyword.declaration.parameter.powershell # This scope is not standard push: expect-param-context @@ -340,6 +330,7 @@ contexts: scope: keyword.context.block.powershell push: expect-function-context + - include: attributes - include: statements expect-function-context: @@ -515,24 +506,46 @@ contexts: ###[ CLASSES ]################################################################# classes: - - match: \b((?i:class))\s+([\w-]+)\b - captures: - 1: storage.type.class.powershell - 2: meta.class.powershell entity.name.class.powershell + - match: \b(?i)class(?=\s) + scope: keyword.declaration.class.powershell + push: [class-body, class-parents, class-name] - class-methods: - - match: ^(?:\s*)(?i)(hidden|static)?\s*(\[)((?!\d+|\.)[\p{L}\p{N}.]+)(\])\s*((?:\p{L}|\d|_|-|\.)+)\s*(?=\() - scope: meta.function.powershell - captures: - 1: storage.modifier.powershell - 2: punctuation.section.brackets.begin.powershell - 3: storage.type.powershell - 4: punctuation.section.brackets.end.powershell - 5: entity.name.function.powershell - push: - - match: (?=\() - pop: 1 - - include: comment-line + class-name: + - match: '{{identifier_simple}}' + scope: entity.name.class.powershell + pop: 1 + - include: else-pop + + class-parents: + - match: ':' + scope: punctuation.separator.type.powershell + push: inside-class-parents + - include: else-pop + + inside-class-parents: + - include: comma-separators + - match: '{{identifier_simple}}' + scope: entity.other.inherited-class.powershell + - include: else-pop + + class-body: + - meta_scope: meta.class.powershell + - match: \{ + scope: punctuation.section.block.begin.powershell + push: inside-class-body + - include: else-pop + + inside-class-body: + - match: \} + scope: punctuation.section.block.end.powershell + pop: 1 + - match: \b(?i:hidden|static)\b + scope: storage.modifier.powershell + - include: attributes + - include: types-without-members + - include: variables-without-members + - match: (?={{identifier_simple}}) + push: [function-body, function-inline-params, function-name] ###[ VARIABLES ]############################################################### @@ -603,6 +616,16 @@ contexts: scope: punctuation.accessor.dot.powershell - match: ::(?=\w) scope: punctuation.accessor.double-colon.powershell + - match: (new)(\() + captures: + 1: meta.function-call.powershell support.function.constructor.powershell + 2: meta.function-call.arguments.powershell punctuation.section.arguments.begin.powershell + push: + - meta_content_scope: meta.function-call.arguments.powershell + - match: \) + scope: meta.function-call.arguments.powershell punctuation.section.arguments.end.powershell + pop: 1 + - include: expressions - match: (\w+)(\() captures: 1: meta.function-call.powershell variable.function.powershell @@ -963,8 +986,9 @@ variables: # Variables # https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_variables - identifier_simple: '[\p{Lu}\p{Ll}\p{Lt}\p{Lm}\p{Lo}\p{Nd}_?]+' + identifier_simple: '[\p{L}\p{Nd}_?]+' identifier_special: '[^}]*[^}`]' + identifier_function: '[\p{L}\p{Nd}_.-]+' # https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_automatic_variables var_constants: |- \b(?xi: diff --git a/Tests/syntax_test_Class.ps1 b/Tests/syntax_test_Class.ps1 index f202d4d6..33e28ea8 100644 --- a/Tests/syntax_test_Class.ps1 +++ b/Tests/syntax_test_Class.ps1 @@ -6,93 +6,127 @@ using namespace system.management.automation # ^ punctuation.accessor.dot.powershell # ^ punctuation.accessor.dot.powershell +class Foo : Bar, Baz { } +#^^^^^^^^^^^^^^^^^^^^^^^^ meta.class.powershell +#^^^^ keyword.declaration.class.powershell +# ^^^ entity.name.class.powershell +# @@@ definition +# ^ punctuation.separator.type.powershell +# ^^^ entity.other.inherited-class.powershell +# @@@ reference +# ^ punctuation.separator.sequence.powershell +# ^^^ entity.other.inherited-class.powershell +# @@@ reference +# ^ punctuation.section.block.begin.powershell +# ^ punctuation.section.block.end.powershell + # Define a class class TypeName -# <- storage.type -# ^^^^^^^^ entity.name.class +#^^^^^^^^^^^^^ meta.class.powershell +#^^^^ keyword.declaration.class.powershell +# ^^^^^^^^ entity.name.class.powershell # @@@@@@@@ definition { # Property with validate set # <- punctuation.definition.comment # ^^^^^^^^^^^^^^^^^^^^^^^^^^ comment.line [ValidateSet("val1", "Val2")] - # ^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.attribute - # <- punctuation.section.brackets.begin - # ^^^^^^^^^^ support.function.attribute - # ^ punctuation.section.group.begin - # ^^^^^^ string.quoted.double - # ^ punctuation.separator - # ^^^^^^ string.quoted.double - # ^ punctuation.section.group.end - # ^ punctuation.section.brackets.end +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.class.powershell +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.attribute.powershell +# ^ punctuation.section.brackets.begin.powershell +# ^^^^^^^^^^^ support.function.attribute.powershell +# ^ punctuation.section.group.begin.powershell +# ^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^ punctuation.separator.sequence.powershell +# ^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^ punctuation.section.group.end.powershell +# ^ punctuation.section.brackets.end.powershell [string] $P1 - # <- punctuation.section.brackets.begin - # ^^^^^ storage.type - # ^ punctuation.section.brackets.end - # ^ punctuation.definition.variable - # ^^ variable.other.readwrite +#^^^^^^^^^^^^^^^ meta.class.powershell +# ^ punctuation.section.brackets.begin.powershell +# ^^^^^^ storage.type.powershell +# ^ punctuation.section.brackets.end.powershell +# ^^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell # Static property # <- punctuation.definition.comment # ^^^^^^^^^^^^^^^ comment.line static [hashtable] $P2 - #^^^^^ storage.modifier - # ^ punctuation.section.brackets.begin - # ^^^^^^^^^ storage.type - # ^ punctuation.section.brackets.end - # ^ punctuation.definition.variable - # ^^ variable.other.readwrite +#^^^^^^^^^^^^^^^^^^^^^^^^^ meta.class.powershell +# ^^^^^^ storage.modifier.powershell +# ^ punctuation.section.brackets.begin.powershell +# ^^^^^^^^^ storage.type.powershell +# ^ punctuation.section.brackets.end.powershell +# ^^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell # Hidden property does not show as result of Get-Member # <- punctuation.definition.comment # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ comment.line hidden [int] $P3 - #^^^^^ storage.modifier - # ^ punctuation.section.brackets.begin - # ^ storage.type - # ^ punctuation.section.brackets.end - # ^ punctuation.definition.variable - # ^^ variable.other.readwrite +#^^^^^^^^^^^^^^^^^^^ meta.class.powershell +# ^^^^^^ storage.modifier.powershell +# ^ punctuation.section.brackets.begin.powershell +# ^^^ storage.type.powershell +# ^ punctuation.section.brackets.end.powershell +# ^^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell # Constructor # <- punctuation.definition.comment # ^^^^^^^^^^^ comment.line TypeName ([string] $s) { - # ^ punctuation.section.group.begin - # ^ punctuation.section.brackets.begin - # ^^^^^^ storage.type - # ^ punctuation.section.brackets.end - # ^ punctuation.definition.variable - # ^ variable.other.readwrite - # ^ punctuation.section.group.end +#^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.class.powershell +# ^^^^^^^^^^^^^^^^^^^^^^^^ meta.function.powershell +# ^^^^^^^^ entity.name.function.powershell +# @@@@@@@@ definition +# ^ punctuation.section.parameters.begin.powershell +# ^ punctuation.section.brackets.begin.powershell +# ^^^^^^ storage.type.powershell +# ^ punctuation.section.brackets.end.powershell +# ^^ variable.parameter.powershell +# ^ punctuation.definition.variable.begin.powershell +# ^ punctuation.section.parameters.end.powershell +# ^ punctuation.section.block.begin.powershell $this.P1 = $s - # <- punctuation.definition.variable - # ^ variable.language - # ^^ variable.other.member - # ^ keyword.operator.assignment - # ^ punctuation.definition.variable - # ^ variable.other.readwrite +#^^^^^^^^^^^^^^^^^^^^ meta.class.powershell meta.function.powershell +# ^^^^^ variable.language.powershell +# ^ punctuation.definition.variable.powershell +# ^ punctuation.accessor.dot.powershell +# ^^ variable.other.member.powershell +# ^ keyword.operator.assignment.powershell +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell } # Static method # <- punctuation.definition.comment # ^^^^^^^^^^^^^ comment.line static [void] MemberMethod1([hashtable] $h) { - # <- storage.modifier - # ^ punctuation.section.brackets.begin - # ^^^^ storage.type - # ^ punctuation.section.brackets.end - # ^^^^^^^^^^^^^ entity.name.function - # @@@@@@@@@@@@@ definition - # ^ punctuation.section.group.begin - # ^ punctuation.section.brackets.begin - # ^^^^^^^^^ storage.type - # ^ punctuation.section.brackets.end - # ^ punctuation.definition.variable - # ^ variable.other.readwrite - # ^ punctuation.section.group.end +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.class.powershell +#^^^ meta.function.powershell +# ^^^^^^ storage.modifier.powershell +# ^ punctuation.section.brackets.begin.powershell +# ^^^^ storage.type.powershell +# ^ punctuation.section.brackets.end.powershell +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.function.powershell +# ^^^^^^^^^^^^^ entity.name.function.powershell +# @@@@@@@@@@@@@ definition +# ^ punctuation.section.parameters.begin.powershell +# ^ punctuation.section.brackets.begin.powershell +# ^^^^^^^^^ storage.type.powershell +# ^ punctuation.section.brackets.end.powershell +# ^^ variable.parameter.powershell +# ^ punctuation.definition.variable.begin.powershell +# ^ punctuation.section.parameters.end.powershell +# ^ punctuation.section.block.begin.powershell [TypeName]::P2 = $h -#^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.block.powershell meta.block.powershell +#^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.class.powershell meta.function.powershell # ^ punctuation.section.brackets.begin.powershell # ^^^^^^^^ support.type.powershell # ^ punctuation.section.brackets.end.powershell @@ -107,27 +141,29 @@ class TypeName # <- punctuation.definition.comment # ^^^^^^^^^^^^^^^ comment.line [int] MemberMethod2([int] $i) { -#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.block.powershell -#^^^^^^^^^^^^^^^^^^^^^^ meta.function.powershell +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.class.powershell +#^^^ meta.function.powershell # ^ punctuation.section.brackets.begin.powershell # ^^^ storage.type.powershell # ^ punctuation.section.brackets.end.powershell +# ^^^^^^^^^^^^^^^^^^^^^^^^^ meta.function.powershell # ^^^^^^^^^^^^^ entity.name.function.powershell # @@@@@@@@@@@@@ definition -# ^^^^^^^^^^ meta.group.powershell -# ^ punctuation.section.group.begin.powershell +# ^ punctuation.section.parameters.begin.powershell # ^ punctuation.section.brackets.begin.powershell # ^^^ storage.type.powershell # ^ punctuation.section.brackets.end.powershell -# ^^ variable.other.readwrite.powershell -# ^ punctuation.definition.variable.powershell -# ^ punctuation.section.group.end.powershell -# ^ meta.block.powershell punctuation.section.braces.begin.powershell +# ^^ variable.parameter.powershell +# ^ punctuation.definition.variable.begin.powershell +# ^ punctuation.section.parameters.end.powershell +# ^ punctuation.section.block.begin.powershell return $this.P3 - # <- keyword.control - # ^ punctuation.definition.variable - # ^^^^ variable.language - # ^^ variable.other.member +#^^^^^^^^^^^^^^^^^^^^^^ meta.class.powershell meta.function.powershell +# ^^^^^^ keyword.control.flow.return.powershell +# ^^^^^ variable.language.powershell +# ^ punctuation.definition.variable.powershell +# ^ punctuation.accessor.dot.powershell +# ^^ variable.other.member.powershell } } @@ -166,12 +202,15 @@ class Book { [string[]] $Tags # Default constructor Book() { $this.Init(@{}) } +# @@@@ definition # @@@@ reference # Convenience constructor from hashtable Book([hashtable]$Properties) { $this.Init($Properties) } +# @@@@ definition # @@@@ reference # Common constructor for title and author Book([string]$Title, [string]$Author) { +# @@@@ definition $this.Init(@{Title = $Title; Author = $Author }) # @@@@ reference } @@ -336,6 +375,7 @@ class BookList { } # Find every book matching the filtering scriptblock. static [Book[]] FindAll([scriptblock]$Predicate) { +# @@@@@@@ definition [BookList]::Initialize() # @@@@@@@@@@ reference return [BookList]::Books.FindAll($Predicate) diff --git a/Tests/syntax_test_PowerShell.ps1 b/Tests/syntax_test_PowerShell.ps1 index 58d6f1d3..94da686d 100644 --- a/Tests/syntax_test_PowerShell.ps1 +++ b/Tests/syntax_test_PowerShell.ps1 @@ -1246,20 +1246,32 @@ function Verb-Noun # Class class Vehicle { -# <- storage.type.class -# ^^^^^^^ entity.name.class +#^^^^^^^^^^^^^^ meta.class.powershell +#^^^^ keyword.declaration.class.powershell +# ^^^^^^^ entity.name.class.powershell # @@@@@@@ definition -# ^ punctuation.section.braces.begin +# ^ punctuation.section.block.begin.powershell Vehicle() {} -# ^ punctuation.section.group.begin -# ^ punctuation.section.group.end -# ^ punctuation.section.braces.begin -# ^ punctuation.section.braces.end +#^^^^^^^^^^^^^^^ meta.class.powershell +# ^^^^^^^^^^^^ meta.function.powershell +# ^^^^^^^ entity.name.function.powershell +# @@@@@@@ definition +# ^ punctuation.section.parameters.begin.powershell +# ^ punctuation.section.parameters.end.powershell +# ^ punctuation.section.block.begin.powershell +# ^ punctuation.section.block.end.powershell Vehicle([string]$Owner) { -# ^ storage.type -# ^ punctuation.definition.variable -# ^ variable.other.readwrite -# ^ punctuation.section.braces.begin +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.class.powershell meta.function.powershell +# ^^^^^^^ entity.name.function.powershell +# @@@@@@@ definition +# ^ punctuation.section.parameters.begin.powershell +# ^ punctuation.section.brackets.begin.powershell +# ^^^^^^ storage.type.powershell +# ^ punctuation.section.brackets.end.powershell +# ^^^^^^ variable.parameter.powershell +# ^ punctuation.definition.variable.begin.powershell +# ^ punctuation.section.parameters.end.powershell +# ^ punctuation.section.block.begin.powershell $this.Owner = $Owner } @@ -1277,29 +1289,54 @@ class Vehicle { # ^ variable.other.readwrite [void]Drive([int]$NumberOfMiles) { -# ^^^^ storage.type -# ^^^^^ meta.function entity.name.function +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.class.powershell +# ^ punctuation.section.brackets.begin.powershell +# ^^^^ storage.type.powershell +# ^ punctuation.section.brackets.end.powershell +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.function.powershell +# ^^^^^ entity.name.function.powershell # @@@@@ definition -# ^^^ storage.type -# ^ punctuation.definition.variable -# ^ variable.other.readwrite +# ^ punctuation.section.parameters.begin.powershell +# ^ punctuation.section.brackets.begin.powershell +# ^^^ storage.type.powershell +# ^ punctuation.section.brackets.end.powershell +# ^^^^^^^^^^^^^^ variable.parameter.powershell +# ^ punctuation.definition.variable.begin.powershell +# ^ punctuation.section.parameters.end.powershell +# ^ punctuation.section.block.begin.powershell $this.Mileage += $NumberOfMiles -# ^^^^^ variable.language -# ^ punctuation.definition.variable -# ^^^^^^^ variable.other.member -# ^^ keyword.operator.assignment +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.class.powershell meta.function.powershell +# ^^^^^ variable.language.powershell +# ^ punctuation.definition.variable.powershell +# ^ punctuation.accessor.dot.powershell +# ^^^^^^^ variable.other.member.powershell +# ^^ keyword.operator.assignment.powershell +# ^^^^^^^^^^^^^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell } - # <- punctuation.section.braces.end +#^^^^ meta.class.powershell meta.function.powershell +# ^ punctuation.section.block.end.powershell + static [System.Array] GetAvailableColors() { -# ^^^^^^^^^^^^^^^^^^ meta.function entity.name.function +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.class.powershell +#^^^ meta.function.powershell +# ^^^^^^ storage.modifier.powershell +# ^ punctuation.section.brackets.begin.powershell +# ^^^^^^^ meta.generic-name.powershell +# ^ punctuation.accessor.dot.powershell +# ^^^^^ support.type.powershell +# ^ punctuation.section.brackets.end.powershell +# ^^^^^^^^^^^^^^^^^^^^^^ meta.function.powershell +# ^^^^^^^^^^^^^^^^^^ entity.name.function.powershell # @@@@@@@@@@@@@@@@@@ definition -# ^^^^^^ meta.function storage.modifier -# ^^^^^^^^^^^ meta.function storage.type +# ^ punctuation.section.parameters.begin.powershell +# ^ punctuation.section.parameters.end.powershell +# ^ punctuation.section.block.begin.powershell return 'yellow', 'red' } } -# <- punctuation.section.braces.end +# <- punctuation.section.block.end $fiat.Drive(42) # ^^^^^ meta.function-call From 9c8fbe76b4865cf8ef0436801900485d4ec0b9a2 Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Sat, 6 Dec 2025 19:58:26 -0500 Subject: [PATCH 43/81] Name the anonymous member contexts --- PowerShell.sublime-syntax | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index dca9a1e6..d3e09c25 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -620,34 +620,33 @@ contexts: captures: 1: meta.function-call.powershell support.function.constructor.powershell 2: meta.function-call.arguments.powershell punctuation.section.arguments.begin.powershell - push: - - meta_content_scope: meta.function-call.arguments.powershell - - match: \) - scope: meta.function-call.arguments.powershell punctuation.section.arguments.end.powershell - pop: 1 - - include: expressions + push: inside-function-call-arguments - match: (\w+)(\() captures: 1: meta.function-call.powershell variable.function.powershell 2: meta.function-call.arguments.powershell punctuation.section.arguments.begin.powershell - push: - - meta_content_scope: meta.function-call.arguments.powershell - - match: \) - scope: meta.function-call.arguments.powershell punctuation.section.arguments.end.powershell - pop: 1 - - include: expressions + push: inside-function-call-arguments - match: \w+ scope: variable.other.member.powershell - match: \[ scope: punctuation.section.brackets.begin.powershell - push: - - meta_scope: meta.brackets.indexer.powershell - - match: \] - scope: punctuation.section.brackets.end.powershell - pop: 1 - - include: expressions + push: inside-indexer - include: immediately-pop + inside-function-call-arguments: + - meta_content_scope: meta.function-call.arguments.powershell + - match: \) + scope: meta.function-call.arguments.powershell punctuation.section.arguments.end.powershell + pop: 1 + - include: expressions + + inside-indexer: + - meta_scope: meta.brackets.indexer.powershell + - match: \] + scope: punctuation.section.brackets.end.powershell + pop: 1 + - include: expressions + ###[ GROUPS ]################################################################## groups: From 98fa78d1832f04ce72ac742aaaae840271fe3ff6 Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Sat, 6 Dec 2025 20:10:12 -0500 Subject: [PATCH 44/81] Organize major syntax sections --- PowerShell.sublime-syntax | 463 +++++++++++++++++++------------------- 1 file changed, 232 insertions(+), 231 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index d3e09c25..b7a62360 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -1,6 +1,7 @@ %YAML 1.2 --- # http://www.sublimetext.com/docs/syntax.html +# https://learn.microsoft.com/en-us/powershell/ name: PowerShell scope: source.powershell version: 2 @@ -139,43 +140,61 @@ contexts: - include: operators - include: parameters - parameters: - # Flags/Options/Parameters - - match: \B(--?|[/+])\p{L}(?:[\w-]*\w)? - scope: variable.parameter.option.powershell +###[ GROUPS ]################################################################## + + groups: + - match: \( + scope: punctuation.section.group.begin.powershell + push: + - meta_scope: meta.group.powershell + - match: \) + scope: punctuation.section.group.end.powershell + set: members + - include: attributes + - include: expressions + + arrays: + - match: (@)(\() captures: - 1: punctuation.definition.parameter.powershell + 1: keyword.other.array.begin.powershell + 2: punctuation.section.group.begin.powershell + push: + - meta_scope: meta.group.array-expression.powershell + - match: \) + scope: punctuation.section.group.end.powershell + pop: 1 + - include: expressions - requires-directives: - - match: (#)((?i:requires))\s + hashtables: + - match: (@)(\{) captures: - 1: punctuation.definition.keyword.powershell - 2: keyword.control.import.require.powershell + 1: keyword.other.hashtable.begin.powershell + 2: punctuation.section.braces.begin.powershell push: - - meta_scope: meta.requires.powershell - - include: pop-eol - - include: hashtables - - match: (-)(?i:Modules|PSSnapin|RunAsAdministrator|ShellId|Version) - scope: variable.parameter.option.powershell + - meta_scope: meta.hashtable.powershell + - match: \} + scope: punctuation.section.braces.end.powershell + pop: 1 + - match: \b(['"]?)(\w+)(['"]?)\s*(=)\s* + scope: meta.hashtable.assignment.powershell captures: - 1: punctuation.definition.variable.powershell - - match: ',' - scope: punctuation.separator.powershell + 1: punctuation.definition.string.begin.powershell + 2: variable.other.readwrite.powershell + 3: punctuation.definition.string.end.powershell + 4: keyword.operator.assignment.powershell + - include: expressions - regions: - - match: ^\s*((#)\s*(region\b)(?:\s*(\S.*))?(\n?)) - captures: - 1: comment.line.powershell - 2: punctuation.definition.comment.powershell - 3: keyword.other.region.begin.powershell - 4: meta.toc-list.powershell entity.name.section.powershell - 5: meta.fold.begin.powershell - - match: ^\s*((#)\s*(endregion\b).*(\n?)) + subexpressions: + - match: (\$)(\() captures: - 1: comment.line.powershell - 2: punctuation.definition.comment.powershell - 3: keyword.other.region.end.powershell - 4: meta.fold.end.powershell + 1: keyword.other.variable.definition.powershell + 2: punctuation.section.group.begin.powershell + push: + - meta_scope: meta.group.complex.subexpression.powershell + - match: \) + scope: punctuation.section.group.end.powershell + pop: 1 + - include: expressions script-blocks: - match: (%)?(\{) @@ -243,7 +262,30 @@ contexts: - include: expressions -###[ USINGS ]################################################################## + parameters: + # Flags/Options/Parameters + - match: \B(--?|[/+])\p{L}(?:[\w-]*\w)? + scope: variable.parameter.option.powershell + captures: + 1: punctuation.definition.parameter.powershell + +###[ DIRECTIVES ]############################################################## + + requires-directives: + - match: (#)((?i:requires))\s + captures: + 1: punctuation.definition.keyword.powershell + 2: keyword.control.import.require.powershell + push: + - meta_scope: meta.requires.powershell + - include: pop-eol + - include: hashtables + - match: (-)(?i:Modules|PSSnapin|RunAsAdministrator|ShellId|Version) + scope: variable.parameter.option.powershell + captures: + 1: punctuation.definition.variable.powershell + - match: ',' + scope: punctuation.separator.powershell using-directives: - match: \b(?i)using(?=\s) @@ -277,6 +319,50 @@ contexts: - match: \p{L}[\p{L}\p{N}]+ scope: meta.path.powershell support.type.powershell +###[ CLASSES ]################################################################# + + classes: + - match: \b(?i)class(?=\s) + scope: keyword.declaration.class.powershell + push: [class-body, class-parents, class-name] + + class-name: + - match: '{{identifier_simple}}' + scope: entity.name.class.powershell + pop: 1 + - include: else-pop + + class-parents: + - match: ':' + scope: punctuation.separator.type.powershell + push: inside-class-parents + - include: else-pop + + inside-class-parents: + - include: comma-separators + - match: '{{identifier_simple}}' + scope: entity.other.inherited-class.powershell + - include: else-pop + + class-body: + - meta_scope: meta.class.powershell + - match: \{ + scope: punctuation.section.block.begin.powershell + push: inside-class-body + - include: else-pop + + inside-class-body: + - match: \} + scope: punctuation.section.block.end.powershell + pop: 1 + - match: \b(?i:hidden|static)\b + scope: storage.modifier.powershell + - include: attributes + - include: types-without-members + - include: variables-without-members + - match: (?={{identifier_simple}}) + push: [function-body, function-inline-params, function-name] + ###[ FUNCTIONS ]############################################################### functions: @@ -386,6 +472,106 @@ contexts: 2: keyword.operator.assignment.powershell - include: expressions +###[ VARIABLES ]############################################################### + + variables: + - match: (?=[$@](?:[{$^]|{{identifier_simple}})) + push: [members, expect-variable] + + variables-without-members: + - match: (?=[$@](?:[{$^]|{{identifier_simple}})) + push: [expect-variable] + + expect-variable: + - match: (\$|@){{var_constants}} + scope: support.constant.variable.powershell + captures: + 1: punctuation.definition.variable.powershell + - match: (\$|@){{var_language}} + scope: variable.language.powershell + captures: + 1: punctuation.definition.variable.powershell + - match: (\$)(\{) + captures: + 1: punctuation.definition.variable.powershell + 2: punctuation.section.interpolation.begin.powershell + push: inside-variable-special-char + - match: (\$|@)(?!\{) + captures: + 1: punctuation.definition.variable.powershell + 2: punctuation.section.interpolation.begin.powershell + push: inside-variable-simple + - include: immediately-pop + + inside-variable-simple: + - meta_include_prototype: false + - meta_scope: variable.other.readwrite.powershell + - match: ({{var_scope_mod}})(:) + captures: + 1: storage.modifier.scope.powershell + 2: punctuation.separator.sequence.powershell + - match: ({{identifier_simple}})(:) + captures: + 1: support.variable.drive.powershell + 2: punctuation.separator.sequence.powershell + - match: '{{identifier_simple}}' + - include: immediately-pop + + inside-variable-special-char: + - meta_include_prototype: false + - meta_scope: variable.other.readwrite.powershell + - match: '`.' + scope: constant.character.escape.powershell + - match: \} + scope: punctuation.section.interpolation.end.powershell + pop: 1 + - match: ({{var_scope_mod}})(:) + captures: + 1: storage.modifier.scope.powershell + 2: punctuation.separator.sequence.powershell + - match: ({{identifier_simple}})(:) + captures: + 1: support.variable.drive.powershell + 2: punctuation.separator.sequence.powershell + + members: + - match: (?=\.\.) + pop: 1 + - match: \.(?=\w) + scope: punctuation.accessor.dot.powershell + - match: ::(?=\w) + scope: punctuation.accessor.double-colon.powershell + - match: (new)(\() + captures: + 1: meta.function-call.powershell support.function.constructor.powershell + 2: meta.function-call.arguments.powershell punctuation.section.arguments.begin.powershell + push: inside-function-call-arguments + - match: (\w+)(\() + captures: + 1: meta.function-call.powershell variable.function.powershell + 2: meta.function-call.arguments.powershell punctuation.section.arguments.begin.powershell + push: inside-function-call-arguments + - match: \w+ + scope: variable.other.member.powershell + - match: \[ + scope: punctuation.section.brackets.begin.powershell + push: inside-indexer + - include: immediately-pop + + inside-function-call-arguments: + - meta_content_scope: meta.function-call.arguments.powershell + - match: \) + scope: meta.function-call.arguments.powershell punctuation.section.arguments.end.powershell + pop: 1 + - include: expressions + + inside-indexer: + - meta_scope: meta.brackets.indexer.powershell + - match: \] + scope: punctuation.section.brackets.end.powershell + pop: 1 + - include: expressions + ###[ TYPES ]################################################################### types: @@ -503,206 +689,6 @@ contexts: # - match: <+ # scope: invalid.illegal.powershell -###[ CLASSES ]################################################################# - - classes: - - match: \b(?i)class(?=\s) - scope: keyword.declaration.class.powershell - push: [class-body, class-parents, class-name] - - class-name: - - match: '{{identifier_simple}}' - scope: entity.name.class.powershell - pop: 1 - - include: else-pop - - class-parents: - - match: ':' - scope: punctuation.separator.type.powershell - push: inside-class-parents - - include: else-pop - - inside-class-parents: - - include: comma-separators - - match: '{{identifier_simple}}' - scope: entity.other.inherited-class.powershell - - include: else-pop - - class-body: - - meta_scope: meta.class.powershell - - match: \{ - scope: punctuation.section.block.begin.powershell - push: inside-class-body - - include: else-pop - - inside-class-body: - - match: \} - scope: punctuation.section.block.end.powershell - pop: 1 - - match: \b(?i:hidden|static)\b - scope: storage.modifier.powershell - - include: attributes - - include: types-without-members - - include: variables-without-members - - match: (?={{identifier_simple}}) - push: [function-body, function-inline-params, function-name] - -###[ VARIABLES ]############################################################### - - variables: - - match: (?=[$@](?:[{$^]|{{identifier_simple}})) - push: [members, expect-variable] - - variables-without-members: - - match: (?=[$@](?:[{$^]|{{identifier_simple}})) - push: [expect-variable] - - expect-variable: - - match: (\$|@){{var_constants}} - scope: support.constant.variable.powershell - captures: - 1: punctuation.definition.variable.powershell - - match: (\$|@){{var_language}} - scope: variable.language.powershell - captures: - 1: punctuation.definition.variable.powershell - - match: (\$)(\{) - captures: - 1: punctuation.definition.variable.powershell - 2: punctuation.section.interpolation.begin.powershell - push: inside-variable-special-char - - match: (\$|@)(?!\{) - captures: - 1: punctuation.definition.variable.powershell - 2: punctuation.section.interpolation.begin.powershell - push: inside-variable-simple - - include: immediately-pop - - inside-variable-simple: - - meta_include_prototype: false - - meta_scope: variable.other.readwrite.powershell - - match: ({{var_scope_mod}})(:) - captures: - 1: storage.modifier.scope.powershell - 2: punctuation.separator.sequence.powershell - - match: ({{identifier_simple}})(:) - captures: - 1: support.variable.drive.powershell - 2: punctuation.separator.sequence.powershell - - match: '{{identifier_simple}}' - - include: immediately-pop - - inside-variable-special-char: - - meta_include_prototype: false - - meta_scope: variable.other.readwrite.powershell - - match: '`.' - scope: constant.character.escape.powershell - - match: \} - scope: punctuation.section.interpolation.end.powershell - pop: 1 - - match: ({{var_scope_mod}})(:) - captures: - 1: storage.modifier.scope.powershell - 2: punctuation.separator.sequence.powershell - - match: ({{identifier_simple}})(:) - captures: - 1: support.variable.drive.powershell - 2: punctuation.separator.sequence.powershell - - members: - - match: (?=\.\.) - pop: 1 - - match: \.(?=\w) - scope: punctuation.accessor.dot.powershell - - match: ::(?=\w) - scope: punctuation.accessor.double-colon.powershell - - match: (new)(\() - captures: - 1: meta.function-call.powershell support.function.constructor.powershell - 2: meta.function-call.arguments.powershell punctuation.section.arguments.begin.powershell - push: inside-function-call-arguments - - match: (\w+)(\() - captures: - 1: meta.function-call.powershell variable.function.powershell - 2: meta.function-call.arguments.powershell punctuation.section.arguments.begin.powershell - push: inside-function-call-arguments - - match: \w+ - scope: variable.other.member.powershell - - match: \[ - scope: punctuation.section.brackets.begin.powershell - push: inside-indexer - - include: immediately-pop - - inside-function-call-arguments: - - meta_content_scope: meta.function-call.arguments.powershell - - match: \) - scope: meta.function-call.arguments.powershell punctuation.section.arguments.end.powershell - pop: 1 - - include: expressions - - inside-indexer: - - meta_scope: meta.brackets.indexer.powershell - - match: \] - scope: punctuation.section.brackets.end.powershell - pop: 1 - - include: expressions - -###[ GROUPS ]################################################################## - - groups: - - match: \( - scope: punctuation.section.group.begin.powershell - push: - - meta_scope: meta.group.powershell - - match: \) - scope: punctuation.section.group.end.powershell - set: members - - include: attributes - - include: expressions - - arrays: - - match: (@)(\() - captures: - 1: keyword.other.array.begin.powershell - 2: punctuation.section.group.begin.powershell - push: - - meta_scope: meta.group.array-expression.powershell - - match: \) - scope: punctuation.section.group.end.powershell - pop: 1 - - include: expressions - - hashtables: - - match: (@)(\{) - captures: - 1: keyword.other.hashtable.begin.powershell - 2: punctuation.section.braces.begin.powershell - push: - - meta_scope: meta.hashtable.powershell - - match: \} - scope: punctuation.section.braces.end.powershell - pop: 1 - - match: \b(['"]?)(\w+)(['"]?)\s*(=)\s* - scope: meta.hashtable.assignment.powershell - captures: - 1: punctuation.definition.string.begin.powershell - 2: variable.other.readwrite.powershell - 3: punctuation.definition.string.end.powershell - 4: keyword.operator.assignment.powershell - - include: expressions - - subexpressions: - - match: (\$)(\() - captures: - 1: keyword.other.variable.definition.powershell - 2: punctuation.section.group.begin.powershell - push: - - meta_scope: meta.group.complex.subexpression.powershell - - match: \) - scope: punctuation.section.group.end.powershell - pop: 1 - - include: expressions - ###[ CONSTANTS ]############################################################### constants: @@ -920,6 +906,21 @@ contexts: - include: pop-eol - include: comment-embedded-docs + regions: + - match: ^\s*((#)\s*(region\b)(?:\s*(\S.*))?(\n?)) + captures: + 1: comment.line.powershell + 2: punctuation.definition.comment.powershell + 3: keyword.other.region.begin.powershell + 4: meta.toc-list.powershell entity.name.section.powershell + 5: meta.fold.begin.powershell + - match: ^\s*((#)\s*(endregion\b).*(\n?)) + captures: + 1: comment.line.powershell + 2: punctuation.definition.comment.powershell + 3: keyword.other.region.end.powershell + 4: meta.fold.end.powershell + ###[ COMPONENTS ]############################################################## comma-separators: From be4206802b69a82308d4eadad15a143f348b4c10 Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Sat, 6 Dec 2025 20:33:40 -0500 Subject: [PATCH 45/81] Change C# context to use indicators Rather than triggering on Add-Type --- PowerShell.sublime-syntax | 64 +++++++++++++++++++--------------- Tests/syntax_test_Add-Type.ps1 | 24 ------------- Tests/syntax_test_strings.ps1 | 15 ++++++++ 3 files changed, 50 insertions(+), 53 deletions(-) delete mode 100644 Tests/syntax_test_Add-Type.ps1 diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index b7a62360..42661368 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -211,7 +211,6 @@ contexts: ###[ COMMANDS ]################################################################ commands: - - include: commands-add-type - include: commands-verb-noun - include: commands-reserved - include: script-invocation @@ -236,32 +235,6 @@ contexts: - match: \b[\w.\\/-]+\.(?i:exe|com|cmd|bat|ps1)\b scope: variable.function.powershell - commands-add-type: - - match: \b(?i:Add-Type)\b - scope: support.function.powershell - push: inside-add-type - - inside-add-type: - - include: pop-eol - - - match: '@"' - scope: meta.string.interpolated.powershell string.quoted.double.powershell punctuation.definition.string.begin.powershell - embed: scope:source.cs - embed_scope: meta.string.interpolated.powershell string.quoted.double.powershell source.cs.embedded - escape: ("@) - escape_captures: - 1: meta.string.powershell string.quoted.double.powershell punctuation.definition.string.end.powershell - - - match: "@'" - scope: meta.string.powershell string.quoted.single.powershell punctuation.definition.string.begin.powershell - embed: scope:source.cs - embed_scope: meta.string.powershell string.quoted.single.powershell source.cs.embedded - escape: ('@) - escape_captures: - 1: meta.string.powershell string.quoted.single.powershell punctuation.definition.string.end.powershell - - - include: expressions - parameters: # Flags/Options/Parameters - match: \B(--?|[/+])\p{L}(?:[\w-]*\w)? @@ -754,7 +727,20 @@ contexts: single-quoted-heredoc-strings: - match: \@'(?=$) scope: punctuation.definition.string.begin.powershell - push: inside-single-quoted-heredoc-string + push: + - inside-single-quoted-heredoc-string + - inside-single-quoted-heredoc-string.syntax + + inside-single-quoted-heredoc-string.syntax: + - meta_include_prototype: false + - match: (?={{csharp_indicator}}) + set: scope:source.cs + with_prototype: + - match: (?=^'@) + pop: 1 + - match: "''" + scope: constant.character.escape.powershell + - include: else-pop inside-single-quoted-heredoc-string: - meta_include_prototype: false @@ -768,7 +754,9 @@ contexts: double-quoted-heredoc-strings: - match: \@"(?=$) scope: punctuation.definition.string.begin.powershell - push: inside-double-quoted-heredoc-string + push: + - inside-double-quoted-heredoc-string + - inside-double-quoted-heredoc-string.syntax inside-double-quoted-heredoc-string: - meta_include_prototype: false @@ -779,6 +767,16 @@ contexts: - include: escape-sequences - include: string-interpolations + inside-double-quoted-heredoc-string.syntax: + - meta_include_prototype: false + - match: (?={{csharp_indicator}}) + set: scope:source.cs + with_prototype: + - match: (?=^"@) + pop: 1 + - include: escape-sequences + - include: else-pop + string-interpolations: - match: \$\( scope: punctuation.section.interpolation.begin.powershell @@ -1062,3 +1060,11 @@ variables: Alias | Cmdlet | HelpFile | Function | Provider | General | FAQ | Glossary | ScriptCommand | ExternalScript | Filter | All ) + + # Strings + csharp_indicator: |- + (?x: \s* (?: + using\s+System[.;] + | public\s+class\s+ + | \[DllImport\b + )) diff --git a/Tests/syntax_test_Add-Type.ps1 b/Tests/syntax_test_Add-Type.ps1 deleted file mode 100644 index 0107efb2..00000000 --- a/Tests/syntax_test_Add-Type.ps1 +++ /dev/null @@ -1,24 +0,0 @@ -# SYNTAX TEST "Packages/PowerShell/PowerShell.sublime-syntax" - - - Add-Type -Language CSharp @" -# ^^^^^^^^ support.function.powershell -# ^^^^^^^^^ variable.parameter.option.powershell -# ^ punctuation.definition.parameter.powershell -# ^^ meta.string.interpolated.powershell string.quoted.double.powershell punctuation.definition.string.begin.powershell - using System; -#^^^^^^^^^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell source.cs.embedded -# ^^^^^ keyword.control.import.cs -# ^^^^^^ meta.path.cs - using System.Runtime.InteropServices; - public class ClassGetForegroundWindow { -#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell source.cs.embedded -# ^^^^^^ storage.modifier.access.cs -# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.class.cs -# ^^^^^^^^^^^^^^^^^^^^^^^^ entity.name.class.cs -# ^ meta.class.body.cs meta.block.cs punctuation.section.block.begin.cs - [DllImport("user32.dll")] - public static extern IntPtr GetForegroundWindow(); - } -"@ -#^ meta.string.powershell string.quoted.double.powershell punctuation.definition.string.end.powershell - source.cs diff --git a/Tests/syntax_test_strings.ps1 b/Tests/syntax_test_strings.ps1 index 2b06b7ca..05690d37 100644 --- a/Tests/syntax_test_strings.ps1 +++ b/Tests/syntax_test_strings.ps1 @@ -50,6 +50,13 @@ '@ #^ meta.string.powershell string.quoted.single.heredoc.powershell punctuation.definition.string.end.powershell + @' + using System; +#^^^^^^^^^^^^^^^^ meta.string.powershell string.quoted.single.heredoc.powershell source.cs +# ^^^^^ keyword.control.import.cs +# ^^^^^^ meta.path.cs +# ^ punctuation.terminator +'@ ###[ Double Quoted Strings ]################################################### @@ -192,6 +199,14 @@ # ^^ constant.character.escape.powershell # ^ punctuation.definition.string.end.powershell + @" + using System; +#^^^^^^^^^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.heredoc.powershell source.cs +# ^^^^^ keyword.control.import.cs +# ^^^^^^ meta.path.cs +# ^ punctuation.terminator +"@ + ###[ String Formatting ]####################################################### From 7daa98aa66a92f9852a400e9913fef3eae114c5c Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Sat, 6 Dec 2025 20:51:15 -0500 Subject: [PATCH 46/81] Add labels --- PowerShell.sublime-syntax | 41 ++++++++++++++++++++------------ Tests/syntax_test_PowerShell.ps1 | 4 ++++ 2 files changed, 30 insertions(+), 15 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index 42661368..7148de50 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -103,9 +103,12 @@ contexts: scope: keyword.declaration.variable.powershell expressions: + # Meta + - include: labels - include: regions - include: requires-directives + # Normal code - include: commands - include: constants - include: types @@ -854,6 +857,29 @@ contexts: 2: constant.numeric.suffix.powershell push: members +###[ LABELS ]################################################################## + + labels: + - match: ^\s*((:){{identifier_simple}}) + captures: + 1: entity.name.label.powershell + 2: punctuation.definition.label.powershell + + regions: + - match: ^\s*((#)\s*(region\b)(?:\s*(\S.*))?(\n?)) + captures: + 1: comment.line.powershell + 2: punctuation.definition.comment.powershell + 3: keyword.other.region.begin.powershell + 4: meta.toc-list.powershell entity.name.section.powershell + 5: meta.fold.begin.powershell + - match: ^\s*((#)\s*(endregion\b).*(\n?)) + captures: + 1: comment.line.powershell + 2: punctuation.definition.comment.powershell + 3: keyword.other.region.end.powershell + 4: meta.fold.end.powershell + ###[ COMMENTS ]################################################################ comments: @@ -904,21 +930,6 @@ contexts: - include: pop-eol - include: comment-embedded-docs - regions: - - match: ^\s*((#)\s*(region\b)(?:\s*(\S.*))?(\n?)) - captures: - 1: comment.line.powershell - 2: punctuation.definition.comment.powershell - 3: keyword.other.region.begin.powershell - 4: meta.toc-list.powershell entity.name.section.powershell - 5: meta.fold.begin.powershell - - match: ^\s*((#)\s*(endregion\b).*(\n?)) - captures: - 1: comment.line.powershell - 2: punctuation.definition.comment.powershell - 3: keyword.other.region.end.powershell - 4: meta.fold.end.powershell - ###[ COMPONENTS ]############################################################## comma-separators: diff --git a/Tests/syntax_test_PowerShell.ps1 b/Tests/syntax_test_PowerShell.ps1 index 94da686d..52001f50 100644 --- a/Tests/syntax_test_PowerShell.ps1 +++ b/Tests/syntax_test_PowerShell.ps1 @@ -80,6 +80,10 @@ using namespace System.Management.Automation # ^ meta.requires meta.hashtable # ^^^^^^^^^ meta.requires meta.hashtable string.quoted.double + :label1 +# ^^^^^^^ entity.name.label.powershell +# ^ punctuation.definition.label.powershell + throw "Do not run this file!" # <- keyword.control # ^^^^^^^^^^^^^^^^^^^^^^^ string.quoted.double From 7d179b3797e872128abfab16115f7080b850e3d1 Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Sun, 7 Dec 2025 12:41:57 -0500 Subject: [PATCH 47/81] Move some reserved words to a not-in-use section --- PowerShell.sublime-syntax | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index 7148de50..e951b07b 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -98,10 +98,6 @@ contexts: - match: \b(?i:where(?!-object)){{kebab_break}} scope: keyword.control.conditional.select.powershell - # Declarations - - match: \b(?i:var){{kebab_break}} - scope: keyword.declaration.variable.powershell - expressions: # Meta - include: labels @@ -128,6 +124,13 @@ contexts: scope: variable.other.object.powershell push: members + # "Reserved for future use" + # https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_reserved_words + - match: \b(?i:define|from){{kebab_break}} + scope: keyword.control.powershell + - match: \b(?i:var){{kebab_break}} + scope: keyword.declaration.variable.powershell + # Uncategorized keywords - match: \b(?i:data|default|define|from|in|inlinescript|parallel|sequence){{kebab_break}} scope: keyword.control.powershell From e014fc7e848b43d8190c8afa60be0054932ddf7f Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Sun, 7 Dec 2025 12:43:00 -0500 Subject: [PATCH 48/81] Add data sections --- PowerShell.sublime-syntax | 34 ++++++++++++++++++++++++++++++-- Tests/syntax_test_PowerShell.ps1 | 25 +++++++++++++++++++++++ 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index e951b07b..154c6ffe 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -105,15 +105,18 @@ contexts: - include: requires-directives # Normal code + - include: escape-sequences + - include: commands - include: constants - include: types - include: hashtables - include: variables - include: strings - - include: script-blocks - - include: escape-sequences - include: numbers + - include: data-blocks + + - include: script-blocks - include: groups - include: arrays - include: subexpressions @@ -668,6 +671,33 @@ contexts: # - match: <+ # scope: invalid.illegal.powershell +###[ DATA BLOCK ]############################################################## + + data-blocks: + - match: \b(?i:data){{kebab_break}} + scope: keyword.control.context.powershell + push: [data-block-body, data-block-name] + + data-block-name: + - match: '{{identifier_simple}}' + scope: entity.name.section.powershell + pop: 1 + - include: else-pop + + data-block-body: + - meta_scope: meta.block.data.powershell + - match: \{ + scope: punctuation.section.block.begin.powershell + push: inside-data-block + - include: else-pop + + inside-data-block: + - match: \} + scope: punctuation.section.block.end.powershell + pop: 1 + # Data sections use a subset of Pwsh, but we don't distinguish yet. + - include: statements + ###[ CONSTANTS ]############################################################### constants: diff --git a/Tests/syntax_test_PowerShell.ps1 b/Tests/syntax_test_PowerShell.ps1 index 52001f50..85863edf 100644 --- a/Tests/syntax_test_PowerShell.ps1 +++ b/Tests/syntax_test_PowerShell.ps1 @@ -1002,6 +1002,31 @@ switch ('this') { } # <- meta.block punctuation.section.braces.end + data { + "Thank you for using my PowerShell Organize.pst script." +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.block.data.powershell +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell + "It is provided free of charge to the community." + "I appreciate your comments and feedback." + } + + data TextMsgs { +#^^^^^^^^^^^^^^^^^^ meta.block.data.powershell +# ^^^^ keyword.control.context.powershell +# ^^^^^^^^ entity.name.section.powershell +# ^ punctuation.section.block.begin.powershell + ConvertFrom-StringData -StringData @' +# @@@@@@@@@@@@@@@@@@@@@@ reference + Text001 = Windows 7 + Text002 = Windows Server 2008 R2 +'@ + } + +$TextMsgs + + # Functions and filters functioN MyFunction{} #^^^^^^^^^^^^^^^^^^^^ meta.function.powershell From 881aae7ea78e7ba08cd0196eec12172a4dc649eb Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Sun, 7 Dec 2025 12:44:00 -0500 Subject: [PATCH 49/81] Restrict workflow execution contexts to functions --- PowerShell.sublime-syntax | 10 +++++++++- Tests/syntax_test_PowerShell.ps1 | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index 154c6ffe..dc49814d 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -135,7 +135,7 @@ contexts: scope: keyword.declaration.variable.powershell # Uncategorized keywords - - match: \b(?i:data|default|define|from|in|inlinescript|parallel|sequence){{kebab_break}} + - match: \b(?i:default|in){{kebab_break}} scope: keyword.control.powershell # Make everything afterward a literal @@ -399,6 +399,7 @@ contexts: push: expect-function-context - include: attributes + - include: workflow-execution-contexts - include: statements expect-function-context: @@ -411,6 +412,7 @@ contexts: - match: \} scope: punctuation.section.block.end.powershell pop: 1 + - include: workflow-execution-contexts - include: statements expect-param-context: @@ -428,6 +430,12 @@ contexts: - include: types - include: variables-without-members + workflow-execution-contexts: + - match: \b(?i:inlinescript){{kebab_break}} + scope: keyword.control.context.powershell + - match: \b(?i:parallel|sequence){{kebab_break}} + scope: keyword.control.flow.powershell + attributes: - match: (\[)\s*({{attributes}}) captures: diff --git a/Tests/syntax_test_PowerShell.ps1 b/Tests/syntax_test_PowerShell.ps1 index 85863edf..bbc1f236 100644 --- a/Tests/syntax_test_PowerShell.ps1 +++ b/Tests/syntax_test_PowerShell.ps1 @@ -1661,7 +1661,7 @@ Workflow work { sequence {} } # ^^^^ entity.name.function.powershell # @@@@ definition # ^ punctuation.section.block.begin.powershell -# ^^^^^^^^ keyword.control.powershell +# ^^^^^^^^ keyword.control.flow.powershell # ^^ meta.block.powershell # ^ punctuation.section.braces.begin.powershell # ^ punctuation.section.braces.end.powershell From c5baa7a98815ec23e81d4762cc29408e89b74e78 Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Sun, 7 Dec 2025 13:00:20 -0500 Subject: [PATCH 50/81] Add null-aware operators and accessors --- PowerShell.sublime-syntax | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index dc49814d..d2f2a2cc 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -527,22 +527,29 @@ contexts: members: - match: (?=\.\.) pop: 1 - - match: \.(?=\w) + - match: \?\.(?={{identifier_simple}}) + scope: punctuation.accessor.null-coalescing.powershell + - match: \??\.(?={{identifier_simple}}) scope: punctuation.accessor.dot.powershell - - match: ::(?=\w) + - match: ::(?={{identifier_simple}}) scope: punctuation.accessor.double-colon.powershell - match: (new)(\() captures: 1: meta.function-call.powershell support.function.constructor.powershell 2: meta.function-call.arguments.powershell punctuation.section.arguments.begin.powershell push: inside-function-call-arguments - - match: (\w+)(\() + - match: ({{identifier_simple}})(\() captures: 1: meta.function-call.powershell variable.function.powershell 2: meta.function-call.arguments.powershell punctuation.section.arguments.begin.powershell push: inside-function-call-arguments - - match: \w+ + - match: '{{identifier_simple}}' scope: variable.other.member.powershell + - match: (\?)(\[) + captures: + 1: punctuation.accessor.null-coalescing.powershell + 2: punctuation.section.brackets.begin.powershell + push: inside-indexer - match: \[ scope: punctuation.section.brackets.begin.powershell push: inside-indexer @@ -652,11 +659,14 @@ contexts: scope: keyword.operator.logical.powershell - match: \| scope: keyword.operator.logical.pipe.powershell + - match: \?\? + scope: keyword.operator.null-coalescing.powershell - match: ; scope: punctuation.terminator.statement.powershell - match: \`(?=\n|$) scope: punctuation.separator.continuation.line.powershell - include: comma-separators + # TODO: Distinguish call operator from background operator - match: '&' scope: keyword.operator.background.powershell - match: \.\.(?=\-?\d|\(|\$) From 1c2adf9764caecc18b556dbeb301924122882ba2 Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Sun, 7 Dec 2025 13:02:19 -0500 Subject: [PATCH 51/81] Let script invocation start with a drive letter --- PowerShell.sublime-syntax | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index d2f2a2cc..1dd971c6 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -241,7 +241,7 @@ contexts: scope: meta.function-call.powershell support.function.powershell script-invocation: - - match: \b[\w.\\/-]+\.(?i:exe|com|cmd|bat|ps1)\b + - match: \b(?i:[a-z]:)?[\w.\\/-]+\.(?i:exe|com|cmd|bat|ps1)\b scope: variable.function.powershell parameters: From cdacd44b2f7c8bccf877c9da6a2a9df621cbe099 Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Sun, 7 Dec 2025 13:24:04 -0500 Subject: [PATCH 52/81] Extract flow-like matches to named contexts --- PowerShell.sublime-syntax | 98 ++++++++++++++++++++++----------------- 1 file changed, 55 insertions(+), 43 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index 1dd971c6..5ba9db2c 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -54,49 +54,10 @@ contexts: - match: \B\.(?= ) scope: support.function.source.powershell - # Exceptions - - match: \b(?i:throw){{kebab_break}} - scope: keyword.control.exception.raise.powershell - - match: \b(?i:try){{kebab_break}} - scope: keyword.control.exception.try.powershell - - match: \b(?i:catch|trap){{kebab_break}} - scope: keyword.control.exception.catch.powershell - - match: \b(?i:finally){{kebab_break}} - scope: keyword.control.exception.finally.powershell - - # Loops - - match: \b(?i:for|foreach(?!-object)){{kebab_break}} - scope: keyword.control.loop.for.powershell - - match: \b(?i:do){{kebab_break}} - scope: keyword.control.loop.do-while.powershell - - match: \b(?i:while){{kebab_break}} - scope: keyword.control.loop.while.powershell - - match: \b(?i:until){{kebab_break}} - scope: keyword.control.loop.repeat-until.powershell - - # Flow - - match: \b(?i:break){{kebab_break}} - scope: keyword.control.flow.break.powershell - - match: \b(?i:continue){{kebab_break}} - scope: keyword.control.flow.continue.powershell - - match: \b(?i:exit){{kebab_break}} - scope: keyword.control.flow.exit.powershell - - match: \b(?i:return){{kebab_break}} - scope: keyword.control.flow.return.powershell - - # Conditionals - - match: \b(?i:if){{kebab_break}} - scope: keyword.control.conditional.if.powershell - - match: \b(?i:elseif){{kebab_break}} - scope: keyword.control.conditional.elseif.powershell - - match: \b(?i:else){{kebab_break}} - scope: keyword.control.conditional.else.powershell - - match: \b(?i:switch){{kebab_break}} - scope: keyword.control.conditional.switch.powershell - - match: \? - scope: keyword.control.conditional.select.powershell - - match: \b(?i:where(?!-object)){{kebab_break}} - scope: keyword.control.conditional.select.powershell + - include: exceptions + - include: loops + - include: flow + - include: conditionals expressions: # Meta @@ -148,6 +109,57 @@ contexts: - include: operators - include: parameters +###[ EXCEPTIONS ]############################################################## + + exceptions: + - match: \b(?i:throw){{kebab_break}} + scope: keyword.control.exception.raise.powershell + - match: \b(?i:try){{kebab_break}} + scope: keyword.control.exception.try.powershell + - match: \b(?i:catch|trap){{kebab_break}} + scope: keyword.control.exception.catch.powershell + - match: \b(?i:finally){{kebab_break}} + scope: keyword.control.exception.finally.powershell + +###[ LOOPS ]################################################################### + + loops: + - match: \b(?i:for|foreach(?!-object)){{kebab_break}} + scope: keyword.control.loop.for.powershell + - match: \b(?i:do){{kebab_break}} + scope: keyword.control.loop.do-while.powershell + - match: \b(?i:while){{kebab_break}} + scope: keyword.control.loop.while.powershell + - match: \b(?i:until){{kebab_break}} + scope: keyword.control.loop.repeat-until.powershell + +###[ FLOW ]#################################################################### + + flow: + - match: \b(?i:break){{kebab_break}} + scope: keyword.control.flow.break.powershell + - match: \b(?i:continue){{kebab_break}} + scope: keyword.control.flow.continue.powershell + - match: \b(?i:exit){{kebab_break}} + scope: keyword.control.flow.exit.powershell + - match: \b(?i:return){{kebab_break}} + scope: keyword.control.flow.return.powershell + +###[ CONDITIONALS ]############################################################ + + conditionals: + - match: \b(?i:if){{kebab_break}} + scope: keyword.control.conditional.if.powershell + - match: \b(?i:elseif){{kebab_break}} + scope: keyword.control.conditional.elseif.powershell + - match: \b(?i:else){{kebab_break}} + scope: keyword.control.conditional.else.powershell + - match: \b(?i:switch){{kebab_break}} + scope: keyword.control.conditional.switch.powershell + - match: \? + scope: keyword.control.conditional.select.powershell + - match: \b(?i:where(?!-object)){{kebab_break}} + scope: keyword.control.conditional.select.powershell ###[ GROUPS ]################################################################## From 8b35b0bccb4b2aa9b2b9590f07e222d2b0232fbe Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Sun, 7 Dec 2025 13:24:52 -0500 Subject: [PATCH 53/81] Sort the last two reserved words --- PowerShell.sublime-syntax | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index 5ba9db2c..304b6464 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -95,9 +95,6 @@ contexts: - match: \b(?i:var){{kebab_break}} scope: keyword.declaration.variable.powershell - # Uncategorized keywords - - match: \b(?i:default|in){{kebab_break}} - scope: keyword.control.powershell # Make everything afterward a literal - match: \B--%\B @@ -156,6 +153,8 @@ contexts: scope: keyword.control.conditional.else.powershell - match: \b(?i:switch){{kebab_break}} scope: keyword.control.conditional.switch.powershell + - match: \b(?i:default){{kebab_break}} + scope: keyword.control.conditional.default.powershell - match: \? scope: keyword.control.conditional.select.powershell - match: \b(?i:where(?!-object)){{kebab_break}} @@ -171,6 +170,9 @@ contexts: - match: \) scope: punctuation.section.group.end.powershell set: members + # TODO: Move this to a foreach (X in Y) construct + - match: \b(?i:in){{kebab_break}} + scope: keyword.control.loop.in.powershell - include: attributes - include: expressions From f5cbac6476fe3f38628c1d49ff2e3f02595f2271 Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Sun, 7 Dec 2025 13:25:21 -0500 Subject: [PATCH 54/81] Extract --% to a named context --- PowerShell.sublime-syntax | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index 304b6464..da5ea9ba 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -67,6 +67,7 @@ contexts: # Normal code - include: escape-sequences + - include: literal-after - include: commands - include: constants @@ -82,8 +83,8 @@ contexts: - include: arrays - include: subexpressions - # Consume a string with a trailing dot - # to prevent members with particular names from being recognized as keywords. + # Consume a string with a trailing dot to prevent members with + # particular names from being recognized as keywords. - match: \b[\w-]+(?=\.) scope: variable.other.object.powershell push: members @@ -95,8 +96,10 @@ contexts: - match: \b(?i:var){{kebab_break}} scope: keyword.declaration.variable.powershell + - include: operators + - include: parameters - # Make everything afterward a literal + literal-after: - match: \B--%\B scope: keyword.control.powershell push: @@ -104,8 +107,6 @@ contexts: - meta_content_scope: string.unquoted.powershell - include: pop-before-eol - - include: operators - - include: parameters ###[ EXCEPTIONS ]############################################################## exceptions: From 86839584aeba676f131d45981734c8c842c31f38 Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Sun, 7 Dec 2025 13:33:49 -0500 Subject: [PATCH 55/81] Consolidate variable lookahead And make sure it doesn't make hashtables --- PowerShell.sublime-syntax | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index da5ea9ba..cd687158 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -480,11 +480,11 @@ contexts: ###[ VARIABLES ]############################################################### variables: - - match: (?=[$@](?:[{$^]|{{identifier_simple}})) + - match: '{{var_lookahead}}' push: [members, expect-variable] variables-without-members: - - match: (?=[$@](?:[{$^]|{{identifier_simple}})) + - match: '{{var_lookahead}}' push: [expect-variable] expect-variable: @@ -501,7 +501,7 @@ contexts: 1: punctuation.definition.variable.powershell 2: punctuation.section.interpolation.begin.powershell push: inside-variable-special-char - - match: (\$|@)(?!\{) + - match: (\$|@) captures: 1: punctuation.definition.variable.powershell 2: punctuation.section.interpolation.begin.powershell @@ -1064,6 +1064,11 @@ variables: identifier_simple: '[\p{L}\p{Nd}_?]+' identifier_special: '[^}]*[^}`]' identifier_function: '[\p{L}\p{Nd}_.-]+' + var_lookahead: |- + (?x: (?= + \$[$^{] + | [$@]{{identifier_simple}} + )) # https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_automatic_variables var_constants: |- \b(?xi: From 3a8aae830dcc7788e54cca713c0ef6b5ad465435 Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Sun, 7 Dec 2025 13:43:45 -0500 Subject: [PATCH 56/81] Tweak expression execution order --- PowerShell.sublime-syntax | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index cd687158..98cb5a3b 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -65,22 +65,24 @@ contexts: - include: regions - include: requires-directives - # Normal code - include: escape-sequences - include: literal-after - - include: commands - - include: constants + # Normal code - include: types - - include: hashtables - - include: variables - include: strings - include: numbers - - include: data-blocks + - include: constants + - include: variables + + - include: hashtables + - include: arrays + - include: commands + + - include: data-blocks - include: script-blocks - include: groups - - include: arrays - include: subexpressions # Consume a string with a trailing dot to prevent members with From cba79c867d8f3f1696176788eb89eb81a6e15cad Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Sun, 7 Dec 2025 13:47:43 -0500 Subject: [PATCH 57/81] Move the ternary operator to its rightful place --- PowerShell.sublime-syntax | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index 98cb5a3b..c45d81f1 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -158,8 +158,6 @@ contexts: scope: keyword.control.conditional.switch.powershell - match: \b(?i:default){{kebab_break}} scope: keyword.control.conditional.default.powershell - - match: \? - scope: keyword.control.conditional.select.powershell - match: \b(?i:where(?!-object)){{kebab_break}} scope: keyword.control.conditional.select.powershell @@ -678,6 +676,8 @@ contexts: scope: keyword.operator.logical.pipe.powershell - match: \?\? scope: keyword.operator.null-coalescing.powershell + - match: '[?:]' + scope: keyword.operator.ternary.powershell - match: ; scope: punctuation.terminator.statement.powershell - match: \`(?=\n|$) From 2f3144fc2959ec8695a3c16cb6bcfdbbff309016 Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Sun, 7 Dec 2025 13:59:25 -0500 Subject: [PATCH 58/81] Fix data section not popping --- PowerShell.sublime-syntax | 2 +- Tests/syntax_test_PowerShell.ps1 | 16 +--------------- Tests/syntax_test_partial-symbols.ps1 | 16 ++++++++++++++++ 3 files changed, 18 insertions(+), 16 deletions(-) create mode 100644 Tests/syntax_test_partial-symbols.ps1 diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index c45d81f1..b5d65200 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -729,7 +729,7 @@ contexts: inside-data-block: - match: \} scope: punctuation.section.block.end.powershell - pop: 1 + pop: 2 # Data sections use a subset of Pwsh, but we don't distinguish yet. - include: statements diff --git a/Tests/syntax_test_PowerShell.ps1 b/Tests/syntax_test_PowerShell.ps1 index bbc1f236..52e1077a 100644 --- a/Tests/syntax_test_PowerShell.ps1 +++ b/Tests/syntax_test_PowerShell.ps1 @@ -1011,21 +1011,7 @@ switch ('this') { "It is provided free of charge to the community." "I appreciate your comments and feedback." } - - data TextMsgs { -#^^^^^^^^^^^^^^^^^^ meta.block.data.powershell -# ^^^^ keyword.control.context.powershell -# ^^^^^^^^ entity.name.section.powershell -# ^ punctuation.section.block.begin.powershell - ConvertFrom-StringData -StringData @' -# @@@@@@@@@@@@@@@@@@@@@@ reference - Text001 = Windows 7 - Text002 = Windows Server 2008 R2 -'@ - } - -$TextMsgs - +# ^ - meta # Functions and filters functioN MyFunction{} diff --git a/Tests/syntax_test_partial-symbols.ps1 b/Tests/syntax_test_partial-symbols.ps1 new file mode 100644 index 00000000..0371a95b --- /dev/null +++ b/Tests/syntax_test_partial-symbols.ps1 @@ -0,0 +1,16 @@ +# SYNTAX TEST partial-symbols "Packages/PowerShell/PowerShell.sublime-syntax" + + + data TextMsgs { +# ^^^^^^^^^^^^^^^ meta.block.data.powershell +# ^^^^ keyword.control.context.powershell +# ^^^^^^^^ entity.name.section.powershell +# ^ punctuation.section.block.begin.powershell + ConvertFrom-StringData -StringData @' +# @@@@@@@@@@@@@@@@@@@@@@ reference + Text001 = Windows 7 + Text002 = Windows Server 2008 R2 +'@ + } + + $TextMsgs From 04f8b43398d4a51979dfd5fb53ea8032df317c4a Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Sun, 7 Dec 2025 14:03:48 -0500 Subject: [PATCH 59/81] Fix functions not popping fast enough --- PowerShell.sublime-syntax | 2 +- Tests/syntax_test_Class.ps1 | 4 +--- Tests/syntax_test_PowerShell.ps1 | 5 +++-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index b5d65200..8fef8023 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -403,7 +403,7 @@ contexts: inside-function-body: - match: \} scope: punctuation.section.block.end.powershell - pop: 1 + pop: 2 - match: \b(?i:(?:Dynamic)?Param){{kebab_break}} scope: keyword.declaration.parameter.powershell # This scope is not standard diff --git a/Tests/syntax_test_Class.ps1 b/Tests/syntax_test_Class.ps1 index 33e28ea8..c1703196 100644 --- a/Tests/syntax_test_Class.ps1 +++ b/Tests/syntax_test_Class.ps1 @@ -103,13 +103,12 @@ class TypeName # ^^ variable.other.readwrite.powershell # ^ punctuation.definition.variable.powershell } - +# ^ - meta.function # Static method # <- punctuation.definition.comment # ^^^^^^^^^^^^^ comment.line static [void] MemberMethod1([hashtable] $h) { #^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.class.powershell -#^^^ meta.function.powershell # ^^^^^^ storage.modifier.powershell # ^ punctuation.section.brackets.begin.powershell # ^^^^ storage.type.powershell @@ -142,7 +141,6 @@ class TypeName # ^^^^^^^^^^^^^^^ comment.line [int] MemberMethod2([int] $i) { #^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.class.powershell -#^^^ meta.function.powershell # ^ punctuation.section.brackets.begin.powershell # ^^^ storage.type.powershell # ^ punctuation.section.brackets.end.powershell diff --git a/Tests/syntax_test_PowerShell.ps1 b/Tests/syntax_test_PowerShell.ps1 index 52e1077a..3b9641bf 100644 --- a/Tests/syntax_test_PowerShell.ps1 +++ b/Tests/syntax_test_PowerShell.ps1 @@ -1021,6 +1021,7 @@ functioN MyFunction{} # @@@@@@@@@@ definition # ^ punctuation.section.block.begin.powershell # ^ punctuation.section.block.end.powershell +# ^ - meta function My-Function {} #^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.function.powershell #^^^^^^^ keyword.declaration.function.powershell @@ -1276,7 +1277,8 @@ class Vehicle { # ^ punctuation.section.block.begin.powershell # ^ punctuation.section.block.end.powershell Vehicle([string]$Owner) { -#^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.class.powershell meta.function.powershell +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.class.powershell +# ^^^^^^^^^^^^^^^^^^^^^^^^^ meta.function.powershell # ^^^^^^^ entity.name.function.powershell # @@@@@@@ definition # ^ punctuation.section.parameters.begin.powershell @@ -1335,7 +1337,6 @@ class Vehicle { static [System.Array] GetAvailableColors() { #^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.class.powershell -#^^^ meta.function.powershell # ^^^^^^ storage.modifier.powershell # ^ punctuation.section.brackets.begin.powershell # ^^^^^^^ meta.generic-name.powershell From 915f845fe06b9490d3a69dc4ec1c195bb5bc51fa Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Sun, 7 Dec 2025 18:51:48 -0500 Subject: [PATCH 60/81] Add naive string placeholder scopes --- PowerShell.sublime-syntax | 20 ++++++ Tests/syntax_test_strings.ps1 | 116 ++++++++++++++++++++++++++++++++-- 2 files changed, 132 insertions(+), 4 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index 8fef8023..44c8ea70 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -774,6 +774,7 @@ contexts: - match: \' scope: punctuation.definition.string.end.powershell pop: 1 + - include: string-placeholders double-quoted-strings: - match: '"' @@ -792,6 +793,7 @@ contexts: # # Silently eat email addresses # - match: '(?i)\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,64}\b' - include: string-interpolations + - include: string-placeholders - match: '`\s*$' scope: keyword.other.powershell @@ -821,6 +823,7 @@ contexts: pop: 1 - match: "''" scope: constant.character.escape.powershell + - include: string-placeholders double-quoted-heredoc-strings: - match: \@"(?=$) @@ -836,6 +839,7 @@ contexts: scope: punctuation.definition.string.end.powershell pop: 1 - include: escape-sequences + - include: string-placeholders - include: string-interpolations inside-double-quoted-heredoc-string.syntax: @@ -868,6 +872,22 @@ contexts: - include: variables-without-members - include: immediately-pop + string-placeholders: + - match: \{ + scope: punctuation.definition.placeholder.begin.powershell + push: inside-string-placeholder + + inside-string-placeholder: + - meta_include_prototype: false + - meta_scope: constant.other.placeholder.powershell + - match: \} + scope: punctuation.definition.placeholder.end.powershell + pop: 1 + - match: (?=['"]) + pop: 1 + - match: '[:,;]' + scope: punctuation.separator.powershell + numbers: # Binary numbers - match: \b(0[bB])([01]*)({{int_suffix}}?{{unit_suffix}}?) diff --git a/Tests/syntax_test_strings.ps1 b/Tests/syntax_test_strings.ps1 index 05690d37..c5a5ff4e 100644 --- a/Tests/syntax_test_strings.ps1 +++ b/Tests/syntax_test_strings.ps1 @@ -213,6 +213,10 @@ "{0:N2}" -f $a # ^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell # ^ punctuation.definition.string.begin.powershell +# ^^^^^^ constant.other.placeholder.powershell +# ^ punctuation.definition.placeholder.begin.powershell +# ^ punctuation.separator.powershell +# ^ punctuation.definition.placeholder.end.powershell # ^ punctuation.definition.string.end.powershell # ^^ keyword.operator.string-format.powershell # ^ punctuation.definition.keyword.powershell @@ -222,6 +226,10 @@ "{0:D8}" -f $a # ^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell # ^ punctuation.definition.string.begin.powershell +# ^^^^^^ constant.other.placeholder.powershell +# ^ punctuation.definition.placeholder.begin.powershell +# ^ punctuation.separator.powershell +# ^ punctuation.definition.placeholder.end.powershell # ^ punctuation.definition.string.end.powershell # ^^ keyword.operator.string-format.powershell # ^ punctuation.definition.keyword.powershell @@ -231,6 +239,10 @@ "{0:C2}" -f $a # ^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell # ^ punctuation.definition.string.begin.powershell +# ^^^^^^ constant.other.placeholder.powershell +# ^ punctuation.definition.placeholder.begin.powershell +# ^ punctuation.separator.powershell +# ^ punctuation.definition.placeholder.end.powershell # ^ punctuation.definition.string.end.powershell # ^^ keyword.operator.string-format.powershell # ^ punctuation.definition.keyword.powershell @@ -240,6 +252,10 @@ "{0:P0}" -f $a # ^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell # ^ punctuation.definition.string.begin.powershell +# ^^^^^^ constant.other.placeholder.powershell +# ^ punctuation.definition.placeholder.begin.powershell +# ^ punctuation.separator.powershell +# ^ punctuation.definition.placeholder.end.powershell # ^ punctuation.definition.string.end.powershell # ^^ keyword.operator.string-format.powershell # ^ punctuation.definition.keyword.powershell @@ -249,6 +265,10 @@ "{0:X0}" -f $a # ^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell # ^ punctuation.definition.string.begin.powershell +# ^^^^^^ constant.other.placeholder.powershell +# ^ punctuation.definition.placeholder.begin.powershell +# ^ punctuation.separator.powershell +# ^ punctuation.definition.placeholder.end.powershell # ^ punctuation.definition.string.end.powershell # ^^ keyword.operator.string-format.powershell # ^ punctuation.definition.keyword.powershell @@ -274,6 +294,19 @@ "{1,10} {0,10} {2,10:x}" -f "First", "Second", 255 # ^^^^^^^^^^^^^^^^^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell # ^ punctuation.definition.string.begin.powershell +# ^^^^^^ constant.other.placeholder.powershell +# ^ punctuation.definition.placeholder.begin.powershell +# ^ punctuation.separator.powershell +# ^ punctuation.definition.placeholder.end.powershell +# ^^^^^^ constant.other.placeholder.powershell +# ^ punctuation.definition.placeholder.begin.powershell +# ^ punctuation.separator.powershell +# ^ punctuation.definition.placeholder.end.powershell +# ^^^^^^^^ constant.other.placeholder.powershell +# ^ punctuation.definition.placeholder.begin.powershell +# ^ punctuation.separator.powershell +# ^ punctuation.separator.powershell +# ^ punctuation.definition.placeholder.end.powershell # ^ punctuation.definition.string.end.powershell # ^^ keyword.operator.string-format.powershell # ^ punctuation.definition.keyword.powershell @@ -292,6 +325,10 @@ # ^ punctuation.section.group.begin.powershell # ^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell # ^ punctuation.definition.string.begin.powershell +# ^^^^^ constant.other.placeholder.powershell +# ^ punctuation.definition.placeholder.begin.powershell +# ^ punctuation.separator.powershell +# ^ punctuation.definition.placeholder.end.powershell # ^ punctuation.definition.string.end.powershell # ^^ keyword.operator.string-format.powershell # ^ punctuation.definition.keyword.powershell @@ -303,6 +340,11 @@ # ^ punctuation.section.group.begin.powershell # ^^^^^^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell # ^ punctuation.definition.string.begin.powershell +# ^^^^^^^^^^^ constant.other.placeholder.powershell +# ^ punctuation.definition.placeholder.begin.powershell +# ^ punctuation.separator.powershell +# ^ punctuation.separator.powershell +# ^ punctuation.definition.placeholder.end.powershell # ^ punctuation.definition.string.end.powershell # ^^ keyword.operator.string-format.powershell # ^ punctuation.definition.keyword.powershell @@ -313,6 +355,10 @@ "{0:R}" -f (1mb/2.0) # ^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell # ^ punctuation.definition.string.begin.powershell +# ^^^^^ constant.other.placeholder.powershell +# ^ punctuation.definition.placeholder.begin.powershell +# ^ punctuation.separator.powershell +# ^ punctuation.definition.placeholder.end.powershell # ^ punctuation.definition.string.end.powershell # ^^ keyword.operator.string-format.powershell # ^ punctuation.definition.keyword.powershell @@ -329,6 +375,10 @@ "{0:00.0}" -f 4.12341234 # ^^^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell # ^ punctuation.definition.string.begin.powershell +# ^^^^^^^^ constant.other.placeholder.powershell +# ^ punctuation.definition.placeholder.begin.powershell +# ^ punctuation.separator.powershell +# ^ punctuation.definition.placeholder.end.powershell # ^ punctuation.definition.string.end.powershell # ^^ keyword.operator.string-format.powershell # ^ punctuation.definition.keyword.powershell @@ -338,6 +388,10 @@ "{0:##.#}" -f 4.12341234 # ^^^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell # ^ punctuation.definition.string.begin.powershell +# ^^^^^^^^ constant.other.placeholder.powershell +# ^ punctuation.definition.placeholder.begin.powershell +# ^ punctuation.separator.powershell +# ^ punctuation.definition.placeholder.end.powershell # ^ punctuation.definition.string.end.powershell # ^^ keyword.operator.string-format.powershell # ^ punctuation.definition.keyword.powershell @@ -347,6 +401,11 @@ "{0:#,#.#}" -f 1234.121234 # ^^^^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell # ^ punctuation.definition.string.begin.powershell +# ^^^^^^^^^ constant.other.placeholder.powershell +# ^ punctuation.definition.placeholder.begin.powershell +# ^ punctuation.separator.powershell +# ^ punctuation.separator.powershell +# ^ punctuation.definition.placeholder.end.powershell # ^ punctuation.definition.string.end.powershell # ^^ keyword.operator.string-format.powershell # ^ punctuation.definition.keyword.powershell @@ -356,6 +415,11 @@ "{0:##,,.000}" -f 1048576 # ^^^^^^^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell # ^ punctuation.definition.string.begin.powershell +# ^^^^^^^^^^^^ constant.other.placeholder.powershell +# ^ punctuation.definition.placeholder.begin.powershell +# ^ punctuation.separator.powershell +# ^^ punctuation.separator.powershell +# ^ punctuation.definition.placeholder.end.powershell # ^ punctuation.definition.string.end.powershell # ^^ keyword.operator.string-format.powershell # ^ punctuation.definition.keyword.powershell @@ -364,20 +428,31 @@ "{this is not a #comment}" # ^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell - comment # ^ punctuation.definition.string.begin.powershell +# ^^^^^^^^^^^^^^^^^^^^^^^^ constant.other.placeholder.powershell +# ^ punctuation.definition.placeholder.begin.powershell +# ^ punctuation.definition.placeholder.end.powershell # ^ punctuation.definition.string.end.powershell "{0:##.#E000}" -f 2.71828 # ^^^^^^^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell # ^ punctuation.definition.string.begin.powershell +# ^^^^^^^^^^^^ constant.other.placeholder.powershell +# ^ punctuation.definition.placeholder.begin.powershell +# ^ punctuation.separator.powershell +# ^ punctuation.definition.placeholder.end.powershell # ^ punctuation.definition.string.end.powershell # ^^ keyword.operator.string-format.powershell # ^ punctuation.definition.keyword.powershell # ^^^^^^^ meta.number.float.decimal.powershell constant.numeric.value.powershell # ^ punctuation.separator.decimal.powershell + # TODO: Let placeholders contain quotes "{0:#.00'##'}" -f 2.71828 # ^^^^^^^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell # ^ punctuation.definition.string.begin.powershell +# ^^^^^^^ constant.other.placeholder.powershell +# ^ punctuation.definition.placeholder.begin.powershell +# ^ punctuation.separator.powershell # ^ punctuation.definition.string.end.powershell # ^^ keyword.operator.string-format.powershell # ^ punctuation.definition.keyword.powershell @@ -387,6 +462,12 @@ "{0:POS;NEG;ZERO}" -f -14 # ^^^^^^^^^^^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell # ^ punctuation.definition.string.begin.powershell +# ^^^^^^^^^^^^^^^^ constant.other.placeholder.powershell +# ^ punctuation.definition.placeholder.begin.powershell +# ^ punctuation.separator.powershell +# ^ punctuation.separator.powershell +# ^ punctuation.separator.powershell +# ^ punctuation.definition.placeholder.end.powershell # ^ punctuation.definition.string.end.powershell # ^^ keyword.operator.string-format.powershell # ^ punctuation.definition.keyword.powershell @@ -394,11 +475,12 @@ # ^^ meta.number.integer.decimal.powershell constant.numeric.value.powershell "{0:$## Please}" -f 14 -# ^^^^^^^^^^^^^^^^ meta.string.interpolated.powershell -# ^^^^ string.quoted.double.powershell +# ^^^^^^^^^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell - comment # ^ punctuation.definition.string.begin.powershell -# ^ meta.interpolation.powershell -# ^^^^^^^^^^^ string.quoted.double.powershell +# ^^^^^^^^^^^^^^ constant.other.placeholder.powershell +# ^ punctuation.definition.placeholder.begin.powershell +# ^ punctuation.separator.powershell +# ^ punctuation.definition.placeholder.end.powershell # ^ punctuation.definition.string.end.powershell # ^^ keyword.operator.string-format.powershell # ^ punctuation.definition.keyword.powershell @@ -407,6 +489,11 @@ "{0,-8:P1}" -f 1.75 # ^^^^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell # ^ punctuation.definition.string.begin.powershell +# ^^^^^^^^^ constant.other.placeholder.powershell +# ^ punctuation.definition.placeholder.begin.powershell +# ^ punctuation.separator.powershell +# ^ punctuation.separator.powershell +# ^ punctuation.definition.placeholder.end.powershell # ^ punctuation.definition.string.end.powershell # ^^ keyword.operator.string-format.powershell # ^ punctuation.definition.keyword.powershell @@ -416,6 +503,23 @@ "{0,10:N3}{1,10:N3}{2,10:N3}{3,10:N3}" -f 0.2, 0.3, 0.45, 0.91 # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell # ^ punctuation.definition.string.begin.powershell +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant.other.placeholder.powershell +# ^ punctuation.definition.placeholder.begin.powershell +# ^ punctuation.separator.powershell +# ^ punctuation.separator.powershell +# ^ punctuation.definition.placeholder.end.powershell +# ^ punctuation.definition.placeholder.begin.powershell +# ^ punctuation.separator.powershell +# ^ punctuation.separator.powershell +# ^ punctuation.definition.placeholder.end.powershell +# ^ punctuation.definition.placeholder.begin.powershell +# ^ punctuation.separator.powershell +# ^ punctuation.separator.powershell +# ^ punctuation.definition.placeholder.end.powershell +# ^ punctuation.definition.placeholder.begin.powershell +# ^ punctuation.separator.powershell +# ^ punctuation.separator.powershell +# ^ punctuation.definition.placeholder.end.powershell # ^ punctuation.definition.string.end.powershell # ^^ keyword.operator.string-format.powershell # ^ punctuation.definition.keyword.powershell @@ -435,6 +539,10 @@ '{0:00000.000}' -f 7.125 # ^^^^^^^^^^^^^^^ meta.string.powershell string.quoted.single.powershell # ^ punctuation.definition.string.begin.powershell +# ^^^^^^^^^^^^^ constant.other.placeholder.powershell +# ^ punctuation.definition.placeholder.begin.powershell +# ^ punctuation.separator.powershell +# ^ punctuation.definition.placeholder.end.powershell # ^ punctuation.definition.string.end.powershell # ^^ keyword.operator.string-format.powershell # ^ punctuation.definition.keyword.powershell From 1347a558945972bbb461bca8f4d3dc0afb79fed9 Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Sun, 7 Dec 2025 19:32:47 -0500 Subject: [PATCH 61/81] Drop some unlikely string rules --- PowerShell.sublime-syntax | 4 ---- 1 file changed, 4 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index 44c8ea70..0142b8aa 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -790,12 +790,8 @@ contexts: - match: '"' scope: punctuation.definition.string.end.powershell pop: 1 - # # Silently eat email addresses - # - match: '(?i)\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,64}\b' - include: string-interpolations - include: string-placeholders - - match: '`\s*$' - scope: keyword.other.powershell single-quoted-heredoc-strings: - match: \@'(?=$) From 649687a8c481ce3ec3a33ce59125dbb74f971e37 Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Sun, 7 Dec 2025 19:53:11 -0500 Subject: [PATCH 62/81] Make straight and curly quotes equivalent I think this language was written by trolls. --- PowerShell.sublime-syntax | 34 ++++++++++++++++++---------------- Tests/syntax_test_strings.ps1 | 14 ++++++++++++++ 2 files changed, 32 insertions(+), 16 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index 0142b8aa..499848b7 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -762,39 +762,39 @@ contexts: - include: single-quoted-heredoc-strings single-quoted-strings: - - match: \' + - match: '{{single_quote}}' scope: punctuation.definition.string.begin.powershell push: inside-single-quoted-string inside-single-quoted-string: - meta_include_prototype: false - meta_scope: meta.string.powershell string.quoted.single.powershell - - match: "''" + - match: '{{single_quote}}{2}' scope: constant.character.escape.powershell - - match: \' + - match: '{{single_quote}}' scope: punctuation.definition.string.end.powershell pop: 1 - include: string-placeholders double-quoted-strings: - - match: '"' + - match: '{{double_quote}}' scope: punctuation.definition.string.begin.powershell push: inside-double-quoted-string inside-double-quoted-string: - meta_include_prototype: false - meta_scope: meta.string.interpolated.powershell string.quoted.double.powershell - - match: '""' + - match: '{{double_quote}}{2}' scope: constant.character.escape.powershell - include: escape-sequences - - match: '"' + - match: '{{double_quote}}' scope: punctuation.definition.string.end.powershell pop: 1 - include: string-interpolations - include: string-placeholders single-quoted-heredoc-strings: - - match: \@'(?=$) + - match: \@{{single_quote}}(?=$) scope: punctuation.definition.string.begin.powershell push: - inside-single-quoted-heredoc-string @@ -805,24 +805,24 @@ contexts: - match: (?={{csharp_indicator}}) set: scope:source.cs with_prototype: - - match: (?=^'@) + - match: (?=^{{single_quote}}@) pop: 1 - - match: "''" + - match: '{{single_quote}}{2}' scope: constant.character.escape.powershell - include: else-pop inside-single-quoted-heredoc-string: - meta_include_prototype: false - meta_scope: meta.string.powershell string.quoted.single.heredoc.powershell - - match: ^'@ + - match: ^{{single_quote}}@ scope: punctuation.definition.string.end.powershell pop: 1 - - match: "''" + - match: '{{single_quote}}{2}' scope: constant.character.escape.powershell - include: string-placeholders double-quoted-heredoc-strings: - - match: \@"(?=$) + - match: \@{{double_quote}}(?=$) scope: punctuation.definition.string.begin.powershell push: - inside-double-quoted-heredoc-string @@ -831,7 +831,7 @@ contexts: inside-double-quoted-heredoc-string: - meta_include_prototype: false - meta_scope: meta.string.interpolated.powershell string.quoted.double.heredoc.powershell - - match: ^"@ + - match: ^{{double_quote}}@ scope: punctuation.definition.string.end.powershell pop: 1 - include: escape-sequences @@ -843,7 +843,7 @@ contexts: - match: (?={{csharp_indicator}}) set: scope:source.cs with_prototype: - - match: (?=^"@) + - match: (?=^{{double_quote}}@) pop: 1 - include: escape-sequences - include: else-pop @@ -879,7 +879,7 @@ contexts: - match: \} scope: punctuation.definition.placeholder.end.powershell pop: 1 - - match: (?=['"]) + - match: (?={{single_quote}}|{{double_quote}}) pop: 1 - match: '[:,;]' scope: punctuation.separator.powershell @@ -1021,7 +1021,7 @@ contexts: scope: punctuation.separator.sequence.powershell escape-sequences: - - match: '`[0abenfrvt"''$`]' + - match: '`(?:[0abenfrvt$`]|{{single_quote}}|{{double_quote}})' scope: constant.character.escape.powershell - match: '`u\{\h+\}' scope: constant.character.escape.powershell @@ -1162,6 +1162,8 @@ variables: ) # Strings + single_quote: "['‘’‚]" + double_quote: '["“”„]' csharp_indicator: |- (?x: \s* (?: using\s+System[.;] diff --git a/Tests/syntax_test_strings.ps1 b/Tests/syntax_test_strings.ps1 index c5a5ff4e..9ba374eb 100644 --- a/Tests/syntax_test_strings.ps1 +++ b/Tests/syntax_test_strings.ps1 @@ -41,6 +41,13 @@ # ^ punctuation.definition.string.begin.powershell # ^ punctuation.definition.string.end.powershell + ‘curly ‘‘quotes'’ are equivalent to straight ones' +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string.powershell string.quoted.single.powershell +# ^ punctuation.definition.string.begin.powershell +# ^^ constant.character.escape.powershell +# ^^ constant.character.escape.powershell +# ^ punctuation.definition.string.end.powershell + @' # ^^ meta.string.powershell string.quoted.single.heredoc.powershell punctuation.definition.string.begin.powershell - meta.string.interpolated A 'single quoted' "heredoc" @@ -167,6 +174,13 @@ # ^ punctuation.section.interpolation.end # @@@@@@@@@@@@@@@@ reference + “curly ““quotes"” are equivalent to straight ones" +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^^ constant.character.escape.powershell +# ^^ constant.character.escape.powershell +# ^ punctuation.definition.string.end.powershell + # Double quoted here-string @" # ^^ meta.string.interpolated.powershell string.quoted.double.heredoc.powershell punctuation.definition.string.begin.powershell From fa4de9241aef44cf5d2d561f2c838161324db516 Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Mon, 8 Dec 2025 10:18:05 -0500 Subject: [PATCH 63/81] Extract C# identifiers to a variable --- PowerShell.sublime-syntax | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index 499848b7..df9e2e78 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -300,20 +300,20 @@ contexts: inside-using-namespace: - include: pop-eol - - match: \p{L}[\p{L}\p{N}]+(\.) + - match: '{{identifier_csharp}}(\.)' scope: meta.path.powershell captures: 1: punctuation.accessor.dot.powershell - - match: \p{L}[\p{L}\p{N}]+ + - match: '{{identifier_csharp}}' scope: meta.path.powershell inside-using-module: - include: pop-eol - - match: \p{L}[\p{L}\p{N}]+(\.) + - match: '{{identifier_csharp}}(\.)' scope: meta.path.powershell captures: 1: punctuation.accessor.dot.powershell - - match: \p{L}[\p{L}\p{N}]+ + - match: '{{identifier_csharp}}' scope: meta.path.powershell support.type.powershell ###[ CLASSES ]################################################################# @@ -1082,6 +1082,7 @@ variables: identifier_simple: '[\p{L}\p{Nd}_?]+' identifier_special: '[^}]*[^}`]' identifier_function: '[\p{L}\p{Nd}_.-]+' + identifier_csharp: '[\p{L}_][\p{L}\p{Nd}_]*' var_lookahead: |- (?x: (?= \$[$^{] From 025c8f97125bfe6d81377364bed29dbad4e112d4 Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Mon, 8 Dec 2025 10:46:59 -0500 Subject: [PATCH 64/81] Add dedicated contexts for DSC Desired State Configuration --- PowerShell.sublime-syntax | 65 ++++++++++++++++- Tests/syntax_test_DSC.ps1 | 116 +++++++++++++++++++++++++++++++ Tests/syntax_test_PowerShell.ps1 | 16 ----- 3 files changed, 178 insertions(+), 19 deletions(-) create mode 100644 Tests/syntax_test_DSC.ps1 diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index df9e2e78..66fb4ec0 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -50,6 +50,7 @@ contexts: - include: classes - include: expressions - include: functions + - include: desired-state-configurations - match: \B\.(?= ) scope: support.function.source.powershell @@ -363,13 +364,13 @@ contexts: ###[ FUNCTIONS ]############################################################### functions: - - match: ^\s*(?i)(function|filter|configuration|workflow)(?=\s) + - match: ^\s*(?i)(function|filter|workflow)(?=\s) captures: 1: keyword.declaration.function.powershell push: [function-body, function-inline-params, function-name] function-name: - - match: (?:(global|local|script|private):)?({{identifier_function}}+) + - match: (?:(global|local|script|private):)?({{identifier_function}}) captures: 1: storage.modifier.scope.powershell 2: entity.name.function.powershell @@ -442,8 +443,11 @@ contexts: pop: 1 - include: comma-separators - include: attributes - - include: types + - include: types-without-members - include: variables-without-members + - include: literals + - match: '=' + scope: keyword.operator.assignment.powershell workflow-execution-contexts: - match: \b(?i:inlinescript){{kebab_break}} @@ -477,6 +481,61 @@ contexts: 2: keyword.operator.assignment.powershell - include: expressions +###[ DESIRED STATE CONFIGURATIONS ]############################################ + + desired-state-configurations: + - match: ^\s*(?i)(configuration)(?=\s) + captures: + 1: keyword.declaration.function.powershell + push: + - desired-state-configuration-body + - desired-state-configuration-name + + desired-state-configuration-name: + - match: '{{identifier_function}}' + scope: entity.name.function.powershell + - match: (?=[{(]) + pop: 1 + + desired-state-configuration-body: + - meta_scope: meta.function.powershell + - match: \{ + scope: punctuation.section.block.begin.powershell + push: inside-desired-state-configuration-body + - include: else-pop + + inside-desired-state-configuration-body: + - match: \} + scope: punctuation.section.block.end.powershell + pop: 2 + + - match: \b(?i:Param){{kebab_break}} + scope: keyword.declaration.parameter.powershell # This scope is not standard + push: expect-param-context + + - match: \b(?i:Node){{kebab_break}} + scope: keyword.context.block.powershell + push: expect-node-context + + - include: attributes + + expect-node-context: + - match: \{ + scope: punctuation.section.block.begin.powershell + push: inside-node-context + - include: expressions + - include: else-pop + + inside-node-context: + - match: \} + scope: punctuation.section.block.end.powershell + pop: 2 + - match: \b((?i:WindowsFeature))\s+({{identifier_csharp}}) + captures: + 1: keyword.other.powershell + 2: entity.name.label.powershell + - include: expressions + ###[ VARIABLES ]############################################################### variables: diff --git a/Tests/syntax_test_DSC.ps1 b/Tests/syntax_test_DSC.ps1 new file mode 100644 index 00000000..ff66f2e4 --- /dev/null +++ b/Tests/syntax_test_DSC.ps1 @@ -0,0 +1,116 @@ +# SYNTAX TEST "Packages/PowerShell/PowerShell.sublime-syntax" + +"<- Exit the imports context block" + + Configuration MyDscConfiguration { +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.function.powershell +# ^^^^^^^^^^^^^ keyword.declaration.function.powershell +# ^^^^^^^^^^^^^^^^^^ entity.name.function.powershell +# ^ punctuation.section.block.begin.powershell + Node "TEST-PC1" { +#^^^^^^^^^^^^^^^^^^^^^^^^ meta.function.powershell +# ^^^^ keyword.context.block.powershell +# ^^^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^ punctuation.section.block.begin.powershell + WindowsFeature MyFeatureInstance { +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.function.powershell +# ^^^^^^^^^^^^^^ keyword.other.powershell +# ^^^^^^^^^^^^^^^^^ entity.name.label.powershell +# ^ meta.block.powershell punctuation.section.braces.begin.powershell + Ensure = 'Present' +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.function.powershell meta.block.powershell +# ^ keyword.operator.assignment.powershell +# ^^^^^^^^^ meta.string.powershell string.quoted.single.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell + Name = 'RSAT' + } + WindowsFeature My2ndFeatureInstance { +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.function.powershell +# ^^^^^^^^^^^^^^ keyword.other.powershell +# ^^^^^^^^^^^^^^^^^^^^ entity.name.label.powershell +# ^ meta.block.powershell punctuation.section.braces.begin.powershell + Ensure = 'Present' + Name = 'Bitlocker' + } +#^^^^^^^^^^^^ meta.function.powershell meta.block.powershell +# ^ punctuation.section.braces.end.powershell + } + } + MyDscConfiguration + + + Configuration MyDscConfiguration + { + param +#^^^^^^^^^^^^ meta.function.powershell +# ^^^^^ keyword.declaration.parameter.powershell + ( + [string[]]$ComputerName='localhost' +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.function.powershell +# ^ punctuation.section.brackets.begin.powershell +# ^^^^^^ storage.type.powershell +# ^ punctuation.section.brackets.begin.powershell +# ^^ punctuation.section.brackets.end.powershell +# ^^^^^^^^^^^^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^ keyword.operator.assignment.powershell +# ^^^^^^^^^^^ meta.string.powershell string.quoted.single.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell + ) + + Node $ComputerName + { + WindowsFeature MyFeatureInstance + { + Ensure = 'Present' + Name = 'RSAT' + } + + WindowsFeature My2ndFeatureInstance + { + Ensure = 'Present' + Name = 'Bitlocker' + } + } + } + MyDscConfiguration + + + Configuration MyDscConfiguration + { + Node @('localhost', 'Server01') +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.function.powershell +# ^^^^ keyword.context.block.powershell +# ^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.group.array-expression.powershell +# ^ keyword.other.array.begin.powershell +# ^ punctuation.section.group.begin.powershell +# ^^^^^^^^^^^ meta.string.powershell string.quoted.single.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^ punctuation.separator.sequence.powershell +# ^^^^^^^^^^ meta.string.powershell string.quoted.single.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^ punctuation.section.group.end.powershell + { + WindowsFeature MyFeatureInstance +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.function.powershell +# ^^^^^^^^^^^^^^ keyword.other.powershell +# ^^^^^^^^^^^^^^^^^ entity.name.label.powershell + { + Ensure = 'Present' + Name = 'RSAT' + } + + WindowsFeature My2ndFeatureInstance + { + Ensure = 'Present' + Name = 'Bitlocker' + } + } + } + MyDscConfiguration diff --git a/Tests/syntax_test_PowerShell.ps1 b/Tests/syntax_test_PowerShell.ps1 index 3b9641bf..d6a87302 100644 --- a/Tests/syntax_test_PowerShell.ps1 +++ b/Tests/syntax_test_PowerShell.ps1 @@ -1382,22 +1382,6 @@ catch { } # ^ punctuation.section.braces.begin # ^ punctuation.section.braces.end -# Reserved words -Configuration Crazyness { -#^^^^^^^^^^^^^^^^^^^^^^^^ meta.function.powershell -#^^^^^^^^^^^^ keyword.declaration.function.powershell -# ^^^^^^^^^ entity.name.function.powershell -# @@@@@@@@@ definition -# ^ punctuation.section.block.begin.powershell - Node Whatever { -# ^ punctuation.section.braces.begin - } -#^^^^ meta.function.powershell meta.block.powershell -# ^ punctuation.section.braces.end.powershell - } -#^^^^ meta.function.powershell -# ^ punctuation.section.block.end.powershell - # Redirection notepad.exe > log.txt #^^^^^^^^^^ variable.function From aec13fa16df73e139e45b49d69288ccbb87b8840 Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Mon, 8 Dec 2025 11:09:44 -0500 Subject: [PATCH 65/81] Add dedicated contexts for workflows --- PowerShell.sublime-syntax | 43 +++++++-- Tests/syntax_test_PowerShell.ps1 | 18 ---- Tests/syntax_test_Workflow.ps1 | 155 +++++++++++++++++++++++++++++++ 3 files changed, 190 insertions(+), 26 deletions(-) create mode 100644 Tests/syntax_test_Workflow.ps1 diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index 66fb4ec0..6015591a 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -50,6 +50,7 @@ contexts: - include: classes - include: expressions - include: functions + - include: workflows - include: desired-state-configurations - match: \B\.(?= ) @@ -364,7 +365,7 @@ contexts: ###[ FUNCTIONS ]############################################################### functions: - - match: ^\s*(?i)(function|filter|workflow)(?=\s) + - match: ^\s*(?i)(function|filter)(?=\s) captures: 1: keyword.declaration.function.powershell push: [function-body, function-inline-params, function-name] @@ -419,6 +420,7 @@ contexts: - include: statements expect-function-context: + - meta_scope: meta.block.powershell - match: \{ scope: punctuation.section.block.begin.powershell push: inside-function-context @@ -427,7 +429,7 @@ contexts: inside-function-context: - match: \} scope: punctuation.section.block.end.powershell - pop: 1 + pop: 2 - include: workflow-execution-contexts - include: statements @@ -449,12 +451,6 @@ contexts: - match: '=' scope: keyword.operator.assignment.powershell - workflow-execution-contexts: - - match: \b(?i:inlinescript){{kebab_break}} - scope: keyword.control.context.powershell - - match: \b(?i:parallel|sequence){{kebab_break}} - scope: keyword.control.flow.powershell - attributes: - match: (\[)\s*({{attributes}}) captures: @@ -481,6 +477,37 @@ contexts: 2: keyword.operator.assignment.powershell - include: expressions +###[ WORKFLOWS ]############################################################### + + workflows: + - match: ^\s*(?i)(workflow)(?=\s) + captures: + 1: keyword.declaration.function.powershell + push: [function-body, function-name] + + workflow-body: + - meta_scope: meta.function.powershell + - match: \{ + scope: punctuation.section.block.begin.powershell + push: inside-workflow-body + with_prototype: + - include: workflow-execution-contexts + - include: else-pop + + inside-workflow-body: + - match: \} + scope: punctuation.section.block.end.powershell + pop: 2 + - include: statements + + workflow-execution-contexts: + - match: \b(?i:inlinescript){{kebab_break}} + scope: keyword.control.context.powershell + push: expect-function-context + - match: \b(?i:parallel|sequence){{kebab_break}} + scope: keyword.control.flow.powershell + push: expect-function-context + ###[ DESIRED STATE CONFIGURATIONS ]############################################ desired-state-configurations: diff --git a/Tests/syntax_test_PowerShell.ps1 b/Tests/syntax_test_PowerShell.ps1 index d6a87302..e3c11520 100644 --- a/Tests/syntax_test_PowerShell.ps1 +++ b/Tests/syntax_test_PowerShell.ps1 @@ -1619,24 +1619,6 @@ $ScriptBlock | Out-File $file -Force # ^ punctuation.definition.variable # ^ punctuation.definition.parameter # ^^^^^^ variable.parameter.option -workflow w1 {} -#^^^^^^^^^^^^^ meta.function.powershell -#^^^^^^^ keyword.declaration.function.powershell -# ^^ entity.name.function.powershell -# @@ definition -# ^ punctuation.section.block.begin.powershell -# ^ punctuation.section.block.end.powershell -Workflow work { sequence {} } -#^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.function.powershell -#^^^^^^^ keyword.declaration.function.powershell -# ^^^^ entity.name.function.powershell -# @@@@ definition -# ^ punctuation.section.block.begin.powershell -# ^^^^^^^^ keyword.control.flow.powershell -# ^^ meta.block.powershell -# ^ punctuation.section.braces.begin.powershell -# ^ punctuation.section.braces.end.powershell -# ^ punctuation.section.block.end.powershell function get-something {} # @@@@@@@@@@@@@ definition function Out-WithYou {} diff --git a/Tests/syntax_test_Workflow.ps1 b/Tests/syntax_test_Workflow.ps1 new file mode 100644 index 00000000..dbe3d2ce --- /dev/null +++ b/Tests/syntax_test_Workflow.ps1 @@ -0,0 +1,155 @@ +# SYNTAX TEST "Packages/PowerShell/PowerShell.sublime-syntax" + +"<- Exit the imports context block" + + workflow w1 {} +#^^^^^^^^^^^^^^^^^ meta.function.powershell +# ^^^^^^^^ keyword.declaration.function.powershell +# ^^ entity.name.function.powershell +# @@ definition +# ^ punctuation.section.block.begin.powershell +# ^ punctuation.section.block.end.powershell + Workflow work { sequence {} } +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.function.powershell +# ^^^^^^^^ keyword.declaration.function.powershell +# ^^^^ entity.name.function.powershell +# @@@@ definition +# ^ punctuation.section.block.begin.powershell +# ^^^^^^^^^^^ meta.block.powershell +# ^^^^^^^^ keyword.control.flow.powershell +# ^ punctuation.section.block.begin.powershell +# ^ punctuation.section.block.end.powershell +# ^ punctuation.section.block.end.powershell + + workflow Test-Workflow { +#^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.function.powershell +# ^^^^^^^^ keyword.declaration.function.powershell +# ^^^^^^^^^^^^^ entity.name.function.powershell +# @@@@@@@@@@@@@ definition +# ^ punctuation.section.block.begin.powershell + parallel { +#^^^^^^^^^^^^^^^^^ meta.function.powershell +# ^^^^^^^^ keyword.control.flow.powershell +# ^ punctuation.section.block.begin.powershell + Get-Process +# @@@@@@@@@@@ reference + Get-Service +#^^^^^^^^^^^^^^^^^^^^^^^ meta.function.powershell +# ^^^^^^^^^^^ meta.function-call.powershell support.function.powershell +# @@@@@@@@@@@ reference + } + } + + + workflow Test-Workflow { +# @@@@@@@@@@@@@ definition + $a = 3 +#^^^^^^^^^^^^^ meta.function.powershell +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^ keyword.operator.assignment.powershell +# ^ meta.number.integer.decimal.powershell constant.numeric.value.powershell + + ## Without $Using, the $a workflow variable isn't visible + ## in inline script. + inlinescript {"Inline A0 = $a"} +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.function.powershell +# ^^^^^^^^^^^^ keyword.control.context.powershell +# ^ punctuation.section.block.begin.powershell +# ^^^^^^^^^^^^^^^^ meta.string.interpolated.powershell +# ^^^^^^^^^^^^^ string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^^ meta.interpolation.powershell variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^ string.quoted.double.powershell punctuation.definition.string.end.powershell +# ^ punctuation.section.block.end.powershell + + ## $Using imports the variable and its current value. + inlinescript {"Inline A1 = $Using:a"} + } + Test-Workflow +# @@@@@@@@@@@@@ reference + + + workflow Test-Workflow { +# @@@@@@@@@@@@@ definition + $a = 3 + + ## Changes to the inlinescript variable value don't + ## change the workflow variable. + inlinescript { + $a = $Using:a+1; + "Inline A = $a" + } + "Workflow A = $a" + + ## To change the variable in workflow scope, return the + ## new value. + $a = inlinescript {$b = $Using:a+1; $b} + "Workflow New A = $a" + } + Test-Workflow +# @@@@@@@@@@@@@ reference + + + workflow Test-Workflow { +# @@@@@@@@@@@@@ definition + $ie = inlinescript { + $ie = New-Object -ComObject InternetExplorer.Application -Property @{navigate2="www.microsoft.com"} +# @@@@@@@@@@ reference + + $ie.Visible = $true +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.function.powershell +# ^^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^ punctuation.accessor.dot.powershell +# ^^^^^^^ variable.other.member.powershell +# ^ keyword.operator.assignment.powershell +# ^^^^^ constant.language.boolean.true.powershell +# ^ punctuation.definition.variable.powershell + } + + $ie + } + Test-Workflow +# @@@@@@@@@@@@@ reference + + + workflow Test-Workflow { +# @@@@@@@@@@@@@ definition + parallel { + Get-Process +# @@@@@@@@@@@ reference + Get-Service +#^^^^^^^^^^^^^^^^^^^^^^^ meta.function.powershell +# ^^^^^^^^^^^ meta.function-call.powershell support.function.powershell +# @@@@@@@@@@@ reference + + sequence { +# ^ meta.function.powershell meta.block.powershell meta.block.powershell punctuation.section.block.begin.powershell + $Hotfix = Get-Content 'D:\HotFixes\Required.txt' +# @@@@@@@@@@@ reference + foreach ($h in $Hotfix) {'D:\Scripts\Verify-Hotfix' -Hotfix $h} +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.function.powershell meta.block.powershell meta.block.powershell +# ^^^^^^^ keyword.control.loop.for.powershell +# ^^^^^^^^^^^^^^^ meta.group.powershell +# ^ punctuation.section.group.begin.powershell +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^^ keyword.control.loop.in.powershell +# ^^^^^^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^ punctuation.section.group.end.powershell +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.block.powershell +# ^ punctuation.section.braces.begin.powershell +# ^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string.powershell string.quoted.single.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^^^^^^^ variable.parameter.option.powershell +# ^ punctuation.definition.parameter.powershell +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^ punctuation.section.braces.end.powershell + } + } + } From a9138a483a67208e58d3afe5983cfda9a71ef784 Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Mon, 8 Dec 2025 12:02:03 -0500 Subject: [PATCH 66/81] Use named contexts for group-likes --- PowerShell.sublime-syntax | 92 ++++++++++++++++++++++----------------- 1 file changed, 51 insertions(+), 41 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index 6015591a..60577a0a 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -168,71 +168,81 @@ contexts: groups: - match: \( scope: punctuation.section.group.begin.powershell - push: - - meta_scope: meta.group.powershell - - match: \) - scope: punctuation.section.group.end.powershell - set: members - # TODO: Move this to a foreach (X in Y) construct - - match: \b(?i:in){{kebab_break}} - scope: keyword.control.loop.in.powershell - - include: attributes - - include: expressions + push: inside-group + + inside-group: + - meta_scope: meta.group.powershell + - match: \) + scope: punctuation.section.group.end.powershell + set: members + # TODO: Move this to a foreach (X in Y) construct + - match: \b(?i:in){{kebab_break}} + scope: keyword.control.loop.in.powershell + - include: attributes + - include: expressions arrays: - match: (@)(\() captures: 1: keyword.other.array.begin.powershell 2: punctuation.section.group.begin.powershell - push: - - meta_scope: meta.group.array-expression.powershell - - match: \) - scope: punctuation.section.group.end.powershell - pop: 1 - - include: expressions + push: inside-array + + inside-array: + - meta_scope: meta.group.array-expression.powershell + - match: \) + scope: punctuation.section.group.end.powershell + pop: 1 + - include: expressions hashtables: - match: (@)(\{) captures: 1: keyword.other.hashtable.begin.powershell 2: punctuation.section.braces.begin.powershell - push: - - meta_scope: meta.hashtable.powershell - - match: \} - scope: punctuation.section.braces.end.powershell - pop: 1 - - match: \b(['"]?)(\w+)(['"]?)\s*(=)\s* - scope: meta.hashtable.assignment.powershell - captures: - 1: punctuation.definition.string.begin.powershell - 2: variable.other.readwrite.powershell - 3: punctuation.definition.string.end.powershell - 4: keyword.operator.assignment.powershell - - include: expressions + push: inside-hashtable + + inside-hashtable: + - meta_scope: meta.hashtable.powershell + - match: \} + scope: punctuation.section.braces.end.powershell + pop: 1 + - match: \b(['"]?)(\w+)(['"]?)\s*(=)\s* + scope: meta.hashtable.assignment.powershell + captures: + 1: punctuation.definition.string.begin.powershell + 2: variable.other.readwrite.powershell + 3: punctuation.definition.string.end.powershell + 4: keyword.operator.assignment.powershell + - include: expressions subexpressions: - match: (\$)(\() captures: 1: keyword.other.variable.definition.powershell 2: punctuation.section.group.begin.powershell - push: - - meta_scope: meta.group.complex.subexpression.powershell - - match: \) - scope: punctuation.section.group.end.powershell - pop: 1 - - include: expressions + push: inside-subexpression + + inside-subexpression: + - meta_scope: meta.group.complex.subexpression.powershell + - match: \) + scope: punctuation.section.group.end.powershell + pop: 1 + - include: expressions script-blocks: - match: (%)?(\{) captures: 1: keyword.control.loop.for.powershell 2: punctuation.section.braces.begin.powershell - push: - - meta_scope: meta.block.powershell - - match: \} - scope: punctuation.section.braces.end.powershell - pop: 1 - - include: statements + push: inside-script-block + + inside-script-block: + - meta_scope: meta.block.powershell + - match: \} + scope: punctuation.section.braces.end.powershell + pop: 1 + - include: statements ###[ COMMANDS ]################################################################ From d56121f1b9a4525639b246742ff0cb03ae81e341 Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Mon, 8 Dec 2025 12:10:44 -0500 Subject: [PATCH 67/81] Update hashtable scopes --- PowerShell.sublime-syntax | 19 ++++++--- Tests/syntax_test_PowerShell.ps1 | 68 +++++++++++++++++++------------- 2 files changed, 54 insertions(+), 33 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index 60577a0a..a6c049df 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -207,13 +207,22 @@ contexts: - match: \} scope: punctuation.section.braces.end.powershell pop: 1 - - match: \b(['"]?)(\w+)(['"]?)\s*(=)\s* - scope: meta.hashtable.assignment.powershell + - match: \b(({{single_quote}}){{identifier_simple}}({{single_quote}}))\s*(=)\s* captures: - 1: punctuation.definition.string.begin.powershell - 2: variable.other.readwrite.powershell + 1: meta.mapping.key.powershell string.quoted.single.powershell + 2: punctuation.definition.string.begin.powershell 3: punctuation.definition.string.end.powershell - 4: keyword.operator.assignment.powershell + 4: punctuation.separator.key-value.powershell + - match: \b(({{double_quote}}){{identifier_simple}}({{double_quote}}))\s*(=)\s* + captures: + 1: meta.mapping.key.powershell string.quoted.double.powershell + 2: punctuation.definition.string.begin.powershell + 3: punctuation.definition.string.end.powershell + 4: punctuation.separator.key-value.powershell + - match: \b({{identifier_simple}})\s*(=)\s* + captures: + 1: meta.mapping.key.powershell string.unquoted.powershell + 2: punctuation.separator.key-value.powershell - include: expressions subexpressions: diff --git a/Tests/syntax_test_PowerShell.ps1 b/Tests/syntax_test_PowerShell.ps1 index e3c11520..42ba44a6 100644 --- a/Tests/syntax_test_PowerShell.ps1 +++ b/Tests/syntax_test_PowerShell.ps1 @@ -68,24 +68,25 @@ using namespace System.Management.Automation # ^^^^^^^^ variable.parameter #Requires -Modules PSWorkflow, @{ModuleName="PSScheduledJob"; ModuleVersion="1.0.0.0"} # <- punctuation.definition.keyword -#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.requires +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.requires #^^^^^^^^ keyword.control.import.require # ^^^^^^^^ variable.parameter # ^ punctuation.separator -# ^^^^^^^^^^ meta.requires meta.hashtable variable.other.readwrite -# ^ meta.requires meta.hashtable -# ^^^^^^^^^^^^^^^^ meta.requires meta.hashtable string.quoted.double -# ^ meta.requires meta.hashtable punctuation.terminator.statement -# ^^^^^^^^^^^^^ meta.requires meta.hashtable variable.other.readwrite -# ^ meta.requires meta.hashtable -# ^^^^^^^^^ meta.requires meta.hashtable string.quoted.double +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.hashtable.powershell +# ^^^^^^^^^^ meta.mapping.key string.unquoted +# ^ punctuation.separator.key-value.powershell +# ^^^^^^^^^^^^^^^^ string.quoted.double +# ^ punctuation.terminator.statement +# ^^^^^^^^^^^^^ meta.mapping.key string.unquoted +# ^ punctuation.separator.key-value.powershell +# ^^^^^^^^^ string.quoted.double :label1 # ^^^^^^^ entity.name.label.powershell # ^ punctuation.definition.label.powershell throw "Do not run this file!" -# <- keyword.control +# <- keyword.control.exception # ^^^^^^^^^^^^^^^^^^^^^^^ string.quoted.double # Stop parsing @@ -241,33 +242,44 @@ $properties = @{ # ^ keyword.other.hashtable.begin # ^ punctuation.section.braces.begin Name = 'Name' - # <- meta.hashtable meta.hashtable.assignment variable.other.readwrite - # ^ meta.hashtable meta.hashtable.assignment keyword.operator.assignment - # ^ meta.hashtable string.quoted.single +#^^^^^^^^^^^^^^^^^^^^^ meta.hashtable.powershell +# ^^^^ meta.mapping.key.powershell string.unquoted.powershell +# ^ punctuation.separator.key-value.powershell +# ^^^^^^ meta.string.powershell string.quoted.single.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell Something = $else #^^^^^^^^^^^^^^^^^^^^ meta.hashtable.powershell -# ^^^^^^^^^^^^ meta.hashtable.assignment.powershell -# ^^^^^^^^^ variable.other.readwrite.powershell -# ^ keyword.operator.assignment.powershell +# ^^^^^^^^^ meta.mapping.key.powershell string.unquoted.powershell +# ^ punctuation.separator.key-value.powershell # ^^^^^ variable.other.readwrite.powershell # ^ punctuation.definition.variable.powershell Number = 16 - # <- meta.hashtable meta.hashtable.assignment variable.other.readwrite - # ^ meta.hashtable meta.hashtable.assignment keyword.operator.assignment - # ^^ meta.hashtable meta.number.integer.decimal constant.numeric.value +#^^^^^^^^^^^^^^^^^ meta.hashtable.powershell +# ^^^^^^ meta.mapping.key.powershell string.unquoted.powershell +# ^ punctuation.separator.key-value.powershell +# ^^ meta.number.integer.decimal.powershell constant.numeric.value.powershell from = 'hello world' - # <- meta.hashtable meta.hashtable.assignment variable.other.readwrite - # ^ meta.hashtable meta.hashtable.assignment keyword.operator.assignment - # ^^^^^^^^^^^^^ meta.hashtable string.quoted.single +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.hashtable.powershell +# ^^^^ meta.mapping.key.powershell string.unquoted.powershell +# ^ punctuation.separator.key-value.powershell +# ^^^^^^^^^^^^^ meta.string.powershell string.quoted.single.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell hash = @{ - # <- meta.hashtable meta.hashtable.assignment variable.other.readwrite - # ^ meta.hashtable meta.hashtable.assignment keyword.operator.assignment - # ^ keyword.other.hashtable.begin - # ^ punctuation.section.braces.begin +#^^^^^^^^^^^^^^^^^ meta.hashtable.powershell +# ^^^^ meta.mapping.key.powershell string.unquoted.powershell +# ^ punctuation.separator.key-value.powershell +# ^^ meta.hashtable.powershell +# ^ keyword.other.hashtable.begin.powershell +# ^ punctuation.section.braces.begin.powershell hello = 'world' - # <- meta.hashtable meta.hashtable.assignment variable.other.readwrite - # ^ meta.hashtable meta.hashtable.assignment keyword.operator.assignment - # ^^^^^^^ meta.hashtable string.quoted.single +#^^^^^^^^^^^^^^^^^^^^^^ meta.hashtable.powershell meta.hashtable.powershell +# ^^^^^ meta.mapping.key.powershell string.unquoted.powershell +# ^ punctuation.separator.key-value.powershell +# ^^^^^^^ meta.string.powershell string.quoted.single.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell } # <- punctuation.section.braces.end } From 82f5288f867b0f6631402c2c139a43672639b271 Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Mon, 8 Dec 2025 16:39:37 -0500 Subject: [PATCH 68/81] Rescope the source operator --- PowerShell.sublime-syntax | 11 ++++--- Tests/syntax_test_PowerShell.ps1 | 53 +++++++++++++++++--------------- 2 files changed, 36 insertions(+), 28 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index a6c049df..0f3342f6 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -48,19 +48,22 @@ contexts: statements: - include: redirection - include: classes - - include: expressions - include: functions - include: workflows - include: desired-state-configurations - - match: \B\.(?= ) - scope: support.function.source.powershell - - include: exceptions - include: loops - include: flow - include: conditionals + - match: \B\.(?= ) + scope: keyword.operator.source.powershell + - match: \& + scope: keyword.operator.call.powershell + + - include: expressions + expressions: # Meta - include: labels diff --git a/Tests/syntax_test_PowerShell.ps1 b/Tests/syntax_test_PowerShell.ps1 index 42ba44a6..ee61724b 100644 --- a/Tests/syntax_test_PowerShell.ps1 +++ b/Tests/syntax_test_PowerShell.ps1 @@ -91,7 +91,7 @@ throw "Do not run this file!" # Stop parsing & tool.exe /arg1 'value' /arg2 $value --% /arg3 $value /arg4 "value" # Comment -# <- keyword.operator.background +# <- keyword.operator.call # ^^^^^^^^ variable.function # ^ punctuation.definition.parameter # ^^^^^ variable.parameter.option @@ -101,7 +101,7 @@ throw "Do not run this file!" # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ string.unquoted - constant - variable - comment & gnutool.exe -s 'short option' --long-option --very_long_option value +plus-option -#<- keyword.operator.background +#<- keyword.operator.call # ^^^^^^^^^^^ variable.function # ^ variable.parameter.option punctuation.definition.parameter # ^ variable.parameter.option @@ -873,28 +873,33 @@ $a3[1..2] # ^ keyword.operator.logical.pipe # ^^^^^^^^^^^^^^^^ support.function -# Commands (Built-in variables) -ls *.ps1 -recurse -# ^ keyword.operator -# ^ punctuation.definition.parameter -# ^^^^^^^^ variable.parameter.option - -# Commands (executable files) -. .\scripts\Test-Foo.ps1 -parameter 'value' -# ^^^^^^^^^^^^^^^^^^^^^^ meta.function-call.powershell support.function.powershell -# @@@@@@@@@@@@@@@@@@@@@@ reference -# ^^^^^^^^^^ variable.parameter.option.powershell -# ^ punctuation.definition.parameter.powershell -# ^^^^^^^ meta.string.powershell string.quoted.single.powershell -# ^ punctuation.definition.string.begin.powershell -# ^ punctuation.definition.string.end.powershell -& tool.exe -# <- keyword.operator.background -# ^^^^^^^^ variable.function -something.cmd -#^^^^^^^^^^^^ variable.function - øyvind.com -#^^^^^^^^^^ variable.function + # Commands (Built-in variables) + ls *.ps1 -recurse +# ^ keyword.operator.arithmetic.powershell +# ^^^^^^^^ variable.parameter.option.powershell +# ^ punctuation.definition.parameter.powershell + + # Commands (executable files) + . .\scripts\Test-Foo.ps1 -parameter 'value' +# ^ keyword.operator.source.powershell +# ^^^^^^^^^^^^^^^^^^^^^^ meta.function-call.powershell support.function.powershell +# @@@@@@@@@@@@@@@@@@@@@@ reference +# ^^^^^^^^^^ variable.parameter.option.powershell +# ^ punctuation.definition.parameter.powershell +# ^^^^^^^ meta.string.powershell string.quoted.single.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell + + & tool.exe +# ^ keyword.operator.call.powershell +# ^^^^^^^^ variable.function.powershell + + something.cmd +# ^^^^^^^^^^^^^ variable.function.powershell + + øyvind.com +# ^^^^^^^^^^ variable.function.powershell + # switch switch ("fourteen") {} From 361ad86d7df42e76a2de64a43d915723e8fe1e06 Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Mon, 8 Dec 2025 20:23:45 -0500 Subject: [PATCH 69/81] Rescope the variable scope colon --- PowerShell.sublime-syntax | 8 ++++---- Tests/syntax_test_PowerShell.ps1 | 9 +++++---- Tests/syntax_test_strings.ps1 | 4 ++-- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index 0f3342f6..e1a52b27 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -622,11 +622,11 @@ contexts: - match: ({{var_scope_mod}})(:) captures: 1: storage.modifier.scope.powershell - 2: punctuation.separator.sequence.powershell + 2: punctuation.accessor.colon.powershell - match: ({{identifier_simple}})(:) captures: 1: support.variable.drive.powershell - 2: punctuation.separator.sequence.powershell + 2: punctuation.accessor.colon.powershell - match: '{{identifier_simple}}' - include: immediately-pop @@ -641,11 +641,11 @@ contexts: - match: ({{var_scope_mod}})(:) captures: 1: storage.modifier.scope.powershell - 2: punctuation.separator.sequence.powershell + 2: punctuation.accessor.colon.powershell - match: ({{identifier_simple}})(:) captures: 1: support.variable.drive.powershell - 2: punctuation.separator.sequence.powershell + 2: punctuation.accessor.colon.powershell members: - match: (?=\.\.) diff --git a/Tests/syntax_test_PowerShell.ps1 b/Tests/syntax_test_PowerShell.ps1 index ee61724b..f974c6e2 100644 --- a/Tests/syntax_test_PowerShell.ps1 +++ b/Tests/syntax_test_PowerShell.ps1 @@ -177,12 +177,13 @@ throw "Do not run this file!" # ^^^^^^^^^^^^^^^^ variable.other.readwrite.powershell # ^ punctuation.definition.variable.powershell # ^^^^^^ storage.modifier.scope.powershell -# ^ punctuation.separator.sequence.powershell +# ^ punctuation.accessor.colon.powershell $ENV:ComputerName # ^^^^^^^^^^^^^^^^^ variable.other.readwrite.powershell # ^ punctuation.definition.variable.powershell # ^^^ support.variable.drive.powershell -# ^ punctuation.separator.sequence.powershell +# ^ punctuation.accessor.colon.powershell +# ^^^^^^^^^^^^^^^^^ variable.other.readwrite.powershell ${variable} # ^^^^^^^^^^^ variable.other.readwrite.powershell # ^ punctuation.definition.variable.powershell @@ -210,7 +211,7 @@ throw "Do not run this file!" # ^ punctuation.definition.variable.powershell # ^ punctuation.section.interpolation.begin.powershell # ^^^^^^ storage.modifier.scope.powershell -# ^ punctuation.separator.sequence.powershell +# ^ punctuation.accessor.colon.powershell # ^ punctuation.section.interpolation.end.powershell @@ -1605,7 +1606,7 @@ $file = join-path $env:SystemDrive "$([System.io.path]::GetRandomFileName()).ps1 # ^^^^^^^^^^^^^^^^ variable.other.readwrite.powershell # ^ punctuation.definition.variable.powershell # ^^^ support.variable.drive.powershell -# ^ punctuation.separator.sequence.powershell +# ^ punctuation.accessor.colon.powershell # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string.interpolated.powershell # ^ string.quoted.double.powershell punctuation.definition.string.begin.powershell # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.interpolation.powershell diff --git a/Tests/syntax_test_strings.ps1 b/Tests/syntax_test_strings.ps1 index 9ba374eb..0e1c7195 100644 --- a/Tests/syntax_test_strings.ps1 +++ b/Tests/syntax_test_strings.ps1 @@ -130,7 +130,7 @@ # ^^^^^^^^^^^^^^^^^ meta.interpolation.powershell variable.other.readwrite.powershell # ^ punctuation.definition.variable.powershell # ^^^ support.variable.drive.powershell -# ^ punctuation.separator.sequence.powershell +# ^ punctuation.accessor.colon.powershell # ^ string.quoted.double.powershell punctuation.definition.string.end.powershell # Here as well @@ -142,7 +142,7 @@ # ^ punctuation.definition.variable.powershell # ^ punctuation.section.interpolation.begin.powershell # ^^^ support.variable.drive.powershell -# ^ punctuation.separator.sequence.powershell +# ^ punctuation.accessor.colon.powershell # ^ punctuation.section.interpolation.end.powershell # ^ string.quoted.double.powershell punctuation.definition.string.end.powershell From 755fdb55ed09ff2fc29caf7029b5e15818d8706b Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Mon, 8 Dec 2025 15:08:32 -0500 Subject: [PATCH 70/81] Recognize first statement as a command --- PowerShell.sublime-syntax | 133 +++-- Tests/syntax_test_Class.ps1 | 19 + Tests/syntax_test_PowerShell.ps1 | 802 +++++++++++++++++++++++-------- Tests/syntax_test_Workflow.ps1 | 21 +- 4 files changed, 726 insertions(+), 249 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index e1a52b27..bfe81a2f 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -46,7 +46,6 @@ contexts: - include: else-pop statements: - - include: redirection - include: classes - include: functions - include: workflows @@ -83,28 +82,43 @@ contexts: - include: hashtables - include: arrays + - include: data-blocks + - include: script-blocks + - include: groups + - include: subexpressions + + - include: future-reserved-words + + - include: operators - include: commands + expressions-without-commands: + # Meta + - include: labels + - include: regions + - include: requires-directives + + - include: escape-sequences + - include: literal-after + + # Normal code + - include: types + - include: strings + - include: numbers + - include: constants + - include: variables + + - include: hashtables + - include: arrays + - include: data-blocks - include: script-blocks - include: groups - include: subexpressions - # Consume a string with a trailing dot to prevent members with - # particular names from being recognized as keywords. - - match: \b[\w-]+(?=\.) - scope: variable.other.object.powershell - push: members - - # "Reserved for future use" - # https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_reserved_words - - match: \b(?i:define|from){{kebab_break}} - scope: keyword.control.powershell - - match: \b(?i:var){{kebab_break}} - scope: keyword.declaration.variable.powershell + - include: future-reserved-words - include: operators - - include: parameters literal-after: - match: \B--%\B @@ -114,6 +128,13 @@ contexts: - meta_content_scope: string.unquoted.powershell - include: pop-before-eol + future-reserved-words: + # https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_reserved_words + - match: \b(?i:define|from){{kebab_break}} + scope: keyword.control.powershell + - match: \b(?i:var){{kebab_break}} + scope: keyword.declaration.variable.powershell + ###[ EXCEPTIONS ]############################################################## exceptions: @@ -161,6 +182,7 @@ contexts: scope: keyword.control.conditional.else.powershell - match: \b(?i:switch){{kebab_break}} scope: keyword.control.conditional.switch.powershell + push: in-command - match: \b(?i:default){{kebab_break}} scope: keyword.control.conditional.default.powershell - match: \b(?i:where(?!-object)){{kebab_break}} @@ -189,7 +211,7 @@ contexts: captures: 1: keyword.other.array.begin.powershell 2: punctuation.section.group.begin.powershell - push: inside-array + push: [members, inside-array] inside-array: - meta_scope: meta.group.array-expression.powershell @@ -203,7 +225,7 @@ contexts: captures: 1: keyword.other.hashtable.begin.powershell 2: punctuation.section.braces.begin.powershell - push: inside-hashtable + push: [members, inside-hashtable] inside-hashtable: - meta_scope: meta.hashtable.powershell @@ -247,13 +269,14 @@ contexts: captures: 1: keyword.control.loop.for.powershell 2: punctuation.section.braces.begin.powershell - push: inside-script-block + push: [members, inside-script-block] inside-script-block: - meta_scope: meta.block.powershell - match: \} scope: punctuation.section.braces.end.powershell pop: 1 + - include: param-block - include: statements ###[ COMMANDS ]################################################################ @@ -262,6 +285,7 @@ contexts: - include: commands-verb-noun - include: commands-reserved - include: script-invocation + - include: command-freeform commands-verb-noun: # The "Verb-Noun" pattern @@ -273,17 +297,57 @@ contexts: (?:\.(?i:exe|cmd|bat|ps1))?\b # More path stuff ) scope: meta.function-call.powershell support.function.powershell + push: in-command commands-reserved: # Builtin cmdlets with reserved verbs - match: \b(?i:(?:ForEach|Where|Sort|Tee)-Object)\b scope: meta.function-call.powershell support.function.powershell + push: in-command script-invocation: - match: \b(?i:[a-z]:)?[\w.\\/-]+\.(?i:exe|com|cmd|bat|ps1)\b - scope: variable.function.powershell + scope: meta.function-call.powershell variable.function.powershell + push: in-command + + command-freeform: + - match: '{{identifier_function}}' + scope: meta.function-call.powershell variable.function.powershell + push: in-command - parameters: + in-command: + # - meta_scope: region.pinkish + - include: line-continuations + - include: pop-eol + - match: (?=[)}]) + pop: 1 + - match: ';' + scope: punctuation.terminator.statement.powershell + pop: 1 + - match: (\|)\s*\n + captures: + 1: keyword.operator.logical.pipe.powershell + push: + - match: ^ + pop: 2 + - match: \| + scope: keyword.operator.logical.pipe.powershell + pop: 1 + - include: redirection + - include: cli-parameters + - include: expressions-without-commands + - match: (?=\S) + push: + - meta_include_prototype: false + - meta_scope: string.unquoted.powershell + - match: (?=[\s#|>;,]|$) + pop: 1 + - match: '[\\/:.]' + scope: punctuation.separator.powershell + - include: escape-sequences + + + cli-parameters: # Flags/Options/Parameters - match: \B(--?|[/+])\p{L}(?:[\w-]*\w)? scope: variable.parameter.option.powershell @@ -429,9 +493,7 @@ contexts: scope: punctuation.section.block.end.powershell pop: 2 - - match: \b(?i:(?:Dynamic)?Param){{kebab_break}} - scope: keyword.declaration.parameter.powershell # This scope is not standard - push: expect-param-context + - include: param-block - match: \b(?i:Begin|Process|End|Clean){{kebab_break}} scope: keyword.context.block.powershell @@ -441,6 +503,11 @@ contexts: - include: workflow-execution-contexts - include: statements + param-block: + - match: \b(?i:(?:Dynamic)?Param){{kebab_break}} + scope: keyword.declaration.parameter.powershell # This scope is not standard + push: expect-param-context + expect-function-context: - meta_scope: meta.block.powershell - match: \{ @@ -650,9 +717,9 @@ contexts: members: - match: (?=\.\.) pop: 1 - - match: \?\.(?={{identifier_simple}}) + - match: \?\.(?=\$?{{identifier_simple}}) scope: punctuation.accessor.null-coalescing.powershell - - match: \??\.(?={{identifier_simple}}) + - match: \??\.(?=\$?{{identifier_simple}}) scope: punctuation.accessor.dot.powershell - match: ::(?={{identifier_simple}}) scope: punctuation.accessor.double-colon.powershell @@ -788,10 +855,7 @@ contexts: scope: keyword.operator.ternary.powershell - match: ; scope: punctuation.terminator.statement.powershell - - match: \`(?=\n|$) - scope: punctuation.separator.continuation.line.powershell - include: comma-separators - # TODO: Distinguish call operator from background operator - match: '&' scope: keyword.operator.background.powershell - match: \.\.(?=\-?\d|\(|\$) @@ -1124,6 +1188,19 @@ contexts: ###[ COMPONENTS ]############################################################## + line-continuations: + - match: (`)\n + captures: + 1: punctuation.separator.continuation.line.powershell + push: line-continuation-body + - match: '`(\s+)\n' + captures: + 1: invalid.illegal.unexpected-whitespace.powershell + + line-continuation-body: + - match: ^ + pop: 1 + comma-separators: - match: ',' scope: punctuation.separator.sequence.powershell @@ -1135,7 +1212,7 @@ contexts: scope: constant.character.escape.powershell pop-eol: - - match: $ + - match: $\n? pop: 1 pop-before-eol: diff --git a/Tests/syntax_test_Class.ps1 b/Tests/syntax_test_Class.ps1 index c1703196..90775389 100644 --- a/Tests/syntax_test_Class.ps1 +++ b/Tests/syntax_test_Class.ps1 @@ -347,6 +347,15 @@ class BookList { $b.Author -eq $Book.Author -and $b.PublishDate -eq $Book.PublishDate }.GetNewClosure() +#^^^^^^^^^^^^^^^^^^^^^^^^ meta.class.powershell meta.function.powershell +#^^^^^^^^ meta.block.powershell +# ^ punctuation.section.braces.end.powershell +# ^ punctuation.accessor.dot.powershell +# ^^^^^^^^^^^^^ meta.function-call.powershell variable.function.powershell +# @@@@@@@@@@@@@ reference +# ^^ meta.function-call.arguments.powershell +# ^ punctuation.section.arguments.begin.powershell +# ^ punctuation.section.arguments.end.powershell if ([BookList]::Books.Find($FindPredicate)) { # @@@@ reference throw "Book '$Book' already in list" @@ -397,6 +406,16 @@ class BookList { param($b) $b.$Property -eq $Value }.GetNewClosure()) +#^^^^^^^^^^^^^^^^^^^^^^^^^ meta.class.powershell meta.function.powershell meta.function-call.arguments.powershell +#^^^^^^^^ meta.block.powershell +# ^ punctuation.section.braces.end.powershell +# ^ punctuation.accessor.dot.powershell +# ^^^^^^^^^^^^^ meta.function-call.powershell variable.function.powershell +# @@@@@@@@@@@@@ reference +# ^^ meta.function-call.arguments.powershell +# ^ punctuation.section.arguments.begin.powershell +# ^ punctuation.section.arguments.end.powershell +# ^ punctuation.section.arguments.end.powershell if ($Index -ge 0) { [BookList]::Books.RemoveAt($Index) # @@@@@@@@ reference diff --git a/Tests/syntax_test_PowerShell.ps1 b/Tests/syntax_test_PowerShell.ps1 index f974c6e2..32283fdd 100644 --- a/Tests/syntax_test_PowerShell.ps1 +++ b/Tests/syntax_test_PowerShell.ps1 @@ -93,6 +93,7 @@ throw "Do not run this file!" & tool.exe /arg1 'value' /arg2 $value --% /arg3 $value /arg4 "value" # Comment # <- keyword.operator.call # ^^^^^^^^ variable.function +# @@@@@@@@ reference # ^ punctuation.definition.parameter # ^^^^^ variable.parameter.option # ^ punctuation.definition.parameter @@ -103,6 +104,7 @@ throw "Do not run this file!" & gnutool.exe -s 'short option' --long-option --very_long_option value +plus-option #<- keyword.operator.call # ^^^^^^^^^^^ variable.function +# @@@@@@@@@@@ reference # ^ variable.parameter.option punctuation.definition.parameter # ^ variable.parameter.option # ^^ variable.parameter.option punctuation.definition.parameter @@ -489,9 +491,11 @@ $a3[1..2] # ^^ meta.number.float.decimal constant.numeric.value - constant constant # ^ punctuation.separator.decimal + # BUG: Don't mark the dot as a function 1. # ^ meta.number.integer.decimal constant.numeric.value # ^ - meta.number - constant.numeric +# @ reference 1.f 1.f() # ^ meta.number.integer.decimal constant.numeric.value @@ -854,11 +858,12 @@ $a3[1..2] # ^ support.function # @@@@@@@@@@@@@@@@ reference Invoke-Something -p1 value ` -#^ support.function +#^^^^^^^^^^^^^^^^ meta.function-call.powershell support.function.powershell #@@@@@@@@@@@@@@@@ reference -# ^ punctuation.definition.parameter -# ^^^ variable.parameter.option -# ^ punctuation.separator.continuation +# ^^^ variable.parameter.option.powershell +# ^ punctuation.definition.parameter.powershell +# ^^^^^ string.unquoted.powershell +# ^ punctuation.separator.continuation.line.powershell -p2 14.4 ` # ^ punctuation.definition.parameter # ^^^ variable.parameter.option @@ -874,9 +879,24 @@ $a3[1..2] # ^ keyword.operator.logical.pipe # ^^^^^^^^^^^^^^^^ support.function + Get-ChildItem | +# ^^^^^^^^^^^^^ meta.function-call.powershell support.function.powershell +# @@@@@@@@@@@@@ reference +# ^ keyword.operator.logical.pipe.powershell + Select Name,Length +# ^^^^^^ meta.function-call.powershell variable.function.powershell +# @@@@@@ reference +# ^^^^ string.unquoted.powershell +# ^ punctuation.separator.sequence.powershell +# ^^^^^^ string.unquoted.powershell + + # Commands (Built-in variables) ls *.ps1 -recurse +# ^^ meta.function-call.powershell variable.function.powershell +# @@ reference # ^ keyword.operator.arithmetic.powershell +# ^^^^ string.unquoted.powershell # ^^^^^^^^ variable.parameter.option.powershell # ^ punctuation.definition.parameter.powershell @@ -893,14 +913,16 @@ $a3[1..2] & tool.exe # ^ keyword.operator.call.powershell -# ^^^^^^^^ variable.function.powershell +# ^^^^^^^^ meta.function-call.powershell variable.function.powershell +# @@@@@@@@ reference something.cmd -# ^^^^^^^^^^^^^ variable.function.powershell +# ^^^^^^^^^^^^^ meta.function-call.powershell variable.function.powershell +# @@@@@@@@@@@@@ reference øyvind.com -# ^^^^^^^^^^ variable.function.powershell - +# ^^^^^^^^^^ meta.function-call.powershell variable.function.powershell +# @@@@@@@@@@ reference # switch switch ("fourteen") {} @@ -1139,11 +1161,20 @@ function Test-Drive([string]$roman) { # ^ punctuation.section.parameters.end.powershell # ^ punctuation.section.block.begin.powershell $roman | c:\users\Me\Documents\Programming\F#\test.exe $roman -# ^ punctuation.definition.variable -# ^ variable.other.readwrite -# ^ keyword.operator.logical.pipe -# ^ punctuation.definition.comment -# ^^^^ comment.line +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.function.powershell +# ^^^^^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^ meta.function-call.powershell variable.function.powershell +# @ reference +# ^ keyword.operator.ternary.powershell +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ string.unquoted.powershell +# ^ punctuation.separator.powershell +# ^ punctuation.separator.powershell +# ^ punctuation.separator.powershell +# ^ punctuation.separator.powershell +# ^ punctuation.separator.powershell +# ^^^^^^^^^^^^^^^^^ comment.line.powershell +# ^ punctuation.definition.comment.powershell } #^^^^ meta.function.powershell # ^ punctuation.section.block.end.powershell @@ -1400,203 +1431,554 @@ catch { } # ^ punctuation.section.braces.begin # ^ punctuation.section.braces.end -# Redirection -notepad.exe > log.txt -#^^^^^^^^^^ variable.function -# ^ keyword.operator.redirection -notepad.exe 1> log.txt -#^^^^^^^^^^ variable.function -# ^ keyword.operator.redirection -notepad.exe *> log.txt -#^^^^^^^^^^ variable.function -# ^ keyword.operator.redirection -notepad.exe 2>&1 -#^^^^^^^^^^ variable.function -# ^^ keyword.operator.redirection -notepad.exe 3>&1 -#^^^^^^^^^^ variable.function -# ^^ keyword.operator.redirection -notepad.exe 4>&1 -#^^^^^^^^^^ variable.function -# ^^ keyword.operator.redirection -notepad.exe 5>&1 -#^^^^^^^^^^ variable.function -# ^^ keyword.operator.redirection -notepad.exe 6>&1 -#^^^^^^^^^^ variable.function -# ^^ keyword.operator.redirection -notepad.exe 2>&1> log.txt -#^^^^^^^^^^ variable.function -# ^^ keyword.operator.redirection -# ^ keyword.operator.redirection - -# Operators -if (10 -cgt 100) { } -# <- keyword.control -# ^ punctuation.section.group.begin -# ^^ meta.number.integer.decimal constant.numeric.value -# ^^^^ keyword.operator.comparison -# ^^^ meta.number.integer.decimal constant.numeric.value -# ^ punctuation.section.group.end -# ^ punctuation.section.braces.begin -# ^ punctuation.section.braces.end -$a -is $b -# ^^^ keyword.operator.logical -$b -contains $c -# ^^^^^^^^^ keyword.operator.logical -$x -notcontains $c -# ^^^^^^^^^^^^ keyword.operator.logical -$c -in $b -# ^^^ keyword.operator.logical -$c -notin $x -# ^^^^^^ keyword.operator.logical -$a -match $b -# ^^^^^^ keyword.operator.logical -$a -notmatch $b -# ^^^^^^^^^ keyword.operator.logical -$x -like $c -# ^^^^^ keyword.operator.logical -100 -and 0 -# ^^^^ keyword.operator.logical -# ^ meta.number.integer.decimal constant.numeric.value -$a -ceq 4 -and $a -ine $d -or -# ^^^^ keyword.operator.comparison -# ^ meta.number.integer.decimal constant.numeric.value -# ^^^^ keyword.operator.logical -# ^ punctuation.definition.variable -# ^^^^ keyword.operator.comparison -# ^^^ keyword.operator.logical -$c -is [Type] -#^ variable.other.readwrite.powershell -# ^^^ keyword.operator.logical.powershell -# ^ punctuation.definition.keyword.powershell -# ^ punctuation.section.brackets.begin.powershell -# ^^^^ support.type.powershell -# ^ punctuation.section.brackets.end.powershell -$c -isnot [Type] -#^ variable.other.readwrite.powershell -# ^^^^^^ keyword.operator.logical.powershell -# ^ punctuation.definition.keyword.powershell -# ^ punctuation.section.brackets.begin.powershell -# ^^^^ support.type.powershell -# ^ punctuation.section.brackets.end.powershell -$c -as [Type] -#^ variable.other.readwrite.powershell -# ^^^ keyword.operator.cast.powershell -# ^ punctuation.definition.keyword.powershell -# ^ punctuation.section.brackets.begin.powershell -# ^^^^ support.type.powershell -# ^ punctuation.section.brackets.end.powershell -$k = $y -bor $k -# ^ keyword.operator.assignment -# ^ keyword.operator.bitwise -$x = $y -band $x -# ^ keyword.operator.assignment -# ^ keyword.operator.bitwise -$z = -bnot $x -# ^ keyword.operator.assignment -# ^ keyword.operator.bitwise -$l = 1 -shl 10 -# ^ keyword.operator.assignment -# ^ meta.number.integer.decimal constant.numeric.value -# ^^ meta.number.integer.decimal constant.numeric.value -# ^^^^ keyword.operator.bitwise -$r = 10 -shr 1 -# ^ keyword.operator.assignment -# ^^ meta.number.integer.decimal constant.numeric.value -# ^ meta.number.integer.decimal constant.numeric.value -# ^^^^ keyword.operator.bitwise -$k = $y -xor $b -# ^ keyword.operator.assignment -# ^ keyword.operator.logical -$k = $y -bxor $b -# ^ keyword.operator.assignment -# ^ keyword.operator.bitwise -$a -icontains $c -# ^^^^^^^^^^ keyword.operator.logical -$a -ccontains $c -# ^^^^^^^^^^ keyword.operator.logical -$a -iNotContains $c -# ^^^^^^^^^^^^^ keyword.operator.logical -$a -cNotContains $c -# ^^^^^^^^^^^^^ keyword.operator.logical -$a -cmatch $c -# ^^^^^^^ keyword.operator.logical -$x -iMatch $c -# ^^^^^^^ keyword.operator.logical -$x -iNotMatch $c -# ^^^^^^^^^^ keyword.operator.logical -$a -iLike $b -# ^^^^^^ keyword.operator.logical -$b -cLike $c -# ^^^^^^ keyword.operator.logical -"hey" -cgt "Hey" -# ^^^^ keyword.operator.comparison -"Hey" -igt "hey" -# ^^^^ keyword.operator.comparison -"hey" -cge "Hey" -# ^^^^ keyword.operator.comparison -"Hey" -ige "hey" -# ^^^^ keyword.operator.comparison -"HEY" -clt "hey" -# ^^^^ keyword.operator.comparison -"HEY" -ilt "hey" -# ^^^^ keyword.operator.comparison -"HEY" -cle "hey" -# ^^^^ keyword.operator.comparison -"HEY" -ile "hey" -# ^^^^ keyword.operator.comparison - -function Test-Function {} -# @@@@@@@@@@@@@ definition -function New-Object {} -# @@@@@@@@@@ definition -# Misc test cases - Test-Function -Class ClassName -# ^^^^^ - storage.type -#@@@@@@@@@@@@@ reference - New-Object -TypeName System.Diagnostics.Process -# ^^^^^^^ - keyword.control -#@@@@@@@@@@ reference - New-Object -TypeName System.Data -# ^^^^ - keyword.control -#@@@@@@@@@@ reference - New-Object -TypeName Sy-stem.if -# ^^ - keyword.control -#@@@@@@@@@@ reference - New-Object -TypeName S_ystem.Clean -# ^^^^^ - keyword.control -#@@@@@@@@@@ reference - New-Object -TypeName Sy_stem-.Throw -# ^^^^^ - keyword.control -#@@@@@@@@@@ reference -echo `"test`" -# ^^^^^^^^^ - string.quoted -# ^^ constant.character.escape -# ^^ constant.character.escape -@("any","array","has").foreach({ $_ }) -# <- keyword.other.array.begin -# ^ meta.group.array-expression -# ^ keyword.control -# ^ meta.block -@('any','array','has').foreach{ $_ } -# <- keyword.other.array.begin -# ^ meta.group.array-expression -# ^ keyword.control -# ^ meta.block -@("any","array","has").where({ $_.Length -gt 3 }) -# <- keyword.other.array.begin -# ^ meta.group.array-expression -# ^ keyword.control -# ^ meta.block -@("any","array","has").where{ $_.Length -gt 3 } -# <- keyword.other.array.begin -# ^ meta.group.array-expression -# ^ keyword.control -# ^ meta.block - -function join-path {} -# @@@@@@@@@ definition + # Redirection + notepad.exe > log.txt +# ^^^^^^^^^^^ meta.function-call.powershell variable.function.powershell +# @@@@@@@@@@@ reference +# ^ keyword.operator.redirection.powershell +# ^^^^^^^ string.unquoted.powershell +# ^ punctuation.separator.powershell + notepad.exe 1> log.txt +# ^^^^^^^^^^^ meta.function-call.powershell variable.function.powershell +# @@@@@@@@@@@ reference +# ^ constant.numeric.decimal.file-descriptor.powershell +# ^ keyword.operator.redirection.powershell +# ^^^^^^^ string.unquoted.powershell +# ^ punctuation.separator.powershell + notepad.exe *> log.txt +# ^^^^^^^^^^^ meta.function-call.powershell variable.function.powershell +# @@@@@@@@@@@ reference +# ^ constant.numeric.decimal.file-descriptor.powershell +# ^ keyword.operator.redirection.powershell +# ^^^^^^^ string.unquoted.powershell +# ^ punctuation.separator.powershell + notepad.exe 2>&1 +# ^^^^^^^^^^^ meta.function-call.powershell variable.function.powershell +# @@@@@@@@@@@ reference +# ^ constant.numeric.decimal.file-descriptor.powershell +# ^^ keyword.operator.redirection.powershell +# ^ constant.numeric.decimal.file-descriptor.powershell + notepad.exe 3>&1 +# ^^^^^^^^^^^ meta.function-call.powershell variable.function.powershell +# @@@@@@@@@@@ reference +# ^ constant.numeric.decimal.file-descriptor.powershell +# ^^ keyword.operator.redirection.powershell +# ^ constant.numeric.decimal.file-descriptor.powershell + notepad.exe 4>&1 +# ^^^^^^^^^^^ meta.function-call.powershell variable.function.powershell +# @@@@@@@@@@@ reference +# ^ constant.numeric.decimal.file-descriptor.powershell +# ^^ keyword.operator.redirection.powershell +# ^ constant.numeric.decimal.file-descriptor.powershell + notepad.exe 5>&1 +# ^^^^^^^^^^^ meta.function-call.powershell variable.function.powershell +# @@@@@@@@@@@ reference +# ^ constant.numeric.decimal.file-descriptor.powershell +# ^^ keyword.operator.redirection.powershell +# ^ constant.numeric.decimal.file-descriptor.powershell + notepad.exe 6>&1 +# ^^^^^^^^^^^ meta.function-call.powershell variable.function.powershell +# @@@@@@@@@@@ reference +# ^ constant.numeric.decimal.file-descriptor.powershell +# ^^ keyword.operator.redirection.powershell +# ^ constant.numeric.decimal.file-descriptor.powershell + notepad.exe 2>&1> log.txt +# ^^^^^^^^^^^ meta.function-call.powershell variable.function.powershell +# @@@@@@@@@@@ reference +# ^ constant.numeric.decimal.file-descriptor.powershell +# ^^ keyword.operator.redirection.powershell +# ^ constant.numeric.decimal.file-descriptor.powershell +# ^ keyword.operator.redirection.powershell +# ^^^^^^^ string.unquoted.powershell +# ^ punctuation.separator.powershell + + # Operators + if (10 -cgt 100) { } +# ^^ keyword.control.conditional.if.powershell +# ^^^^^^^^^^^^^ meta.group.powershell +# ^ punctuation.section.group.begin.powershell +# ^^ meta.number.integer.decimal.powershell constant.numeric.value.powershell +# ^^^^ keyword.operator.comparison.powershell +# ^ punctuation.definition.keyword.powershell +# ^^^ meta.number.integer.decimal.powershell constant.numeric.value.powershell +# ^ punctuation.section.group.end.powershell +# ^^^ meta.block.powershell +# ^ punctuation.section.braces.begin.powershell +# ^ punctuation.section.braces.end.powershell + $a -is $b +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^^^ keyword.operator.logical.powershell +# ^ punctuation.definition.keyword.powershell +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell + $b -contains $c +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^^^^^^^^^ keyword.operator.logical.powershell +# ^ punctuation.definition.keyword.powershell +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell + $x -notcontains $c +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^^^^^^^^^^^^ keyword.operator.logical.powershell +# ^ punctuation.definition.keyword.powershell +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell + $c -in $b +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^^^ keyword.operator.logical.powershell +# ^ punctuation.definition.keyword.powershell +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell + $c -notin $x +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^^^^^^ keyword.operator.logical.powershell +# ^ punctuation.definition.keyword.powershell +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell + $a -match $b +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^^^^^^ keyword.operator.logical.powershell +# ^ punctuation.definition.keyword.powershell +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell + $a -notmatch $b +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^^^^^^^^^ keyword.operator.logical.powershell +# ^ punctuation.definition.keyword.powershell +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell + $x -like $c +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^^^^^ keyword.operator.logical.powershell +# ^ punctuation.definition.keyword.powershell +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell + 100 -and 0 +# ^^^ meta.number.integer.decimal.powershell constant.numeric.value.powershell +# ^^^^ keyword.operator.logical.powershell +# ^ punctuation.definition.keyword.powershell +# ^ meta.number.integer.decimal.powershell constant.numeric.value.powershell + $a -ceq 4 -and $a -ine $d -or +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^^^^ keyword.operator.comparison.powershell +# ^ punctuation.definition.keyword.powershell +# ^ meta.number.integer.decimal.powershell constant.numeric.value.powershell +# ^^^^ keyword.operator.logical.powershell +# ^ punctuation.definition.keyword.powershell +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^^^^ keyword.operator.comparison.powershell +# ^ punctuation.definition.keyword.powershell +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^^^ keyword.operator.logical.powershell +# ^ punctuation.definition.keyword.powershell + $c -is [Type] +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^^^ keyword.operator.logical.powershell +# ^ punctuation.definition.keyword.powershell +# ^ punctuation.section.brackets.begin.powershell +# ^^^^ support.type.powershell +# ^ punctuation.section.brackets.end.powershell + $c -isnot [Type] +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^^^^^^ keyword.operator.logical.powershell +# ^ punctuation.definition.keyword.powershell +# ^ punctuation.section.brackets.begin.powershell +# ^^^^ support.type.powershell +# ^ punctuation.section.brackets.end.powershell + $c -as [Type] +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^^^ keyword.operator.cast.powershell +# ^ punctuation.definition.keyword.powershell +# ^ punctuation.section.brackets.begin.powershell +# ^^^^ support.type.powershell +# ^ punctuation.section.brackets.end.powershell + $k = $y -bor $k +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^ keyword.operator.assignment.powershell +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^^^^ keyword.operator.bitwise.powershell +# ^ punctuation.definition.keyword.powershell +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell + $x = $y -band $x +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^ keyword.operator.assignment.powershell +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^^^^^ keyword.operator.bitwise.powershell +# ^ punctuation.definition.keyword.powershell +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell + $z = -bnot $x +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^ keyword.operator.assignment.powershell +# ^^^^^ keyword.operator.bitwise.powershell +# ^ punctuation.definition.keyword.powershell +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell + $l = 1 -shl 10 +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^ keyword.operator.assignment.powershell +# ^ meta.number.integer.decimal.powershell constant.numeric.value.powershell +# ^^^^ keyword.operator.bitwise.powershell +# ^ punctuation.definition.keyword.powershell +# ^^ meta.number.integer.decimal.powershell constant.numeric.value.powershell + $r = 10 -shr 1 +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^ keyword.operator.assignment.powershell +# ^^ meta.number.integer.decimal.powershell constant.numeric.value.powershell +# ^^^^ keyword.operator.bitwise.powershell +# ^ punctuation.definition.keyword.powershell +# ^ meta.number.integer.decimal.powershell constant.numeric.value.powershell + $k = $y -xor $b +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^ keyword.operator.assignment.powershell +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^^^^ keyword.operator.logical.powershell +# ^ punctuation.definition.keyword.powershell +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell + $k = $y -bxor $b +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^ keyword.operator.assignment.powershell +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^^^^^ keyword.operator.bitwise.powershell +# ^ punctuation.definition.keyword.powershell +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell + $a -icontains $c +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^^^^^^^^^^ keyword.operator.logical.powershell +# ^ punctuation.definition.keyword.powershell +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell + $a -ccontains $c +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^^^^^^^^^^ keyword.operator.logical.powershell +# ^ punctuation.definition.keyword.powershell +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell + $a -iNotContains $c +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^^^^^^^^^^^^^ keyword.operator.logical.powershell +# ^ punctuation.definition.keyword.powershell +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell + $a -cNotContains $c +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^^^^^^^^^^^^^ keyword.operator.logical.powershell +# ^ punctuation.definition.keyword.powershell +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell + $a -cmatch $c +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^^^^^^^ keyword.operator.logical.powershell +# ^ punctuation.definition.keyword.powershell +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell + $x -iMatch $c +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^^^^^^^ keyword.operator.logical.powershell +# ^ punctuation.definition.keyword.powershell +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell + $x -iNotMatch $c +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^^^^^^^^^^ keyword.operator.logical.powershell +# ^ punctuation.definition.keyword.powershell +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell + $a -iLike $b +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^^^^^^ keyword.operator.logical.powershell +# ^ punctuation.definition.keyword.powershell +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell + $b -cLike $c +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^^^^^^ keyword.operator.logical.powershell +# ^ punctuation.definition.keyword.powershell +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell + "hey" -cgt "Hey" +# ^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^^^^ keyword.operator.comparison.powershell +# ^ punctuation.definition.keyword.powershell +# ^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell + "Hey" -igt "hey" +# ^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^^^^ keyword.operator.comparison.powershell +# ^ punctuation.definition.keyword.powershell +# ^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell + "hey" -cge "Hey" +# ^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^^^^ keyword.operator.comparison.powershell +# ^ punctuation.definition.keyword.powershell +# ^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell + "Hey" -ige "hey" +# ^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^^^^ keyword.operator.comparison.powershell +# ^ punctuation.definition.keyword.powershell +# ^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell + "HEY" -clt "hey" +# ^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^^^^ keyword.operator.comparison.powershell +# ^ punctuation.definition.keyword.powershell +# ^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell + "HEY" -ilt "hey" +# ^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^^^^ keyword.operator.comparison.powershell +# ^ punctuation.definition.keyword.powershell +# ^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell + "HEY" -cle "hey" +# ^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^^^^ keyword.operator.comparison.powershell +# ^ punctuation.definition.keyword.powershell +# ^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell + "HEY" -ile "hey" +# ^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^^^^ keyword.operator.comparison.powershell +# ^ punctuation.definition.keyword.powershell +# ^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell + + function Test-Function {} +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.function.powershell +# ^^^^^^^^ keyword.declaration.function.powershell +# ^^^^^^^^^^^^^ entity.name.function.powershell +# ^ punctuation.section.block.begin.powershell +# ^ punctuation.section.block.end.powershell +# @@@@@@@@@@@@@ definition + function New-Object {} +#^^^^^^^^^^^^^^^^^^^^^^^^^ meta.function.powershell +# ^^^^^^^^ keyword.declaration.function.powershell +# ^^^^^^^^^^ entity.name.function.powershell +# ^ punctuation.section.block.begin.powershell +# ^ punctuation.section.block.end.powershell +# @@@@@@@@@@ definition + Test-Function -Class ClassName +# ^^^^^^^^^^^^^ meta.function-call.powershell support.function.powershell +# ^^^^^^ variable.parameter.option.powershell - storage - keyword +# ^ punctuation.definition.parameter.powershell +# ^^^^^^^^^ string.unquoted.powershell +# @@@@@@@@@@@@@ reference + New-Object -TypeName System.Diagnostics.Process +# ^^^^^^^^^^ meta.function-call.powershell support.function.powershell +# @@@@@@@@@@ reference +# ^^^^^^^^^ variable.parameter.option.powershell +# ^ punctuation.definition.parameter.powershell +# ^^^^^^^^^^^^^^^^^^^^^^^^^^ string.unquoted.powershell - keyword +# ^ punctuation.separator.powershell +# ^ punctuation.separator.powershell + New-Object -TypeName System.Data +# ^^^^^^^^^^ meta.function-call.powershell support.function.powershell +# @@@@@@@@@@ reference +# ^^^^^^^^^ variable.parameter.option.powershell +# ^ punctuation.definition.parameter.powershell +# ^^^^^^^^^^^ string.unquoted.powershell - keyword + New-Object -TypeName Sy-stem.if +# ^^^^^^^^^^ meta.function-call.powershell support.function.powershell +# @@@@@@@@@@ reference +# ^^^^^^^^^ variable.parameter.option.powershell +# ^ punctuation.definition.parameter.powershell +# ^^^^^^^^^^ string.unquoted.powershell - keyword +# ^ punctuation.separator.powershell + New-Object -TypeName S_ystem.Clean +# ^^^^^^^^^^ meta.function-call.powershell support.function.powershell +# @@@@@@@@@@ reference +# ^^^^^^^^^ variable.parameter.option.powershell +# ^ punctuation.definition.parameter.powershell +# ^^^^^^^^^^^^^ string.unquoted.powershell - keyword +# ^ punctuation.separator.powershell + New-Object -TypeName Sy_stem-.Throw +# ^^^^^^^^^^ meta.function-call.powershell support.function.powershell +# @@@@@@@@@@ reference +# ^^^^^^^^^ variable.parameter.option.powershell +# ^ punctuation.definition.parameter.powershell +# ^^^^^^^^^^^^^^ string.unquoted.powershell - keyword + + echo `"test`" +# ^^^^ meta.function-call.powershell variable.function.powershell +# @@@@ reference +# ^^ constant.character.escape.powershell +# ^^^^^^ string.unquoted.powershell - string.quoted +# ^^ constant.character.escape.powershell + + @("any","array","has").foreach({ $_ }) +# ^^^^^^^^^^^^^^^^^^^^^^ meta.group.array-expression.powershell +# ^ keyword.other.array.begin.powershell +# ^ punctuation.section.group.begin.powershell +# ^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^ punctuation.separator.sequence.powershell +# ^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^ punctuation.separator.sequence.powershell +# ^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^ punctuation.section.group.end.powershell +# ^ punctuation.accessor.dot.powershell +# ^^^^^^^ meta.function-call.powershell variable.function.powershell +# @@@@@@@ reference +# ^^^^^^^^ meta.function-call.arguments.powershell +# ^ punctuation.section.arguments.begin.powershell +# ^^^^^^ meta.block.powershell +# ^ punctuation.section.braces.begin.powershell +# ^^ variable.language.powershell +# ^ punctuation.definition.variable.powershell +# ^ punctuation.section.braces.end.powershell +# ^ punctuation.section.arguments.end.powershell + @('any','array','has').foreach{ $_ } +# ^^^^^^^^^^^^^^^^^^^^^^ meta.group.array-expression.powershell +# ^ keyword.other.array.begin.powershell +# ^ punctuation.section.group.begin.powershell +# ^^^^^ meta.string.powershell string.quoted.single.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^ punctuation.separator.sequence.powershell +# ^^^^^^^ meta.string.powershell string.quoted.single.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^ punctuation.separator.sequence.powershell +# ^^^^^ meta.string.powershell string.quoted.single.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^ punctuation.section.group.end.powershell +# ^ punctuation.accessor.dot.powershell +# ^^^^^^ meta.block.powershell +# ^ punctuation.section.braces.begin.powershell +# ^^ variable.language.powershell +# ^ punctuation.definition.variable.powershell +# ^ punctuation.section.braces.end.powershell + @("any","array","has").where({ $_.Length -gt 3 }) +# ^^^^^^^^^^^^^^^^^^^^^^ meta.group.array-expression.powershell +# ^ keyword.other.array.begin.powershell +# ^ punctuation.section.group.begin.powershell +# ^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^ punctuation.separator.sequence.powershell +# ^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^ punctuation.separator.sequence.powershell +# ^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^ punctuation.section.group.end.powershell +# ^ punctuation.accessor.dot.powershell +# ^^^^^ meta.function-call.powershell variable.function.powershell +# @@@@@ reference +# ^^^^^^^^^^^^^^^^^^^^^ meta.function-call.arguments.powershell +# ^ punctuation.section.arguments.begin.powershell +# ^^^^^^^^^^^^^^^^^^^ meta.block.powershell +# ^ punctuation.section.braces.begin.powershell +# ^^ variable.language.powershell +# ^ punctuation.definition.variable.powershell +# ^ punctuation.accessor.dot.powershell +# ^^^^^^ variable.other.member.powershell +# ^^^ keyword.operator.comparison.powershell +# ^ punctuation.definition.keyword.powershell +# ^ meta.number.integer.decimal.powershell constant.numeric.value.powershell +# ^ punctuation.section.braces.end.powershell +# ^ punctuation.section.arguments.end.powershell + @("any","array","has").where{ $_.Length -gt 3 } +# ^^^^^^^^^^^^^^^^^^^^^^ meta.group.array-expression.powershell +# ^ keyword.other.array.begin.powershell +# ^ punctuation.section.group.begin.powershell +# ^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^ punctuation.separator.sequence.powershell +# ^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^ punctuation.separator.sequence.powershell +# ^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^ punctuation.section.group.end.powershell +# ^ punctuation.accessor.dot.powershell +# ^^^^^^^^^^^^^^^^^^^ meta.block.powershell +# ^ punctuation.section.braces.begin.powershell +# ^^ variable.language.powershell +# ^ punctuation.definition.variable.powershell +# ^ punctuation.accessor.dot.powershell +# ^^^^^^ variable.other.member.powershell +# ^^^ keyword.operator.comparison.powershell +# ^ punctuation.definition.keyword.powershell +# ^ meta.number.integer.decimal.powershell constant.numeric.value.powershell +# ^ punctuation.section.braces.end.powershell + + function join-path {} +# @@@@@@@@@ definition $file = join-path $env:SystemDrive "$([System.io.path]::GetRandomFileName()).ps1" #^^^^ variable.other.readwrite.powershell diff --git a/Tests/syntax_test_Workflow.ps1 b/Tests/syntax_test_Workflow.ps1 index dbe3d2ce..94d4e66d 100644 --- a/Tests/syntax_test_Workflow.ps1 +++ b/Tests/syntax_test_Workflow.ps1 @@ -129,8 +129,8 @@ # ^ meta.function.powershell meta.block.powershell meta.block.powershell punctuation.section.block.begin.powershell $Hotfix = Get-Content 'D:\HotFixes\Required.txt' # @@@@@@@@@@@ reference - foreach ($h in $Hotfix) {'D:\Scripts\Verify-Hotfix' -Hotfix $h} -#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.function.powershell meta.block.powershell meta.block.powershell + foreach ($h in $Hotfix) {D:\Scripts\Verify-Hotfix.ps1 -Hotfix $h} +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.function.powershell meta.block.powershell meta.block.powershell # ^^^^^^^ keyword.control.loop.for.powershell # ^^^^^^^^^^^^^^^ meta.group.powershell # ^ punctuation.section.group.begin.powershell @@ -140,16 +140,15 @@ # ^^^^^^^ variable.other.readwrite.powershell # ^ punctuation.definition.variable.powershell # ^ punctuation.section.group.end.powershell -# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.block.powershell +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.block.powershell # ^ punctuation.section.braces.begin.powershell -# ^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string.powershell string.quoted.single.powershell -# ^ punctuation.definition.string.begin.powershell -# ^ punctuation.definition.string.end.powershell -# ^^^^^^^ variable.parameter.option.powershell -# ^ punctuation.definition.parameter.powershell -# ^^ variable.other.readwrite.powershell -# ^ punctuation.definition.variable.powershell -# ^ punctuation.section.braces.end.powershell +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.function-call.powershell variable.function.powershell +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@ reference +# ^^^^^^^ variable.parameter.option.powershell +# ^ punctuation.definition.parameter.powershell +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^ punctuation.section.braces.end.powershell } } } From 72e580c373b07a66fd1ea47c73c6556d8fac1c92 Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Mon, 8 Dec 2025 18:36:54 -0500 Subject: [PATCH 71/81] Extract command ending sequences to a context --- PowerShell.sublime-syntax | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index bfe81a2f..c4e4245a 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -317,6 +317,21 @@ contexts: in-command: # - meta_scope: region.pinkish + - include: command-ending-sequences + - include: redirection + - include: cli-parameters + - include: expressions-without-commands + - match: (?=\S) + push: + - meta_include_prototype: false + - meta_scope: string.unquoted.powershell + - match: (?=[\s#|>;,]|$) + pop: 1 + - match: '[\\/:.]' + scope: punctuation.separator.powershell + - include: escape-sequences + + command-ending-sequences: - include: line-continuations - include: pop-eol - match: (?=[)}]) @@ -333,19 +348,6 @@ contexts: - match: \| scope: keyword.operator.logical.pipe.powershell pop: 1 - - include: redirection - - include: cli-parameters - - include: expressions-without-commands - - match: (?=\S) - push: - - meta_include_prototype: false - - meta_scope: string.unquoted.powershell - - match: (?=[\s#|>;,]|$) - pop: 1 - - match: '[\\/:.]' - scope: punctuation.separator.powershell - - include: escape-sequences - cli-parameters: # Flags/Options/Parameters From a1804900c1963ea5d9b3de163374a7f64f741df4 Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Mon, 8 Dec 2025 16:55:43 -0500 Subject: [PATCH 72/81] Change command identifier for kicks --- PowerShell.sublime-syntax | 2 +- Tests/syntax_test_PowerShell.ps1 | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index c4e4245a..cc98a79c 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -311,7 +311,7 @@ contexts: push: in-command command-freeform: - - match: '{{identifier_function}}' + - match: '{{identifier_simple}}' scope: meta.function-call.powershell variable.function.powershell push: in-command diff --git a/Tests/syntax_test_PowerShell.ps1 b/Tests/syntax_test_PowerShell.ps1 index 32283fdd..e906f63b 100644 --- a/Tests/syntax_test_PowerShell.ps1 +++ b/Tests/syntax_test_PowerShell.ps1 @@ -495,7 +495,6 @@ $a3[1..2] 1. # ^ meta.number.integer.decimal constant.numeric.value # ^ - meta.number - constant.numeric -# @ reference 1.f 1.f() # ^ meta.number.integer.decimal constant.numeric.value From eadc61e49597d06ab3f1d1cc4d9d3b1e2e4e6352 Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Mon, 8 Dec 2025 17:04:24 -0500 Subject: [PATCH 73/81] Mark scripts as functions after & or . Even if they are quoted. --- PowerShell.sublime-syntax | 22 ++++++++++++++++++++++ Tests/syntax_test_PowerShell.ps1 | 7 +++++++ 2 files changed, 29 insertions(+) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index cc98a79c..cfef6a4f 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -58,8 +58,14 @@ contexts: - match: \B\.(?= ) scope: keyword.operator.source.powershell + push: + - include: commands-quoted + - include: else-pop - match: \& scope: keyword.operator.call.powershell + push: + - include: commands-quoted + - include: else-pop - include: expressions @@ -310,6 +316,22 @@ contexts: scope: meta.function-call.powershell variable.function.powershell push: in-command + commands-quoted: + - match: (?={{single_quote}}) + push: [in-command, expect-single-quoted-command] + - match: (?={{double_quote}}) + push: [in-command, expect-double-quoted-command] + + expect-single-quoted-command: + - meta_scope: meta.function-call.powershell variable.function.powershell + - include: single-quoted-strings + - include: immediately-pop + + expect-double-quoted-command: + - meta_scope: meta.function-call.powershell variable.function.powershell + - include: double-quoted-strings + - include: immediately-pop + command-freeform: - match: '{{identifier_simple}}' scope: meta.function-call.powershell variable.function.powershell diff --git a/Tests/syntax_test_PowerShell.ps1 b/Tests/syntax_test_PowerShell.ps1 index e906f63b..a074974f 100644 --- a/Tests/syntax_test_PowerShell.ps1 +++ b/Tests/syntax_test_PowerShell.ps1 @@ -923,6 +923,13 @@ $a3[1..2] # ^^^^^^^^^^ meta.function-call.powershell variable.function.powershell # @@@@@@@@@@ reference + & ".\script name with spaces.ps1" +# ^ keyword.operator.call.powershell +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.function-call.powershell variable.function.powershell meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ reference + # switch switch ("fourteen") {} # <- keyword.control From a4b0a2e992ca944b2427136206cdc18da0e181d2 Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Mon, 8 Dec 2025 17:19:34 -0500 Subject: [PATCH 74/81] Stack function scopes over strings --- PowerShell.sublime-syntax | 48 ++++++++++++++++++++++++-------- Tests/syntax_test_PowerShell.ps1 | 15 ++++++++-- 2 files changed, 50 insertions(+), 13 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index cfef6a4f..6bc5efee 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -318,27 +318,50 @@ contexts: commands-quoted: - match: (?={{single_quote}}) - push: [in-command, expect-single-quoted-command] + push: [in-command, single-quoted-command-string] - match: (?={{double_quote}}) - push: [in-command, expect-double-quoted-command] + push: [in-command, double-quoted-command-string] - expect-single-quoted-command: - - meta_scope: meta.function-call.powershell variable.function.powershell - - include: single-quoted-strings + single-quoted-command-string: + - match: '{{single_quote}}' + scope: punctuation.definition.string.begin.powershell + push: inside-single-quoted-command-string - include: immediately-pop - expect-double-quoted-command: - - meta_scope: meta.function-call.powershell variable.function.powershell - - include: double-quoted-strings + inside-single-quoted-command-string: + - meta_include_prototype: false + - meta_scope: meta.string.powershell string.quoted.single.powershell meta.function-call.powershell variable.function.powershell + - match: '{{single_quote}}{2}' + scope: constant.character.escape.powershell + - match: '{{single_quote}}' + scope: punctuation.definition.string.end.powershell + pop: 1 + - include: path-punctuation + + double-quoted-command-string: + - match: '{{double_quote}}' + scope: punctuation.definition.string.begin.powershell + push: inside-double-quoted-command-string - include: immediately-pop + inside-double-quoted-command-string: + - meta_include_prototype: false + - meta_scope: meta.string.interpolated.powershell string.quoted.double.powershell meta.function-call.powershell variable.function.powershell + - match: '{{double_quote}}{2}' + scope: constant.character.escape.powershell + - include: escape-sequences + - match: '{{double_quote}}' + scope: punctuation.definition.string.end.powershell + pop: 1 + - include: string-interpolations + - include: path-punctuation + command-freeform: - match: '{{identifier_simple}}' scope: meta.function-call.powershell variable.function.powershell push: in-command in-command: - # - meta_scope: region.pinkish - include: command-ending-sequences - include: redirection - include: cli-parameters @@ -349,8 +372,7 @@ contexts: - meta_scope: string.unquoted.powershell - match: (?=[\s#|>;,]|$) pop: 1 - - match: '[\\/:.]' - scope: punctuation.separator.powershell + - include: path-punctuation - include: escape-sequences command-ending-sequences: @@ -1212,6 +1234,10 @@ contexts: ###[ COMPONENTS ]############################################################## + path-punctuation: + - match: '[:/\\.]+' + scope: punctuation.separator.powershell + line-continuations: - match: (`)\n captures: diff --git a/Tests/syntax_test_PowerShell.ps1 b/Tests/syntax_test_PowerShell.ps1 index a074974f..7dc2a098 100644 --- a/Tests/syntax_test_PowerShell.ps1 +++ b/Tests/syntax_test_PowerShell.ps1 @@ -923,12 +923,23 @@ $a3[1..2] # ^^^^^^^^^^ meta.function-call.powershell variable.function.powershell # @@@@@@@@@@ reference - & ".\script name with spaces.ps1" + & '.\script name with spaces.ps1' # ^ keyword.operator.call.powershell -# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.function-call.powershell variable.function.powershell meta.string.interpolated.powershell string.quoted.double.powershell +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string.powershell string.quoted.single.powershell meta.function-call.powershell variable.function.powershell +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ reference # ^ punctuation.definition.string.begin.powershell +# ^^ punctuation.separator.powershell +# ^ punctuation.separator.powershell # ^ punctuation.definition.string.end.powershell + + & ".\script name with spaces.ps1" +# ^ keyword.operator.call.powershell +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell meta.function-call.powershell variable.function.powershell # @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ reference +# ^ punctuation.definition.string.begin.powershell +# ^^ punctuation.separator.powershell +# ^ punctuation.separator.powershell +# ^ punctuation.definition.string.end.powershell # switch switch ("fourteen") {} From 6c3e17b5f198860dc2466cb09211491f2af5daba Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Mon, 8 Dec 2025 18:44:47 -0500 Subject: [PATCH 75/81] Test for background operator --- Tests/syntax_test_PowerShell.ps1 | 84 ++++++++++++++++++++++---------- 1 file changed, 57 insertions(+), 27 deletions(-) diff --git a/Tests/syntax_test_PowerShell.ps1 b/Tests/syntax_test_PowerShell.ps1 index 7dc2a098..177344b1 100644 --- a/Tests/syntax_test_PowerShell.ps1 +++ b/Tests/syntax_test_PowerShell.ps1 @@ -85,33 +85,63 @@ using namespace System.Management.Automation # ^^^^^^^ entity.name.label.powershell # ^ punctuation.definition.label.powershell -throw "Do not run this file!" -# <- keyword.control.exception -# ^^^^^^^^^^^^^^^^^^^^^^^ string.quoted.double - -# Stop parsing -& tool.exe /arg1 'value' /arg2 $value --% /arg3 $value /arg4 "value" # Comment -# <- keyword.operator.call -# ^^^^^^^^ variable.function -# @@@@@@@@ reference -# ^ punctuation.definition.parameter -# ^^^^^ variable.parameter.option -# ^ punctuation.definition.parameter -# ^^^^^ variable.parameter.option -# ^^^ keyword.control -# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ string.unquoted - constant - variable - comment - -& gnutool.exe -s 'short option' --long-option --very_long_option value +plus-option -#<- keyword.operator.call -# ^^^^^^^^^^^ variable.function -# @@@@@@@@@@@ reference -# ^ variable.parameter.option punctuation.definition.parameter -# ^ variable.parameter.option -# ^^ variable.parameter.option punctuation.definition.parameter -# ^^ variable.parameter.option punctuation.definition.parameter -# ^^^^^^^^^^^^^^^^ variable.parameter.option -# ^ variable.parameter.option punctuation.definition.parameter -# ^^^^^^^^^^^ variable.parameter.option + throw "Do not run this file!" +# ^^^^^ keyword.control.exception.raise.powershell +# ^^^^^^^^^^^^^^^^^^^^^^^ meta.string.interpolated.powershell string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell + + # Stop parsing + & tool.exe /arg1 'value' /arg2 $value --% /arg3 $value /arg4 "value" # Comment +# ^ keyword.operator.call.powershell +# ^^^^^^^^ meta.function-call.powershell variable.function.powershell +# @@@@@@@@ reference +# ^^^^^ variable.parameter.option.powershell +# ^ punctuation.definition.parameter.powershell +# ^^^^^^^ meta.string.powershell string.quoted.single.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^^^^^ variable.parameter.option.powershell +# ^ punctuation.definition.parameter.powershell +# ^^^^^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^^^ keyword.control.powershell +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ string.unquoted.powershell + + & gnutool.exe -s 'short option' --long-option --very_long_option value +plus-option +# ^ keyword.operator.call.powershell +# ^^^^^^^^^^^ meta.function-call.powershell variable.function.powershell +# @@@@@@@@@@@ reference +# ^^ variable.parameter.option.powershell +# ^ punctuation.definition.parameter.powershell +# ^^^^^^^^^^^^^^ meta.string.powershell string.quoted.single.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^^^^^^^^^^^^^ variable.parameter.option.powershell +# ^^ punctuation.definition.parameter.powershell +# ^^^^^^^^^^^^^^^^^^ variable.parameter.option.powershell +# ^^ punctuation.definition.parameter.powershell +# ^^^^^ string.unquoted.powershell +# ^^^^^^^^^^^^ variable.parameter.option.powershell +# ^ punctuation.definition.parameter.powershell + + $job = Get-Process -Name pwsh & +# ^^^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^ keyword.operator.assignment.powershell +# ^^^^^^^^^^^ meta.function-call.powershell support.function.powershell +# @@@@@@@@@@@ reference +# ^^^^^ variable.parameter.option.powershell +# ^ punctuation.definition.parameter.powershell +# ^^^^ string.unquoted.powershell +# ^ keyword.operator.background.powershell + Receive-Job $job -Wait +# ^^^^^^^^^^^ meta.function-call.powershell support.function.powershell +# @@@@@@@@@@@ reference +# ^^^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^^^^^ variable.parameter.option.powershell +# ^ punctuation.definition.parameter.powershell # Constants $true From 9fe8439f6f561167a4fff484d412f8eaa090999a Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Mon, 8 Dec 2025 18:46:20 -0500 Subject: [PATCH 76/81] Test string subexpression property access --- Tests/syntax_test_strings.ps1 | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Tests/syntax_test_strings.ps1 b/Tests/syntax_test_strings.ps1 index 0e1c7195..9d68c1a5 100644 --- a/Tests/syntax_test_strings.ps1 +++ b/Tests/syntax_test_strings.ps1 @@ -122,6 +122,22 @@ # ^^ string.quoted.double.powershell - meta.interpolation # ^ punctuation.definition.string.end.powershell + # When used in a subexpression, still don't extend past its closing + "This is my $($variable.Name).Name!" +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string.interpolated.powershell +# ^^^^^^^^^^^^ string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^^^^^^^^^^^^^^^^^ meta.interpolation.powershell +# ^^ punctuation.section.interpolation.begin.powershell +# ^^^^^^^^^^^^^^ source.powershell.embedded +# ^^^^^^^^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^ punctuation.accessor.dot.powershell +# ^^^^ variable.other.member.powershell +# ^ punctuation.section.interpolation.end.powershell +# ^^^^^^^ string.quoted.double.powershell +# ^ punctuation.definition.string.end.powershell + # $ENV:ComputerName should be highlighted "This is the name of my computer: $ENV:ComputerName" # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string.interpolated.powershell From f3090e79d2e8e2c961b557a2ee90188e1bcfe4e9 Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Mon, 8 Dec 2025 20:34:27 -0500 Subject: [PATCH 77/81] Allow default value in function params And refactor assignment a little --- PowerShell.sublime-syntax | 21 ++++++++--- Tests/syntax_test_Pester.ps1 | 61 ++++++++++++++++++++++++++++++++ Tests/syntax_test_PowerShell.ps1 | 2 +- Tests/syntax_test_Workflow.ps1 | 33 +++++++++++++++++ 4 files changed, 112 insertions(+), 5 deletions(-) create mode 100644 Tests/syntax_test_Pester.ps1 diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index 6bc5efee..6df19da9 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -526,6 +526,7 @@ contexts: scope: variable.parameter.powershell captures: 1: punctuation.definition.variable.begin.powershell + - include: assignment-normal function-body: - meta_scope: meta.function.powershell @@ -583,8 +584,7 @@ contexts: - include: types-without-members - include: variables-without-members - include: literals - - match: '=' - scope: keyword.operator.assignment.powershell + - include: assignment-normal attributes: - match: (\[)\s*({{attributes}}) @@ -876,8 +876,10 @@ contexts: # Symbol operators - match: \! scope: keyword.operator.logical.powershell - - match: '[+/*%-]?=' - scope: keyword.operator.assignment.powershell + - include: assignment-normal + - match: (?:[+/*%-]|\?\?)= + scope: keyword.operator.assignment.augmented.powershell + push: in-assignment - match: (?:\+\+|--)(?![ \t]*\d|[[:alpha:]]) scope: keyword.operator.assignment.powershell - match: '[+-](?=\.?\d)' # This is sort of heuristic @@ -908,6 +910,17 @@ contexts: # This is very imprecise. Is there a syntax for 'must come after...'? scope: keyword.operator.range.powershell + assignment-normal: + - match: = + scope: keyword.operator.assignment.powershell + push: in-assignment + + in-assignment: + - include: command-ending-sequences + # INFO: Someday maybe we can nix the workflow stuff + - include: workflow-execution-contexts + - include: expressions + redirection: # https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_redirection - match: ([2-6*])(>&)(1) diff --git a/Tests/syntax_test_Pester.ps1 b/Tests/syntax_test_Pester.ps1 new file mode 100644 index 00000000..6dfbb125 --- /dev/null +++ b/Tests/syntax_test_Pester.ps1 @@ -0,0 +1,61 @@ +# SYNTAX TEST "Packages/PowerShell/PowerShell.sublime-syntax" + +BeforeAll { + # your function + function Get-Planet ([string]$Name='*') +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.block.powershell meta.function.powershell +# ^^^^^^^^ keyword.declaration.function.powershell +# ^^^^^^^^^^ entity.name.function.powershell +# ^ punctuation.section.parameters.begin.powershell +# ^ punctuation.section.brackets.begin.powershell +# ^^^^^^ storage.type.powershell +# ^ punctuation.section.brackets.end.powershell +# ^^^^^ variable.parameter.powershell +# ^ punctuation.definition.variable.begin.powershell +# ^ keyword.operator.assignment.powershell +# ^^^ meta.string.powershell string.quoted.single.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^ punctuation.section.parameters.end.powershell + { + $planets = @( + @{ Name = 'Mercury' } + @{ Name = 'Venus' } + @{ Name = 'Earth' } + @{ Name = 'Mars' } + @{ Name = 'Jupiter' } + @{ Name = 'Saturn' } + @{ Name = 'Uranus' } + @{ Name = 'Neptune' } + ) | foreach { [PSCustomObject]$_ } + + $planets | where { $_.Name -like $Name } + } +} + +# Pester tests +Describe 'Get-Planet' { + It "Given no parameters, it lists all 8 planets" { + $allPlanets = Get-Planet + $allPlanets.Count | Should -Be 8 + } + + Context "Filtering by Name" { + It "Given valid -Name '', it returns ''" -TestCases @( + @{ Filter = 'Earth'; Expected = 'Earth' } + @{ Filter = 'ne*' ; Expected = 'Neptune' } + @{ Filter = 'ur*' ; Expected = 'Uranus' } + @{ Filter = 'm*' ; Expected = 'Mercury', 'Mars' } + ) { + param ($Filter, $Expected) + + $planets = Get-Planet -Name $Filter + $planets.Name | Should -Be $Expected + } + + It "Given invalid parameter -Name 'Alpha Centauri', it returns `$null" { + $planets = Get-Planet -Name 'Alpha Centauri' + $planets | Should -Be $null + } + } +} diff --git a/Tests/syntax_test_PowerShell.ps1 b/Tests/syntax_test_PowerShell.ps1 index 177344b1..e47887ca 100644 --- a/Tests/syntax_test_PowerShell.ps1 +++ b/Tests/syntax_test_PowerShell.ps1 @@ -1423,7 +1423,7 @@ class Vehicle { # ^ punctuation.definition.variable.powershell # ^ punctuation.accessor.dot.powershell # ^^^^^^^ variable.other.member.powershell -# ^^ keyword.operator.assignment.powershell +# ^^ keyword.operator.assignment.augmented.powershell # ^^^^^^^^^^^^^^ variable.other.readwrite.powershell # ^ punctuation.definition.variable.powershell diff --git a/Tests/syntax_test_Workflow.ps1 b/Tests/syntax_test_Workflow.ps1 index 94d4e66d..be0bbb72 100644 --- a/Tests/syntax_test_Workflow.ps1 +++ b/Tests/syntax_test_Workflow.ps1 @@ -66,6 +66,19 @@ ## $Using imports the variable and its current value. inlinescript {"Inline A1 = $Using:a"} +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.function.powershell +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.block.powershell +# ^^^^^^^^^^^^ keyword.control.context.powershell +# ^ punctuation.section.block.begin.powershell +# ^^^^^^^^^^^^^^^^^^^^^^ meta.string.interpolated.powershell +# ^^^^^^^^^^^^^ string.quoted.double.powershell +# ^ punctuation.definition.string.begin.powershell +# ^^^^^^^^ meta.interpolation.powershell variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^^^^^ storage.modifier.scope.powershell +# ^ punctuation.accessor.colon.powershell +# ^ string.quoted.double.powershell punctuation.definition.string.end.powershell +# ^ punctuation.section.block.end.powershell } Test-Workflow # @@@@@@@@@@@@@ reference @@ -86,6 +99,26 @@ ## To change the variable in workflow scope, return the ## new value. $a = inlinescript {$b = $Using:a+1; $b} +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.function.powershell +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^ keyword.operator.assignment.powershell +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.block.powershell +# ^^^^^^^^^^^^ keyword.control.context.powershell +# ^ punctuation.section.block.begin.powershell +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^ keyword.operator.assignment.powershell +# ^^^^^^^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^^^^^ storage.modifier.scope.powershell +# ^ punctuation.accessor.colon.powershell +# ^ keyword.operator.unary.powershell +# ^ meta.number.integer.decimal.powershell constant.numeric.value.powershell +# ^ punctuation.terminator.statement.powershell +# ^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^ punctuation.section.block.end.powershell "Workflow New A = $a" } Test-Workflow From 8e35b8e317022201cb9547324ea8f94455edb215 Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Mon, 8 Dec 2025 20:43:26 -0500 Subject: [PATCH 78/81] Recognize wildcards in unquoted strings --- PowerShell.sublime-syntax | 10 +++++++++- Tests/syntax_test_PowerShell.ps1 | 5 +++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index 6df19da9..35b861bb 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -374,6 +374,7 @@ contexts: pop: 1 - include: path-punctuation - include: escape-sequences + - include: string-wildcards command-ending-sequences: - include: line-continuations @@ -889,8 +890,9 @@ contexts: scope: keyword.operator.arithmetic.powershell - match: -(?![[:alpha:]-]) scope: keyword.operator.arithmetic.powershell - - match: \* + - match: \*(?!\.?[[:alpha:]]) scope: keyword.operator.arithmetic.powershell + # Exclude foreach shortcut - match: '%(?!\s*\{)' scope: keyword.operator.arithmetic.powershell - match: \|\||&& @@ -1115,6 +1117,12 @@ contexts: - match: '[:,;]' scope: punctuation.separator.powershell + string-wildcards: + - match: \* + scope: constant.other.wildcard.asterisk.powershell + - match: \? + scope: constant.other.wildcard.questionmark.powershell + numbers: # Binary numbers - match: \b(0[bB])([01]*)({{int_suffix}}?{{unit_suffix}}?) diff --git a/Tests/syntax_test_PowerShell.ps1 b/Tests/syntax_test_PowerShell.ps1 index e47887ca..ef6da678 100644 --- a/Tests/syntax_test_PowerShell.ps1 +++ b/Tests/syntax_test_PowerShell.ps1 @@ -924,8 +924,9 @@ $a3[1..2] ls *.ps1 -recurse # ^^ meta.function-call.powershell variable.function.powershell # @@ reference -# ^ keyword.operator.arithmetic.powershell -# ^^^^ string.unquoted.powershell +# ^^^^^ string.unquoted.powershell +# ^ constant.other.wildcard.asterisk.powershell +# ^ punctuation.separator.powershell # ^^^^^^^^ variable.parameter.option.powershell # ^ punctuation.definition.parameter.powershell From 7dc10a538325382b8c71240372dc02b2f539d8a9 Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Mon, 8 Dec 2025 20:56:10 -0500 Subject: [PATCH 79/81] Scope command arguments --- PowerShell.sublime-syntax | 1 + Tests/syntax_test_PowerShell.ps1 | 221 +++++++++++++++++++------------ 2 files changed, 137 insertions(+), 85 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index 35b861bb..0ac9e761 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -362,6 +362,7 @@ contexts: push: in-command in-command: + - meta_content_scope: meta.function-call.arguments.powershell - include: command-ending-sequences - include: redirection - include: cli-parameters diff --git a/Tests/syntax_test_PowerShell.ps1 b/Tests/syntax_test_PowerShell.ps1 index ef6da678..eebe5dab 100644 --- a/Tests/syntax_test_PowerShell.ps1 +++ b/Tests/syntax_test_PowerShell.ps1 @@ -96,6 +96,7 @@ using namespace System.Management.Automation # ^ keyword.operator.call.powershell # ^^^^^^^^ meta.function-call.powershell variable.function.powershell # @@@@@@@@ reference +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.function-call.arguments.powershell # ^^^^^ variable.parameter.option.powershell # ^ punctuation.definition.parameter.powershell # ^^^^^^^ meta.string.powershell string.quoted.single.powershell @@ -112,6 +113,7 @@ using namespace System.Management.Automation # ^ keyword.operator.call.powershell # ^^^^^^^^^^^ meta.function-call.powershell variable.function.powershell # @@@@@@@@@@@ reference +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.function-call.arguments.powershell # ^^ variable.parameter.option.powershell # ^ punctuation.definition.parameter.powershell # ^^^^^^^^^^^^^^ meta.string.powershell string.quoted.single.powershell @@ -131,6 +133,7 @@ using namespace System.Management.Automation # ^ keyword.operator.assignment.powershell # ^^^^^^^^^^^ meta.function-call.powershell support.function.powershell # @@@@@@@@@@@ reference +# ^^^^^^^^^^^^^ meta.function-call.arguments.powershell # ^^^^^ variable.parameter.option.powershell # ^ punctuation.definition.parameter.powershell # ^^^^ string.unquoted.powershell @@ -138,6 +141,7 @@ using namespace System.Management.Automation Receive-Job $job -Wait # ^^^^^^^^^^^ meta.function-call.powershell support.function.powershell # @@@@@@@@@@@ reference +# ^^^^^^^^^^^ meta.function-call.arguments.powershell # ^^^^ variable.other.readwrite.powershell # ^ punctuation.definition.variable.powershell # ^^^^^ variable.parameter.option.powershell @@ -817,109 +821,156 @@ $a3[1..2] ###[ Commands ]################################################################ -# Commands (functions) - Invoke-Something -foobar -#^ support.function -# ^ punctuation.definition.parameter -# ^^^^^^^ variable.parameter.option -#@@@@@@@@@@@@@@@@ reference - Invoke-Something -foobar value -#^ support.function -# ^ punctuation.definition.parameter -# ^^^^^^^ variable.parameter.option -#@@@@@@@@@@@@@@@@ reference - Invoke-Something -foobar:$true -#^ support.function -#@@@@@@@@@@@@@@@@ reference -# ^ punctuation.definition.parameter -# ^^^^^^^ variable.parameter.option -# ^ punctuation.definition.variable -# ^^^^ constant.language - Invoke-Something -foobar: $true -#^ support.function -#@@@@@@@@@@@@@@@@ reference -# ^ punctuation.definition.parameter -# ^^^^^^^ variable.parameter.option - Invoke-Something -p1 v1 -p2 10 -p3 'value' -switch -verbose -#^ support.function -#@@@@@@@@@@@@@@@@ reference -# ^ punctuation.definition.parameter -# ^^^ variable.parameter.option -# ^ punctuation.definition.parameter -# ^^^ variable.parameter.option -# ^^ meta.number.integer.decimal constant.numeric.value -# ^^^^^^ - keyword -# ^ punctuation.definition.parameter -# ^^^ variable.parameter.option - Invoke-Something (1..20 | Invoke-Something) -p2 'value' -#^ support.function -#@@@@@@@@@@@@@@@@ reference -# @@@@@@@@@@@@@@@@ reference -# ^^ keyword.operator.range - Invoke-Something -p1 v2 -p2 30 | Invoke-Something -switch -#^ support.function -# @@@@@@@@@@@@@@@@ reference -#@@@@@@@@@@@@@@@@ reference -# ^ punctuation.definition.parameter -# ^^^ variable.parameter.option -# ^ punctuation.definition.parameter -# ^^^ variable.parameter.option -# ^^ meta.number.integer.decimal constant.numeric.value -# ^ keyword.operator.logical.pipe -# ^ support.function -# ^ punctuation.definition.parameter -# ^^^^^^^ variable.parameter.option - keyword - Invoke-Something -p1 { -#^ support.function -#@@@@@@@@@@@@@@@@ reference -# ^ punctuation.definition.parameter -# ^^^ variable.parameter.option + Invoke-Something -foobar +# ^^^^^^^^^^^^^^^^ meta.function-call.powershell support.function.powershell +# @@@@@@@@@@@@@@@@ reference +# ^^^^^^^^ meta.function-call.arguments.powershell +# ^^^^^^^ variable.parameter.option.powershell +# ^ punctuation.definition.parameter.powershell + Invoke-Something -foobar value +# ^^^^^^^^^^^^^^^^ meta.function-call.powershell support.function.powershell +# @@@@@@@@@@@@@@@@ reference +# ^^^^^^^^^^^^^^ meta.function-call.arguments.powershell +# ^^^^^^^ variable.parameter.option.powershell +# ^ punctuation.definition.parameter.powershell +# ^^^^^ string.unquoted.powershell Invoke-Something -foobar:$true -# ^ support.function +# ^^^^^^^^^^^^^^^^ meta.function-call.powershell support.function.powershell # @@@@@@@@@@@@@@@@ reference -# ^ punctuation.definition.parameter -# ^^^^^^^ variable.parameter.option -# ^ punctuation.definition.variable -# ^^^^ constant.language -} | Invoke-Something -# <- punctuation.section.braces.end -# ^ keyword.operator.logical.pipe -# ^ support.function +# ^^^^^^^^^^^^^^ meta.function-call.arguments.powershell +# ^^^^^^^ variable.parameter.option.powershell +# ^ punctuation.definition.parameter.powershell +# ^ keyword.operator.ternary.powershell +# ^^^^^ constant.language.boolean.true.powershell +# ^ punctuation.definition.variable.powershell + Invoke-Something -foobar: $true +# ^^^^^^^^^^^^^^^^ meta.function-call.powershell support.function.powershell # @@@@@@@@@@@@@@@@ reference - Invoke-Something -p1 value ` -#^^^^^^^^^^^^^^^^ meta.function-call.powershell support.function.powershell -#@@@@@@@@@@@@@@@@ reference -# ^^^ variable.parameter.option.powershell -# ^ punctuation.definition.parameter.powershell -# ^^^^^ string.unquoted.powershell -# ^ punctuation.separator.continuation.line.powershell +# ^^^^^^^^^^^^^^^ meta.function-call.arguments.powershell +# ^^^^^^^ variable.parameter.option.powershell +# ^ punctuation.definition.parameter.powershell +# ^ keyword.operator.ternary.powershell +# ^^^^^ constant.language.boolean.true.powershell +# ^ punctuation.definition.variable.powershell + Invoke-Something -p1 v1 -p2 10 -p3 'value' -switch -verbose +# ^^^^^^^^^^^^^^^^ meta.function-call.powershell support.function.powershell +# @@@@@@@@@@@@@@@@ reference +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.function-call.arguments.powershell +# ^^^ variable.parameter.option.powershell +# ^ punctuation.definition.parameter.powershell +# ^^ string.unquoted.powershell +# ^^^ variable.parameter.option.powershell +# ^ punctuation.definition.parameter.powershell +# ^^ meta.number.integer.decimal.powershell constant.numeric.value.powershell +# ^^^ variable.parameter.option.powershell +# ^ punctuation.definition.parameter.powershell +# ^^^^^^^ meta.string.powershell string.quoted.single.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^^^^^^^ variable.parameter.option.powershell +# ^ punctuation.definition.parameter.powershell +# ^^^^^^^^ variable.parameter.option.powershell +# ^ punctuation.definition.parameter.powershell + Invoke-Something (1..20 | Invoke-Something) -p2 'value' +# ^^^^^^^^^^^^^^^^ meta.function-call.powershell support.function.powershell +# @@@@@@@@@@@@@@@@ reference +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.function-call.arguments.powershell +# ^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.group.powershell +# ^ punctuation.section.group.begin.powershell +# ^ meta.number.integer.decimal.powershell constant.numeric.value.powershell +# ^^ keyword.operator.range.powershell +# ^^ meta.number.integer.decimal.powershell constant.numeric.value.powershell +# ^ keyword.operator.logical.pipe.powershell +# ^^^^^^^^^^^^^^^^ meta.function-call.powershell support.function.powershell +# @@@@@@@@@@@@@@@@ reference +# ^ punctuation.section.group.end.powershell +# ^^^ variable.parameter.option.powershell +# ^ punctuation.definition.parameter.powershell +# ^^^^^^^ meta.string.powershell string.quoted.single.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell + Invoke-Something -p1 v2 -p2 30 | Invoke-Something -switch +# ^^^^^^^^^^^^^^^^ meta.function-call.powershell support.function.powershell +# @@@@@@@@@@@@@@@@ reference +# ^^^^^^^^^^^^^^^ meta.function-call.arguments.powershell +# ^^^ variable.parameter.option.powershell +# ^ punctuation.definition.parameter.powershell +# ^^ string.unquoted.powershell +# ^^^ variable.parameter.option.powershell +# ^ punctuation.definition.parameter.powershell +# ^^ meta.number.integer.decimal.powershell constant.numeric.value.powershell +# ^ keyword.operator.logical.pipe.powershell +# ^^^^^^^^^^^^^^^^ meta.function-call.powershell support.function.powershell +# @@@@@@@@@@@@@@@@ reference +# ^^^^^^^^ meta.function-call.arguments.powershell +# ^^^^^^^ variable.parameter.option.powershell +# ^ punctuation.definition.parameter.powershell + Invoke-Something -p1 { +# ^^^^^^^^^^^^^^^^ meta.function-call.powershell support.function.powershell +# @@@@@@@@@@@@@@@@ reference +# ^^^^^^ meta.function-call.arguments.powershell +# ^^^ variable.parameter.option.powershell +# ^ punctuation.definition.parameter.powershell +# ^ meta.block.powershell punctuation.section.braces.begin.powershell + Invoke-Something -foobar:$true +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.function-call.arguments.powershell meta.block.powershell +# ^^^^^^^^^^^^^^^^ meta.function-call.powershell support.function.powershell +# @@@@@@@@@@@@@@@@ reference +# ^^^^^^^^^^^^^^ meta.function-call.arguments.powershell +# ^^^^^^^ variable.parameter.option.powershell +# ^ punctuation.definition.parameter.powershell +# ^ keyword.operator.ternary.powershell +# ^^^^^ constant.language.boolean.true.powershell +# ^ punctuation.definition.variable.powershell + } | Invoke-Something +#^^^^^^^^^ meta.function-call.arguments.powershell +#^^^^^^^^ meta.block.powershell +# ^ punctuation.section.braces.end.powershell +# ^ keyword.operator.logical.pipe.powershell +# ^^^^^^^^^^^^^^^^ meta.function-call.powershell support.function.powershell +# @@@@@@@@@@@@@@@@ reference + + Invoke-Something -p1 value ` +# ^^^^^^^^^^^^^^^^ meta.function-call.powershell support.function.powershell +# @@@@@@@@@@@@@@@@ reference +# ^^^^^^^^^^^^ meta.function-call.arguments.powershell +# ^^^ variable.parameter.option.powershell +# ^ punctuation.definition.parameter.powershell +# ^^^^^ string.unquoted.powershell +# ^ punctuation.separator.continuation.line.powershell -p2 14.4 ` -# ^ punctuation.definition.parameter -# ^^^ variable.parameter.option -# ^^^^ meta.number.float.decimal constant.numeric.value -# ^ punctuation.separator.continuation +#^^^^^^^^^^^^^ meta.function-call.arguments.powershell +# ^^^ variable.parameter.option.powershell +# ^ punctuation.definition.parameter.powershell +# ^^^^ meta.number.float.decimal.powershell constant.numeric.value.powershell +# ^ punctuation.separator.decimal.powershell +# ^ punctuation.separator.continuation.line.powershell -p3 $value | Invoke-Something -verbose -# ^ punctuation.definition.parameter -# ^^^ variable.parameter.option +#^^^^^^^^^^^^^^ meta.function-call.arguments.powershell +# ^^^ variable.parameter.option.powershell +# ^ punctuation.definition.parameter.powershell +# ^^^^^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^ keyword.operator.logical.pipe.powershell +# ^^^^^^^^^^^^^^^^ meta.function-call.powershell support.function.powershell # @@@@@@@@@@@@@@@@ reference -# ^ punctuation.definition.parameter -# ^^^^^^^^ variable.parameter.option -# ^ punctuation.definition.variable -# ^ keyword.operator.logical.pipe -# ^^^^^^^^^^^^^^^^ support.function +# ^^^^^^^^^ meta.function-call.arguments.powershell +# ^^^^^^^^ variable.parameter.option.powershell +# ^ punctuation.definition.parameter.powershell Get-ChildItem | # ^^^^^^^^^^^^^ meta.function-call.powershell support.function.powershell # @@@@@@@@@@@@@ reference +# ^^ meta.function-call.arguments.powershell # ^ keyword.operator.logical.pipe.powershell Select Name,Length # ^^^^^^ meta.function-call.powershell variable.function.powershell # @@@@@@ reference +# ^^^^^^^^^^^^ meta.function-call.arguments.powershell # ^^^^ string.unquoted.powershell # ^ punctuation.separator.sequence.powershell # ^^^^^^ string.unquoted.powershell - # Commands (Built-in variables) ls *.ps1 -recurse # ^^ meta.function-call.powershell variable.function.powershell From e62352fb04e09e92e099ec59392c4e613e1f1d4d Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Mon, 8 Dec 2025 20:57:45 -0500 Subject: [PATCH 80/81] Allow indented comments in line continuation --- PowerShell.sublime-syntax | 2 +- Tests/syntax_test_PowerShell.ps1 | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index 0ac9e761..c69559f7 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -1270,7 +1270,7 @@ contexts: 1: invalid.illegal.unexpected-whitespace.powershell line-continuation-body: - - match: ^ + - match: ^(?!\s*#) pop: 1 comma-separators: diff --git a/Tests/syntax_test_PowerShell.ps1 b/Tests/syntax_test_PowerShell.ps1 index eebe5dab..87b38ae3 100644 --- a/Tests/syntax_test_PowerShell.ps1 +++ b/Tests/syntax_test_PowerShell.ps1 @@ -945,6 +945,7 @@ $a3[1..2] # ^^^^ meta.number.float.decimal.powershell constant.numeric.value.powershell # ^ punctuation.separator.decimal.powershell # ^ punctuation.separator.continuation.line.powershell + # An indented comment doesn't interrupt line continuation -p3 $value | Invoke-Something -verbose #^^^^^^^^^^^^^^ meta.function-call.arguments.powershell # ^^^ variable.parameter.option.powershell From 96cae369ecd490fb112e9c430ed8527314db1ef3 Mon Sep 17 00:00:00 2001 From: Michael Lyons Date: Mon, 8 Dec 2025 21:34:17 -0500 Subject: [PATCH 81/81] Add naive regex in single-quoted strings following regex operators --- PowerShell.sublime-syntax | 26 +++++- Tests/syntax_test_strings.ps1 | 171 ++++++++++++++++++++++++++++++++++ 2 files changed, 195 insertions(+), 2 deletions(-) diff --git a/PowerShell.sublime-syntax b/PowerShell.sublime-syntax index c69559f7..cf6e7e8c 100644 --- a/PowerShell.sublime-syntax +++ b/PowerShell.sublime-syntax @@ -850,11 +850,21 @@ contexts: scope: keyword.operator.comparison.powershell captures: 1: punctuation.definition.keyword.powershell - - match: \B(-)(?i:[ic]?(?:not)?(?:like|match|contains|in)){{kebab_break}} + - match: \B(-)(?i:[ic]?(?:not)?(?:match)){{kebab_break}} scope: keyword.operator.logical.powershell captures: 1: punctuation.definition.keyword.powershell - - match: \B(-)(?i:join|split|replace){{kebab_break}} + push: expect-regex-string + - match: \B(-)(?i:[ic]?(?:not)?(?:like|contains|in)){{kebab_break}} + scope: keyword.operator.logical.powershell + captures: + 1: punctuation.definition.keyword.powershell + - match: \B(-)(?i:replace){{kebab_break}} + scope: keyword.operator.string.powershell + captures: + 1: punctuation.definition.keyword.powershell + push: expect-regex-string + - match: \B(-)(?i:join|split){{kebab_break}} scope: keyword.operator.string.powershell captures: 1: punctuation.definition.keyword.powershell @@ -995,6 +1005,18 @@ contexts: - include: double-quoted-heredoc-strings - include: single-quoted-heredoc-strings + expect-regex-string: + - match: '{{single_quote}}' + scope: meta.string.powershell string.quoted.single.powershell punctuation.definition.string.begin.powershell + embed: scope:source.regexp + embed_scope: meta.string.powershell source.regexp.embedded + escape: ({{single_quote}}) + escape_captures: + 1: meta.string.powershell string.quoted.single.powershell punctuation.definition.string.end.powershell + - include: comma-separators + - include: else-pop + - include: pop-eol + single-quoted-strings: - match: '{{single_quote}}' scope: punctuation.definition.string.begin.powershell diff --git a/Tests/syntax_test_strings.ps1 b/Tests/syntax_test_strings.ps1 index 9d68c1a5..05962bb2 100644 --- a/Tests/syntax_test_strings.ps1 +++ b/Tests/syntax_test_strings.ps1 @@ -238,6 +238,177 @@ "@ +###[ Regular Expressions ]##################################################### + + 'book' -match 'oo' +# ^^^^^^ meta.string.powershell string.quoted.single.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^^^^^^ keyword.operator.logical.powershell +# ^ punctuation.definition.keyword.powershell +# ^^^^ meta.string.powershell +# ^ string.quoted.single.powershell punctuation.definition.string.begin.powershell +# ^^ source.regexp.embedded +# ^ string.quoted.single.powershell punctuation.definition.string.end.powershell + 'big' -match 'b[iou]g' +# ^^^^^ meta.string.powershell string.quoted.single.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^^^^^^ keyword.operator.logical.powershell +# ^ punctuation.definition.keyword.powershell +# ^^^^^^^^^ meta.string.powershell +# ^ string.quoted.single.powershell punctuation.definition.string.begin.powershell +# ^^^^^^^ source.regexp.embedded +# ^ string.quoted.single.powershell punctuation.definition.string.end.powershell + 42 -match '[0-9][0-9]' +# ^^ meta.number.integer.decimal.powershell constant.numeric.value.powershell +# ^^^^^^ keyword.operator.logical.powershell +# ^ punctuation.definition.keyword.powershell +# ^^^^^^^^^^^^ meta.string.powershell +# ^ string.quoted.single.powershell punctuation.definition.string.begin.powershell +# ^^^^^^^^^^ source.regexp.embedded +# ^ string.quoted.single.powershell punctuation.definition.string.end.powershell + 'a1\ ' -match '....' +# ^^^^^^ meta.string.powershell string.quoted.single.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^^^^^^ keyword.operator.logical.powershell +# ^ punctuation.definition.keyword.powershell +# ^^^^^^ meta.string.powershell +# ^ string.quoted.single.powershell punctuation.definition.string.begin.powershell +# ^^^^ source.regexp.embedded keyword.other.any.regexp +# ^ string.quoted.single.powershell punctuation.definition.string.end.powershell + 'ACCOUNT NAME: Administrator' -match 'ACCOUNT NAME:\s*\w*' +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string.powershell string.quoted.single.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^^^^^^ keyword.operator.logical.powershell +# ^ punctuation.definition.keyword.powershell +# ^^^^^^^^^^^^^^^^^^^^^ meta.string.powershell +# ^ string.quoted.single.powershell punctuation.definition.string.begin.powershell +# ^^^^^^^^^^^^^^^^^^^ source.regexp.embedded +# ^^ keyword.control.character-class.regexp +# ^ keyword.operator.quantifier.regexp +# ^^ keyword.control.character-class.regexp +# ^ keyword.operator.quantifier.regexp +# ^ string.quoted.single.powershell punctuation.definition.string.end.powershell + 'SERVER01' -match '[A-Z]+-?\d\d' +# ^^^^^^^^^^ meta.string.powershell string.quoted.single.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^^^^^^ keyword.operator.logical.powershell +# ^ punctuation.definition.keyword.powershell +# ^^^^^^^^^^^^^^ meta.string.powershell +# ^ string.quoted.single.powershell punctuation.definition.string.begin.powershell +# ^^^^^^^^^^^^ source.regexp.embedded +# ^^^^^ meta.set.regexp +# ^ keyword.operator.quantifier.regexp +# ^ keyword.operator.quantifier.regexp +# ^^^^ keyword.control.character-class.regexp +# ^ string.quoted.single.powershell punctuation.definition.string.end.powershell + '111-222-3333' -match '\d{3}-\d{3}-\d{4}' +# ^^^^^^^^^^^^^^ meta.string.powershell string.quoted.single.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^^^^^^ keyword.operator.logical.powershell +# ^ punctuation.definition.keyword.powershell +# ^^^^^^^^^^^^^^^^^^^ meta.string.powershell +# ^ string.quoted.single.powershell punctuation.definition.string.begin.powershell +# ^^^^^^^^^^^^^^^^^ source.regexp.embedded +# ^^ keyword.control.character-class.regexp +# ^^^ keyword.operator.quantifier.regexp +# ^^ keyword.control.character-class.regexp +# ^^^ keyword.operator.quantifier.regexp +# ^^ keyword.control.character-class.regexp +# ^^^ keyword.operator.quantifier.regexp +# ^ string.quoted.single.powershell punctuation.definition.string.end.powershell + 'fishing' -match '^fish$' +# ^^^^^^^^^ meta.string.powershell string.quoted.single.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^^^^^^ keyword.operator.logical.powershell +# ^ punctuation.definition.keyword.powershell +# ^^^^^^^^ meta.string.powershell +# ^ string.quoted.single.powershell punctuation.definition.string.begin.powershell +# ^^^^^^ source.regexp.embedded +# ^ keyword.control +# ^ keyword.control +# ^ string.quoted.single.powershell punctuation.definition.string.end.powershell + '3.141' -match '3\.\d{2,}' +# ^^^^^^^ meta.string.powershell string.quoted.single.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^^^^^^ keyword.operator.logical.powershell +# ^ punctuation.definition.keyword.powershell +# ^^^^^^^^^^^ meta.string.powershell +# ^ string.quoted.single.powershell punctuation.definition.string.begin.powershell +# ^^^^^^^^^ source.regexp.embedded +# ^^ constant.character.escape.regexp +# ^^ keyword.control.character-class.regexp +# ^^^^ keyword.operator.quantifier.regexp +# ^ string.quoted.single.powershell punctuation.definition.string.end.powershell + 'The last logged on user was CONTOSO\jsmith' -match '(.+was )(.+)' +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string.powershell string.quoted.single.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^^^^^^ keyword.operator.logical.powershell +# ^ punctuation.definition.keyword.powershell +# ^^^^^^^^^^^^^^ meta.string.powershell +# ^ string.quoted.single.powershell punctuation.definition.string.begin.powershell +# ^^^^^^^^^^^^ source.regexp.embedded +# ^ keyword.other.any.regexp +# ^ keyword.operator.quantifier.regexp +# ^ keyword.other.any.regexp +# ^ keyword.operator.quantifier.regexp +# ^ string.quoted.single.powershell punctuation.definition.string.end.powershell + $string -match 'was (?.+)\\(?.+)' +# ^^^^^^^ variable.other.readwrite.powershell +# ^ punctuation.definition.variable.powershell +# ^^^^^^ keyword.operator.logical.powershell +# ^ punctuation.definition.keyword.powershell +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string.powershell +# ^ string.quoted.single.powershell punctuation.definition.string.begin.powershell +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ source.regexp.embedded +# ^ string.quoted.single.powershell punctuation.definition.string.end.powershell + 'Hello World' -replace '(\w+) \w+', '$1 Universe' +# ^^^^^^^^^^^^^ meta.string.powershell string.quoted.single.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^^^^^^^^ keyword.operator.string.powershell +# ^ punctuation.definition.keyword.powershell +# ^^^^^^^^^^^ meta.string.powershell +# ^ string.quoted.single.powershell punctuation.definition.string.begin.powershell +# ^^^^^^^^^ source.regexp.embedded +# ^^ keyword.control.character-class.regexp +# ^ keyword.operator.quantifier.regexp +# ^^ keyword.control.character-class.regexp +# ^ keyword.operator.quantifier.regexp +# ^ string.quoted.single.powershell punctuation.definition.string.end.powershell +# ^ punctuation.separator.sequence.powershell +# ^^^^^^^^^^^^^ meta.string.powershell +# ^ string.quoted.single.powershell punctuation.definition.string.begin.powershell +# ^^^^^^^^^^^ source.regexp.embedded +# ^ string.quoted.single.powershell punctuation.definition.string.end.powershell + "Hello World" -replace "(\w+) \w+", "`$1 Universe" + '5.72' -replace '(.+)', '$$$1' +# ^^^^^^ meta.string.powershell string.quoted.single.powershell +# ^ punctuation.definition.string.begin.powershell +# ^ punctuation.definition.string.end.powershell +# ^^^^^^^^ keyword.operator.string.powershell +# ^ punctuation.definition.keyword.powershell +# ^^^^^^ meta.string.powershell +# ^ string.quoted.single.powershell punctuation.definition.string.begin.powershell +# ^^^^ source.regexp.embedded +# ^ keyword.other.any.regexp +# ^ keyword.operator.quantifier.regexp +# ^ string.quoted.single.powershell punctuation.definition.string.end.powershell +# ^ punctuation.separator.sequence.powershell +# ^^^^^^ meta.string.powershell +# ^ string.quoted.single.powershell punctuation.definition.string.begin.powershell +# ^^^^ source.regexp.embedded +# ^ string.quoted.single.powershell punctuation.definition.string.end.powershell + "5.72" -replace "(.+)", "`$`$`$1" + ###[ String Formatting ]####################################################### "{0:N2}" -f $a