Skip to content

Commit 68434e6

Browse files
committed
Fix running untitled scripts with arguments (but break debugging)
So the extant hack that enabled debugging untitled scripts is really untenable. It shifted the user's args by one since it ran the untitled script as the first arg to the dot-source operator. Unfortunately, there doesn't seem to be a clear way to break on lines in an untitled script. However, `Wait-Debugger` and command breakpoints should still work.
1 parent 77d1ffc commit 68434e6

File tree

2 files changed

+22
-34
lines changed

2 files changed

+22
-34
lines changed

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

+19-31
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
// Copyright (c) Microsoft Corporation.
22
// Licensed under the MIT License.
33

4+
using System.Management.Automation;
5+
using System.Management.Automation.Language;
6+
using System.Threading;
7+
using System.Threading.Tasks;
48
using Microsoft.Extensions.Logging;
59
using Microsoft.PowerShell.EditorServices.Services;
610
using Microsoft.PowerShell.EditorServices.Services.DebugAdapter;
@@ -13,10 +17,6 @@
1317
using OmniSharp.Extensions.DebugAdapter.Protocol.Events;
1418
using OmniSharp.Extensions.DebugAdapter.Protocol.Requests;
1519
using OmniSharp.Extensions.DebugAdapter.Protocol.Server;
16-
using System.Management.Automation;
17-
using System.Management.Automation.Language;
18-
using System.Threading;
19-
using System.Threading.Tasks;
2020

2121
namespace Microsoft.PowerShell.EditorServices.Handlers
2222
{
@@ -102,48 +102,36 @@ public Task<ConfigurationDoneResponse> Handle(ConfigurationDoneArguments request
102102

103103
private async Task LaunchScriptAsync(string scriptToLaunch)
104104
{
105-
// Is this an untitled script?
105+
PSCommand cmd;
106106
if (ScriptFile.IsUntitledPath(scriptToLaunch))
107107
{
108108
ScriptFile untitledScript = _workspaceService.GetFile(scriptToLaunch);
109-
110109
if (BreakpointApiUtils.SupportsBreakpointApis(_runspaceContext.CurrentRunspace))
111110
{
112-
// Parse untitled files with their `Untitled:` URI as the file name which will cache the URI & contents within the PowerShell parser.
113-
// By doing this, we light up the ability to debug Untitled files with breakpoints.
114-
// This is only possible via the direct usage of the breakpoint APIs in PowerShell because
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
115115
// Set-PSBreakpoint validates that paths are actually on the filesystem.
116-
ScriptBlockAst ast = Parser.ParseInput(untitledScript.Contents, untitledScript.DocumentUri.ToString(), out Token[] tokens, out ParseError[] errors);
117-
118-
// This seems to be the simplest way to invoke a script block (which contains breakpoint information) via the PowerShell API.
119-
//
120-
// TODO: Fix this so the added script doesn't show up.
121-
var cmd = new PSCommand().AddScript(". $args[0]").AddArgument(ast.GetScriptBlock());
122-
await _executionService
123-
.ExecutePSCommandAsync<object>(cmd, CancellationToken.None, s_debuggerExecutionOptions)
124-
.ConfigureAwait(false);
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);
125123
}
126124
else
127125
{
128-
await _executionService
129-
.ExecutePSCommandAsync(
130-
new PSCommand().AddScript(untitledScript.Contents),
131-
CancellationToken.None,
132-
s_debuggerExecutionOptions)
133-
.ConfigureAwait(false);
126+
cmd = PSCommandHelpers.BuildCommandFromArguments(untitledScript.Contents, _debugStateService.Arguments, isScriptBlock: true);
134127
}
135128
}
136129
else
137130
{
138-
// TODO: Fix this so the added script doesn't show up.
139-
await _executionService
140-
.ExecutePSCommandAsync(
141-
PSCommandHelpers.BuildCommandFromArguments(scriptToLaunch, _debugStateService.Arguments),
142-
CancellationToken.None,
143-
s_debuggerExecutionOptions)
144-
.ConfigureAwait(false);
131+
cmd = PSCommandHelpers.BuildCommandFromArguments(scriptToLaunch, _debugStateService.Arguments, isScriptBlock: false);
145132
}
146133

134+
await _executionService.ExecutePSCommandAsync(cmd, CancellationToken.None, s_debuggerExecutionOptions).ConfigureAwait(false);
147135
_debugAdapterServer.SendNotification(EventNames.Terminated);
148136
}
149137
}

src/PowerShellEditorServices/Utility/PSCommandExtensions.cs

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

132-
public static PSCommand BuildCommandFromArguments(string command, IReadOnlyList<string> arguments)
132+
public static PSCommand BuildCommandFromArguments(string command, IReadOnlyList<string> arguments, bool isScriptBlock = false)
133133
{
134134
// HACK: We use AddScript instead of AddArgument/AddParameter to reuse Powershell parameter binding logic.
135135
// We quote the command parameter so that expressions can still be used in the arguments.
136136
var sb = new StringBuilder()
137137
.Append('.')
138138
.Append(' ')
139-
.Append('"')
139+
.Append(isScriptBlock ? "{ " : '"')
140140
.Append(command)
141-
.Append('"');
141+
.Append(isScriptBlock ? " }" : '"');
142142

143143
foreach (string arg in arguments ?? System.Linq.Enumerable.Empty<string>())
144144
{

0 commit comments

Comments
 (0)