Skip to content

Modernize alias expansion to use the language parser#2312

Open
andyleejordan wants to merge 1 commit into
mainfrom
andyleejordan/modernize-alias-expansion
Open

Modernize alias expansion to use the language parser#2312
andyleejordan wants to merge 1 commit into
mainfrom
andyleejordan/modernize-alias-expansion

Conversation

@andyleejordan

@andyleejordan andyleejordan commented Jun 16, 2026

Copy link
Copy Markdown
Member

Fixes #2108.

The powerShell/expandAlias handler built an embedded PowerShell here-string that called [System.Management.Automation.PsParser]::Tokenize to find command tokens. That legacy tokenizer is Windows PowerShell / full-framework only and carries its parsing limitations.

This rewrites the logic in C# against the modern, cross-edition APIs:

  • Tokenize with Parser.ParseInput and select command-name tokens via TokenFlags.CommandName instead of the legacy PSTokenType.Command.
  • Resolve every distinct name to its alias definition in a single Get-Command -CommandType Alias round-trip, rather than re-defining a helper function and querying one token at a time.
  • Escape wildcard metacharacters with WildcardPattern.Escape so aliases whose names are patterns — ? (Where-Object) and % (ForEach-Object) — resolve to themselves. The old script did this by hand with a leading backtick.
  • Rebuild the text by substituting from the highest offset down so earlier extents stay valid as the length changes, preserving behavior for multiple aliases on a line and multi-token definitions.

Scripts with no aliases are returned unchanged, and the JSON-RPC contract (IExpandAliasHandler / powerShell/expandAlias / ExpandAliasParams.TextExpandAliasResult.Text) is untouched.

Testing

Extended the E2E tests with a multi-alias line that includes the wildcard-named ? alias — gci | ? Name | % NameGet-ChildItem | Where-Object Name | ForEach-Object Name — which the naive modern approach would mishandle. Both ExpandAlias E2E tests pass.

The `powerShell/expandAlias` handler built an embedded PowerShell
here-string that called `[System.Management.Automation.PsParser]::Tokenize`
to find command tokens. That legacy tokenizer is Windows PowerShell /
full-framework only and carries the parsing limitations that come with it.

This rewrites the logic in C# against the modern, cross-edition APIs:

- Tokenize with `Parser.ParseInput` and select command-name tokens via
  `TokenFlags.CommandName` instead of the legacy `PSTokenType.Command`.
- Resolve every distinct name to its alias definition in a single
  `Get-Command -CommandType Alias` round-trip rather than re-defining a
  helper function and querying one token at a time.
- Escape wildcard metacharacters with `WildcardPattern.Escape` so aliases
  whose names are patterns -- `?` (Where-Object) and `%` (ForEach-Object)
  -- resolve to themselves. The old script did this by hand with a leading
  backtick.
- Rebuild the text by substituting from the highest offset down so the
  earlier extents stay valid as the length changes, preserving the existing
  behavior for multiple aliases on a line and multi-token definitions.

Scripts with no aliases are returned unchanged. The JSON-RPC contract is
untouched. I extended the E2E tests with a multi-alias line that includes
the wildcard-named `?` alias, which the naive modern approach would
mishandle.

Fixes #2108

Drafted by Copilot (Claude Opus 4.8).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 16, 2026 03:26
@andyleejordan andyleejordan added Issue-Enhancement A feature request (enhancement). Area-Language Server labels Jun 16, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR modernizes the ExpandAliasHandler by replacing a legacy approach that repeatedly defined and executed an internal PowerShell script using the obsolete PsParser tokenizer with a modern implementation that uses the System.Management.Automation.Language.Parser API directly from C#. This addresses issue #2108.

Changes:

  • Replaced the inline PowerShell script with C# code that uses Parser.ParseInput to tokenize the input and identify command-name tokens, resolves aliases via a single Get-Command call, and performs backward string substitution using StringBuilder.
  • Added proper handling of wildcard metacharacter alias names (like ? and %) via WildcardPattern.Escape.
  • Added a new E2E test that exercises multiple aliases on one line, including wildcard metacharacter aliases.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
src/PowerShellEditorServices/Services/PowerShell/Handlers/ExpandAliasHandler.cs Rewrote alias expansion to use the modern language parser and C#-native token manipulation instead of an inline PowerShell script with the legacy PsParser.
test/PowerShellEditorServices.Test.E2E/LanguageServerProtocolMessageTests.cs Added E2E test for expanding multiple aliases (including ? and %) in a single request.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@andyleejordan

Copy link
Copy Markdown
Member Author

Well that's an old TODO solved and the tests pass so...

@andyleejordan andyleejordan enabled auto-merge (squash) June 16, 2026 03:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area-Language Server Issue-Enhancement A feature request (enhancement).

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Update ExpandAliasHandler to use latest PowerShell parser

2 participants