Skip to content

Commit 62f81c8

Browse files
committed
Remove argument escaping logic from script launching
Attempting to be "helpful" by escaping arguments proved to cause more issues than it solved. We can instead massively simplify our script launching logic (and fix yet another test that had a "maybe bug") by just launching what the user gave us. This should also be easier for the user to debug.
1 parent 5649efd commit 62f81c8

File tree

5 files changed

+20
-168
lines changed

5 files changed

+20
-168
lines changed

src/PowerShellEditorServices/Services/DebugAdapter/Handlers/ConfigurationDoneHandler.cs

+7-29
Original file line numberDiff line numberDiff line change
@@ -102,35 +102,13 @@ public Task<ConfigurationDoneResponse> Handle(ConfigurationDoneArguments request
102102

103103
private async Task LaunchScriptAsync(string scriptToLaunch)
104104
{
105-
PSCommand cmd;
106-
if (ScriptFile.IsUntitledPath(scriptToLaunch))
107-
{
108-
ScriptFile untitledScript = _workspaceService.GetFile(scriptToLaunch);
109-
if (BreakpointApiUtils.SupportsBreakpointApis(_runspaceContext.CurrentRunspace))
110-
{
111-
// Parse untitled files with their `Untitled:` URI as the file name which will
112-
// cache the URI and contents within the PowerShell parser. By doing this, we
113-
// light up the ability to debug Untitled files with breakpoints. This is only
114-
// possible via the direct usage of the breakpoint APIs in PowerShell because
115-
// Set-PSBreakpoint validates that paths are actually on the filesystem.
116-
ScriptBlockAst ast = Parser.ParseInput(
117-
untitledScript.Contents,
118-
untitledScript.DocumentUri.ToString(),
119-
out _,
120-
out _);
121-
// TODO: This breaks the ability to debug untitled files with breakpoints.
122-
cmd = PSCommandHelpers.BuildCommandFromArguments(ast.GetScriptBlock().ToString(), _debugStateService.Arguments, isScriptBlock: true);
123-
}
124-
else
125-
{
126-
cmd = PSCommandHelpers.BuildCommandFromArguments(untitledScript.Contents, _debugStateService.Arguments, isScriptBlock: true);
127-
}
128-
}
129-
else
130-
{
131-
cmd = PSCommandHelpers.BuildCommandFromArguments(scriptToLaunch, _debugStateService.Arguments, isScriptBlock: false);
132-
}
133-
105+
// TODO: Theoretically we can make PowerShell respect line breakpoints in untitled
106+
// files, but the previous method was a hack that conflicted with correct passing of
107+
// arguments to the debugged script. We are prioritizing the latter over the former, as
108+
// command breakpoints and `Wait-Debugger` work fine.
109+
PSCommand cmd = ScriptFile.IsUntitledPath(scriptToLaunch)
110+
? PSCommandHelpers.BuildCommandFromArguments(string.Concat("{ ", _workspaceService.GetFile(scriptToLaunch).Contents, " }"), _debugStateService.Arguments)
111+
: PSCommandHelpers.BuildCommandFromArguments(string.Concat('"', scriptToLaunch, '"'), _debugStateService.Arguments);
134112
await _executionService.ExecutePSCommandAsync(cmd, CancellationToken.None, s_debuggerExecutionOptions).ConfigureAwait(false);
135113
_debugAdapterServer.SendNotification(EventNames.Terminated);
136114
}

src/PowerShellEditorServices/Utility/ArgumentUtils.cs

-47
This file was deleted.

src/PowerShellEditorServices/Utility/PSCommandExtensions.cs

+2-17
Original file line numberDiff line numberDiff line change
@@ -129,25 +129,10 @@ private static StringBuilder AddCommandText(this StringBuilder sb, Command comma
129129
return sb;
130130
}
131131

132-
public static PSCommand BuildCommandFromArguments(string command, IReadOnlyList<string> arguments, bool isScriptBlock = false)
132+
public static PSCommand BuildCommandFromArguments(string command, IEnumerable<string> arguments = default)
133133
{
134134
// HACK: We use AddScript instead of AddArgument/AddParameter to reuse Powershell parameter binding logic.
135-
// We quote the command parameter so that expressions can still be used in the arguments.
136-
var sb = new StringBuilder()
137-
.Append('.')
138-
.Append(' ')
139-
.Append(isScriptBlock ? "{ " : '"')
140-
.Append(command)
141-
.Append(isScriptBlock ? " }" : '"');
142-
143-
foreach (string arg in arguments ?? System.Linq.Enumerable.Empty<string>())
144-
{
145-
sb
146-
.Append(' ')
147-
.Append(ArgumentEscaping.Escape(arg));
148-
}
149-
150-
return new PSCommand().AddScript(sb.ToString());
135+
return new PSCommand().AddScript(string.Concat(". ", command, " ", string.Join(" ", arguments)));
151136
}
152137
}
153138
}

test/PowerShellEditorServices.Test/Debugging/DebugServiceTests.cs

+11-6
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ private VariableDetailsBase[] GetVariables(string scopeName)
9696
private Task ExecutePowerShellCommand(string command, params string[] args)
9797
{
9898
return psesHost.ExecutePSCommandAsync(
99-
PSCommandHelpers.BuildCommandFromArguments(command, args),
99+
PSCommandHelpers.BuildCommandFromArguments(string.Concat('"', command, '"'), args),
100100
CancellationToken.None);
101101
}
102102

@@ -176,8 +176,16 @@ await debugService.SetCommandBreakpointsAsync(
176176
Assert.Equal("[ArrayList: 0]", var.ValueString);
177177
}
178178

179-
[Fact]
180-
public async Task DebuggerAcceptsScriptArgs()
179+
// See https://www.thomasbogholm.net/2021/06/01/convenient-member-data-sources-with-xunit/
180+
public static IEnumerable<object[]> DebuggerAcceptsScriptArgsTestData => new List<object[]>()
181+
{
182+
new object[] { new object[] { "Foo -Param2 @('Bar','Baz') -Force Extra1" } },
183+
new object[] { new object[] { "Foo", "-Param2", "@('Bar','Baz')", "-Force", "Extra1" } }
184+
};
185+
186+
[Theory]
187+
[MemberData(nameof(DebuggerAcceptsScriptArgsTestData))]
188+
public async Task DebuggerAcceptsScriptArgs(string[] args)
181189
{
182190
// The path is intentionally odd (some escaped chars but not all) because we are testing
183191
// the internal path escaping mechanism - it should escape certains chars ([, ] and space) but
@@ -197,9 +205,6 @@ public async Task DebuggerAcceptsScriptArgs()
197205
Assert.True(breakpoint.Verified);
198206
});
199207

200-
// TODO: This test used to also pass the args as a single string, but that doesn't seem
201-
// to work any more. Perhaps that's a bug?
202-
var args = new[] { "Foo", "-Param2", "@('Bar','Baz')", "-Force", "Extra1" };
203208
Task _ = ExecutePowerShellCommand(debugWithParamsFile.FilePath, args);
204209

205210
AssertDebuggerStopped(debugWithParamsFile.FilePath, 3);

test/PowerShellEditorServices.Test/Utility/ArgumentEscapingTests.cs

-69
This file was deleted.

0 commit comments

Comments
 (0)