Skip to content

Commit cfd4959

Browse files
authored
Merge pull request #412 from daviwil/execution-options
Interrupt integrated console command prompt when commands are executed
2 parents 0b2a773 + ec2c814 commit cfd4959

File tree

10 files changed

+292
-58
lines changed

10 files changed

+292
-58
lines changed

Diff for: src/PowerShellEditorServices.Protocol/Server/DebugAdapter.cs

-12
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,6 @@ protected override void Initialize()
100100

101101
protected Task LaunchScript(RequestContext<object> requestContext)
102102
{
103-
// Ensure the read loop is stopped
104-
this.editorSession.ConsoleService.CancelReadLoop();
105-
106103
// Is this an untitled script?
107104
Task launchTask = null;
108105

@@ -144,9 +141,6 @@ private async Task OnExecutionCompleted(Task executeTask)
144141

145142
if (this.isAttachSession)
146143
{
147-
// Ensure the read loop is stopped
148-
this.editorSession.ConsoleService.CancelReadLoop();
149-
150144
// Pop the sessions
151145
if (this.editorSession.PowerShellContext.CurrentRunspace.Context == RunspaceContext.EnteredProcess)
152146
{
@@ -165,12 +159,6 @@ private async Task OnExecutionCompleted(Task executeTask)
165159
Logger.WriteException("Caught exception while popping attached process after debugging", e);
166160
}
167161
}
168-
169-
}
170-
171-
if (!this.ownsEditorSession)
172-
{
173-
this.editorSession.ConsoleService.StartReadLoop();
174162
}
175163

176164
if (this.disconnectRequestContext != null)

Diff for: src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs

-3
Original file line numberDiff line numberDiff line change
@@ -1108,9 +1108,6 @@ protected Task HandleEvaluateRequest(
11081108
DebugAdapterMessages.EvaluateRequestArguments evaluateParams,
11091109
RequestContext<DebugAdapterMessages.EvaluateResponseBody> requestContext)
11101110
{
1111-
// Cancel the read loop before executing
1112-
this.editorSession.ConsoleService.CancelReadLoop();
1113-
11141111
// We don't await the result of the execution here because we want
11151112
// to be able to receive further messages while the current script
11161113
// is executing. This important in cases where the pipeline thread

Diff for: src/PowerShellEditorServices/Console/ChoicePromptHandler.cs

+8-1
Original file line numberDiff line numberDiff line change
@@ -199,8 +199,15 @@ private async Task<int[]> StartPromptLoop(
199199
break;
200200
}
201201

202-
// If the handler returns null it means we should prompt again
203202
choiceIndexes = this.HandleResponse(responseString);
203+
204+
// Return the default choice values if no choices were entered
205+
if (choiceIndexes == null && string.IsNullOrEmpty(responseString))
206+
{
207+
choiceIndexes = this.DefaultChoices;
208+
}
209+
210+
// If the user provided no choices, we should prompt again
204211
if (choiceIndexes != null)
205212
{
206213
break;

Diff for: src/PowerShellEditorServices/Console/ConsoleService.cs

+42-30
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ public ConsoleService(
7979
this.powerShellContext.ConsoleHost = this;
8080
this.powerShellContext.DebuggerStop += PowerShellContext_DebuggerStop;
8181
this.powerShellContext.DebuggerResumed += PowerShellContext_DebuggerResumed;
82+
this.powerShellContext.ExecutionStatusChanged += PowerShellContext_ExecutionStatusChanged;
8283

8384
// Set the default prompt handler factory or create
8485
// a default if one is not provided
@@ -140,31 +141,6 @@ public void CancelReadLoop()
140141
}
141142
}
142143

143-
/// <summary>
144-
/// Called when a command string is received from the user.
145-
/// If a prompt is currently active, the prompt handler is
146-
/// asked to handle the string. Otherwise the string is
147-
/// executed in the PowerShellContext.
148-
/// </summary>
149-
/// <param name="inputString">The input string to evaluate.</param>
150-
/// <param name="echoToConsole">If true, the input will be echoed to the console.</param>
151-
public void ExecuteCommand(string inputString, bool echoToConsole)
152-
{
153-
this.CancelReadLoop();
154-
155-
if (this.activePromptHandler == null)
156-
{
157-
// Execute the script string but don't wait for completion
158-
var executeTask =
159-
this.powerShellContext
160-
.ExecuteScriptString(
161-
inputString,
162-
echoToConsole,
163-
true)
164-
.ConfigureAwait(false);
165-
}
166-
}
167-
168144
/// <summary>
169145
/// Executes a script file at the specified path.
170146
/// </summary>
@@ -338,11 +314,16 @@ await this.consoleReadLine.ReadCommandLine(
338314
{
339315
Console.Write(Environment.NewLine);
340316

341-
await this.powerShellContext.ExecuteScriptString(
342-
commandString,
343-
false,
344-
true,
345-
true);
317+
var unusedTask =
318+
this.powerShellContext
319+
.ExecuteScriptString(
320+
commandString,
321+
false,
322+
true,
323+
true)
324+
.ConfigureAwait(false);
325+
326+
break;
346327
}
347328
}
348329
while (!cancellationToken.IsCancellationRequested);
@@ -459,6 +440,37 @@ private void PowerShellContext_DebuggerResumed(object sender, System.Management.
459440
this.CancelReadLoop();
460441
}
461442

443+
private void PowerShellContext_ExecutionStatusChanged(object sender, ExecutionStatusChangedEventArgs eventArgs)
444+
{
445+
if (this.EnableConsoleRepl)
446+
{
447+
// Any command which writes output to the host will affect
448+
// the display of the prompt
449+
if (eventArgs.ExecutionOptions.WriteOutputToHost ||
450+
eventArgs.ExecutionOptions.InterruptCommandPrompt)
451+
{
452+
if (eventArgs.ExecutionStatus != ExecutionStatus.Running)
453+
{
454+
// Execution has completed, start the input prompt
455+
this.StartReadLoop();
456+
}
457+
else
458+
{
459+
// A new command was started, cancel the input prompt
460+
this.CancelReadLoop();
461+
}
462+
}
463+
else if (
464+
eventArgs.ExecutionOptions.WriteErrorsToHost &&
465+
(eventArgs.ExecutionStatus == ExecutionStatus.Failed ||
466+
eventArgs.HadErrors))
467+
{
468+
this.CancelReadLoop();
469+
this.StartReadLoop();
470+
}
471+
}
472+
}
473+
462474
#endregion
463475
}
464476
}
+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
//
2+
// Copyright (c) Microsoft. All rights reserved.
3+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
4+
//
5+
6+
namespace Microsoft.PowerShell.EditorServices
7+
{
8+
/// <summary>
9+
/// Defines options for the execution of a command.
10+
/// </summary>
11+
public class ExecutionOptions
12+
{
13+
#region Properties
14+
15+
/// <summary>
16+
/// Gets or sets a boolean that determines whether command output
17+
/// should be written to the host.
18+
/// </summary>
19+
public bool WriteOutputToHost { get; set; }
20+
21+
/// <summary>
22+
/// Gets or sets a boolean that determines whether command errors
23+
/// should be written to the host.
24+
/// </summary>
25+
public bool WriteErrorsToHost { get; set; }
26+
27+
/// <summary>
28+
/// Gets or sets a boolean that determines whether the executed
29+
/// command should be added to the command history.
30+
/// </summary>
31+
public bool AddToHistory { get; set; }
32+
33+
/// <summary>
34+
/// Gets or sets a boolean that determines whether the execution
35+
/// of the command should interrupt the command prompt. Should
36+
/// only be set if WriteOutputToHost is false but the command
37+
/// should still interrupt the command prompt.
38+
/// </summary>
39+
public bool InterruptCommandPrompt { get; set; }
40+
41+
#endregion
42+
43+
#region Constructors
44+
45+
/// <summary>
46+
/// Creates an instance of the ExecutionOptions class with
47+
/// default settings configured.
48+
/// </summary>
49+
public ExecutionOptions()
50+
{
51+
this.WriteOutputToHost = true;
52+
this.WriteErrorsToHost = true;
53+
this.AddToHistory = false;
54+
this.InterruptCommandPrompt = false;
55+
}
56+
57+
#endregion
58+
}
59+
}
+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
//
2+
// Copyright (c) Microsoft. All rights reserved.
3+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
4+
//
5+
6+
namespace Microsoft.PowerShell.EditorServices
7+
{
8+
/// <summary>
9+
/// Enumerates the possible execution results that can occur after
10+
/// executing a command or script.
11+
/// </summary>
12+
public enum ExecutionStatus
13+
{
14+
/// <summary>
15+
/// Indicates that execution has not yet started.
16+
/// </summary>
17+
Pending,
18+
19+
/// <summary>
20+
/// Indicates that the command is executing.
21+
/// </summary>
22+
Running,
23+
24+
/// <summary>
25+
/// Indicates that execution has failed.
26+
/// </summary>
27+
Failed,
28+
29+
/// <summary>
30+
/// Indicates that execution was aborted by the user.
31+
/// </summary>
32+
Aborted,
33+
34+
/// <summary>
35+
/// Indicates that execution completed successfully.
36+
/// </summary>
37+
Completed
38+
}
39+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
//
2+
// Copyright (c) Microsoft. All rights reserved.
3+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
4+
//
5+
6+
namespace Microsoft.PowerShell.EditorServices
7+
{
8+
/// <summary>
9+
/// Contains details about an executed
10+
/// </summary>
11+
public class ExecutionStatusChangedEventArgs
12+
{
13+
#region Properties
14+
15+
/// <summary>
16+
/// Gets the options used when the command was executed.
17+
/// </summary>
18+
public ExecutionOptions ExecutionOptions { get; private set; }
19+
20+
/// <summary>
21+
/// Gets the command execution's current status.
22+
/// </summary>
23+
public ExecutionStatus ExecutionStatus { get; private set; }
24+
25+
/// <summary>
26+
/// If true, the command execution had errors.
27+
/// </summary>
28+
public bool HadErrors { get; private set; }
29+
30+
#endregion
31+
32+
#region Constructors
33+
34+
/// <summary>
35+
/// Creates an instance of the ExecutionStatusChangedEventArgs class.
36+
/// </summary>
37+
/// <param name="executionStatus">The command execution's current status.</param>
38+
/// <param name="executionOptions">The options used when the command was executed.</param>
39+
/// <param name="hadErrors">If execution has completed, indicates whether there were errors.</param>
40+
public ExecutionStatusChangedEventArgs(
41+
ExecutionStatus executionStatus,
42+
ExecutionOptions executionOptions,
43+
bool hadErrors)
44+
{
45+
this.ExecutionStatus = executionStatus;
46+
this.ExecutionOptions = executionOptions;
47+
this.HadErrors = hadErrors || (executionStatus == ExecutionStatus.Failed);
48+
}
49+
50+
#endregion
51+
}
52+
}

0 commit comments

Comments
 (0)