Skip to content

Commit bc99890

Browse files
committed
Fix bug where error in prompt function crashed REPL loop
Double-whammy fix by both setting `ThrowOnError` to false, and catching a more generic PowerShell `RuntimeException`. Plus a regression test!
1 parent c6b7b91 commit bc99890

File tree

2 files changed

+29
-7
lines changed

2 files changed

+29
-7
lines changed

Diff for: src/PowerShellEditorServices/Services/PowerShell/Host/PsesInternalHost.cs

+8-4
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ namespace Microsoft.PowerShell.EditorServices.Services.PowerShell.Host
3131

3232
internal class PsesInternalHost : PSHost, IHostSupportsInteractiveSession, IRunspaceContext, IInternalPowerShellExecutionService
3333
{
34-
private const string DefaultPrompt = "> ";
34+
internal const string DefaultPrompt = "> ";
3535

3636
private static readonly PropertyInfo s_scriptDebuggerTriggerObjectProperty;
3737

@@ -865,21 +865,25 @@ private void DoOneRepl(CancellationToken cancellationToken)
865865
}
866866
}
867867

868-
private string GetPrompt(CancellationToken cancellationToken)
868+
internal string GetPrompt(CancellationToken cancellationToken)
869869
{
870870
Runspace.ThrowCancelledIfUnusable();
871871
string prompt = DefaultPrompt;
872872
try
873873
{
874874
// TODO: Should we cache PSCommands like this as static members?
875875
PSCommand command = new PSCommand().AddCommand("prompt");
876-
IReadOnlyList<string> results = InvokePSCommand<string>(command, executionOptions: null, cancellationToken);
876+
IReadOnlyList<string> results = InvokePSCommand<string>(
877+
command,
878+
executionOptions: new PowerShellExecutionOptions { ThrowOnError = false },
879+
cancellationToken);
880+
877881
if (results?.Count > 0)
878882
{
879883
prompt = results[0];
880884
}
881885
}
882-
catch (CommandNotFoundException) { } // Use default prompt
886+
catch (RuntimeException) { } // Use default prompt
883887

884888
if (CurrentRunspace.RunspaceOrigin != RunspaceOrigin.Local)
885889
{

Diff for: test/PowerShellEditorServices.Test/Session/PsesInternalHostTests.cs

+21-3
Original file line numberDiff line numberDiff line change
@@ -162,12 +162,30 @@ await psesHost.ExecuteDelegateAsync(
162162
CancellationToken.None).ConfigureAwait(true);
163163
}
164164

165+
// NOTE: Tests where we call functions that use PowerShell runspaces are slightly more
166+
// complicated than one would expect because we explicitly need the methods to run on the
167+
// pipeline thread, otherwise Windows complains about the the thread's apartment state not
168+
// matching. Hence we use a delegate where it looks like we could just call the method.
169+
170+
[Fact]
171+
public async Task CanHandleBrokenPrompt()
172+
{
173+
await psesHost.ExecutePSCommandAsync(
174+
new PSCommand().AddScript("function prompt { throw }"),
175+
CancellationToken.None).ConfigureAwait(true);
176+
177+
string prompt = await psesHost.ExecuteDelegateAsync(
178+
nameof(psesHost.GetPrompt),
179+
executionOptions: null,
180+
(_, _) => psesHost.GetPrompt(CancellationToken.None),
181+
CancellationToken.None).ConfigureAwait(true);
182+
183+
Assert.Equal(PsesInternalHost.DefaultPrompt, prompt);
184+
}
185+
165186
[Fact]
166187
public async Task CanLoadPSReadLine()
167188
{
168-
// NOTE: This is slightly more complicated than one would expect because we explicitly
169-
// need it to run on the pipeline thread otherwise Windows complains about the the
170-
// thread's apartment state not matching.
171189
Assert.True(await psesHost.ExecuteDelegateAsync(
172190
nameof(psesHost.TryLoadPSReadLine),
173191
executionOptions: null,

0 commit comments

Comments
 (0)