Update SelectCommandArgument to properly handle POSIX style options for CLI commands (#4016)

This commit is contained in:
Dongbo Wang
2024-05-14 13:34:37 -07:00
committed by GitHub
parent 4023f0607d
commit 61f598d8a7
2 changed files with 73 additions and 1 deletions
+23 -1
View File
@@ -6,6 +6,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Management.Automation.Language;
using System.Text.RegularExpressions;
using Microsoft.PowerShell.Internal;
namespace Microsoft.PowerShell
@@ -29,6 +30,10 @@ namespace Microsoft.PowerShell
private YankLastArgState _yankLastArgState;
private int _visualSelectionCommandCount;
// Pattern to check for CLI parameters like '--json'.
// Valid characters are 'a-z', 'A-Z', '0-9', '_' (all covered by '\w'), and '-'.
private static readonly Regex s_cliOptionPattern = new(@"^--[\w-]+$", RegexOptions.Compiled);
/// <summary>
/// Mark the current location of the cursor for use in a subsequent editing command.
/// </summary>
@@ -480,7 +485,7 @@ namespace Microsoft.PowerShell
var argument = cmdAst.CommandElements[j] switch
{
CommandParameterAst paramAst => paramAst.Argument,
ExpressionAst expAst => expAst,
ExpressionAst exprAst => ProcessExpressionAst(exprAst),
_ => null,
};
@@ -614,6 +619,7 @@ namespace Microsoft.PowerShell
_singleton.VisualSelectionCommon(() => SetCursorPosition(newEndCursor), forceSetMark: true);
// ===== Local Functions =====
// Get the script block AST's whose extent contains the cursor.
bool GetScriptBlockAst(Ast ast)
{
@@ -639,6 +645,22 @@ namespace Microsoft.PowerShell
? ast.Extent.EndOffset - 1 > cursor
: ast.Extent.EndOffset >= cursor;
}
// Process an expression AST to check if it's a CLI posix style option.
static ExpressionAst ProcessExpressionAst(ExpressionAst exprAst)
{
if (exprAst is StringConstantExpressionAst strAst
&& strAst.StringConstantType is StringConstantType.BareWord
&& strAst.Value.StartsWith("--")
&& s_cliOptionPattern.IsMatch(strAst.Value))
{
// It's a CLI posix style option, like '--json' or '--machine-type',
// so we treat it as a parameter.
return null;
}
return exprAst;
}
}
/// <summary>
+50
View File
@@ -619,6 +619,56 @@ namespace Test
_.Escape));
}
[SkippableFact]
public void SelectCommandArgument_CLIArgs()
{
TestSetup(KeyMode.Cmd);
Test("", Keys(
"az webapp --name MyWebApp --resource-group MyResourceGroup",
_.Alt_a, CheckThat(() => AssertScreenIs(1,
TokenClassification.Command, "az",
TokenClassification.None, ' ',
TokenClassification.Selection, "webapp",
TokenClassification.None, ' ',
TokenClassification.Parameter, "--name",
TokenClassification.None, " MyWebApp ",
TokenClassification.Parameter, "--resource-group",
TokenClassification.None, " MyResourceGroup ")),
_.Alt_a, CheckThat(() => AssertScreenIs(1,
TokenClassification.Command, "az",
TokenClassification.None, " webapp ",
TokenClassification.Parameter, "--name",
TokenClassification.None, ' ',
TokenClassification.Selection, "MyWebApp",
TokenClassification.None, ' ',
TokenClassification.Parameter, "--resource-group",
TokenClassification.None, " MyResourceGroup ")),
_.Alt_a, CheckThat(() => AssertScreenIs(1,
TokenClassification.Command, "az",
TokenClassification.None, " webapp ",
TokenClassification.Parameter, "--name",
TokenClassification.None, " MyWebApp ",
TokenClassification.Parameter, "--resource-group",
TokenClassification.None, ' ',
TokenClassification.Selection, "MyResourceGroup")),
// Verify that we can loop through the arguments.
_.Alt_a, CheckThat(() => AssertScreenIs(1,
TokenClassification.Command, "az",
TokenClassification.None, ' ',
TokenClassification.Selection, "webapp",
TokenClassification.None, ' ',
TokenClassification.Parameter, "--name",
TokenClassification.None, " MyWebApp ",
TokenClassification.Parameter, "--resource-group",
TokenClassification.None, " MyResourceGroup ")),
_.Escape));
}
[SkippableFact]
public void SelectCommandArgument_HereStringArgs()
{