Skip to content

Commit c52e26d

Browse files
LucasAronaandyleejordan
authored andcommitted
Add the ability to use the Call operator instead of the DotSource operator
With a unit test!
1 parent 9cda0eb commit c52e26d

File tree

6 files changed

+32
-13
lines changed

6 files changed

+32
-13
lines changed

src/PowerShellEditorServices/Services/DebugAdapter/DebugStateService.cs

+2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ internal class DebugStateService
3434

3535
internal bool IsUsingTempIntegratedConsole { get; set; }
3636

37+
internal string ExecuteMode { get; set; }
38+
3739
// This gets set at the end of the Launch/Attach handler which set debug state.
3840
internal TaskCompletionSource<bool> ServerStarted { get; set; }
3941

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

+4-2
Original file line numberDiff line numberDiff line change
@@ -110,9 +110,11 @@ internal async Task LaunchScriptAsync(string scriptToLaunch)
110110
PSCommand command;
111111
if (System.IO.File.Exists(scriptToLaunch))
112112
{
113-
// For a saved file we just execute its path (after escaping it).
113+
// For a saved file we just execute its path (after escaping it), with the configured operator
114+
// (which can't be called that because it's a reserved keyword in C#).
115+
string executeMode = _debugStateService?.ExecuteMode == "Call" ? "&" : ".";
114116
command = PSCommandHelpers.BuildDotSourceCommandWithArguments(
115-
PSCommandHelpers.EscapeScriptFilePath(scriptToLaunch), _debugStateService?.Arguments);
117+
PSCommandHelpers.EscapeScriptFilePath(scriptToLaunch), _debugStateService?.Arguments, executeMode);
116118
}
117119
else // It's a URI to an untitled script, or a raw script.
118120
{

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

+6
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,11 @@ internal record PsesLaunchRequestArguments : LaunchRequestArguments
6565
/// </summary>
6666
public string[] RuntimeArgs { get; set; }
6767

68+
/// <summary>
69+
/// Gets or sets the script execution mode, either "DotSource" or "Call".
70+
/// </summary>
71+
public string ExecuteMode { get; set; }
72+
6873
/// <summary>
6974
/// Gets or sets optional environment variables to pass to the debuggee. The string valued
7075
/// properties of the 'environmentVariables' are used as key/value pairs.
@@ -186,6 +191,7 @@ public async Task<LaunchResponse> Handle(PsesLaunchRequestArguments request, Can
186191
_debugStateService.ScriptToLaunch = request.Script;
187192
_debugStateService.Arguments = request.Args;
188193
_debugStateService.IsUsingTempIntegratedConsole = request.CreateTemporaryIntegratedConsole;
194+
_debugStateService.ExecuteMode = request.ExecuteMode;
189195

190196
if (request.CreateTemporaryIntegratedConsole
191197
&& !string.IsNullOrEmpty(request.Script)

src/PowerShellEditorServices/Utility/PSCommandExtensions.cs

+4-2
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,12 @@ private static StringBuilder AddCommandText(this StringBuilder sb, Command comma
9494

9595
public static string EscapeScriptFilePath(string f) => string.Concat("'", f.Replace("'", "''"), "'");
9696

97-
public static PSCommand BuildDotSourceCommandWithArguments(string command, IEnumerable<string> arguments)
97+
// Operator defaults to dot-source but could also be call (ampersand).
98+
// It can't be called that because it's a reserved keyword in C#.
99+
public static PSCommand BuildDotSourceCommandWithArguments(string command, IEnumerable<string> arguments, string executeMode = ".")
98100
{
99101
string args = string.Join(" ", arguments ?? Array.Empty<string>());
100-
string script = string.Concat(". ", command, string.IsNullOrEmpty(args) ? "" : " ", args);
102+
string script = string.Concat(executeMode, " ", command, string.IsNullOrEmpty(args) ? "" : " ", args);
101103
// HACK: We use AddScript instead of AddArgument/AddParameter to reuse Powershell parameter binding logic.
102104
return new PSCommand().AddScript(script);
103105
}

test/PowerShellEditorServices.Test.E2E/DebugAdapterClientExtensions.cs

+5-9
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,17 @@ namespace PowerShellEditorServices.Test.E2E
1111
{
1212
public static class DebugAdapterClientExtensions
1313
{
14-
public static async Task LaunchScript(this DebugAdapterClient debugAdapterClient, string script, TaskCompletionSource<object> started)
14+
public static async Task LaunchScript(this DebugAdapterClient debugAdapterClient, string script, TaskCompletionSource<object> started, string executeMode = "DotSource")
1515
{
16-
LaunchResponse launchResponse = await debugAdapterClient.Launch(
16+
_ = await debugAdapterClient.Launch(
1717
new PsesLaunchRequestArguments
1818
{
1919
NoDebug = false,
2020
Script = script,
2121
Cwd = "",
22-
CreateTemporaryIntegratedConsole = false
23-
});
24-
25-
if (launchResponse is null)
26-
{
27-
throw new Exception("Launch response was null.");
28-
}
22+
CreateTemporaryIntegratedConsole = false,
23+
ExecuteMode = executeMode,
24+
}) ?? throw new Exception("Launch response was null.");
2925

3026
// This will check to see if we received the Initialized event from the server.
3127
await started.Task;

test/PowerShellEditorServices.Test.E2E/DebugAdapterProtocolMessageTests.cs

+11
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,17 @@ public async Task UsesDotSourceOperatorAndQuotesAsync()
189189
(i) => Assert.StartsWith(". '", i));
190190
}
191191

192+
[Fact]
193+
public async Task UsesCallOperatorWithSettingAsync()
194+
{
195+
string filePath = NewTestFile(GenerateScriptFromLoggingStatements("$($MyInvocation.Line)"));
196+
await PsesDebugAdapterClient.LaunchScript(filePath, Started, executeMode: "Call");
197+
ConfigurationDoneResponse configDoneResponse = await PsesDebugAdapterClient.RequestConfigurationDone(new ConfigurationDoneArguments());
198+
Assert.NotNull(configDoneResponse);
199+
Assert.Collection(await GetLog(),
200+
(i) => Assert.StartsWith("& '", i));
201+
}
202+
192203
[Fact]
193204
public async Task CanLaunchScriptWithNoBreakpointsAsync()
194205
{

0 commit comments

Comments
 (0)