Skip to content

Commit 0948131

Browse files
committed
Catch exceptions within completion handler
We'll still see the same error in the log, but as a warning and not as an exception bubbled up over LSP that causes some clients, like Kate, to crash. We can't do anything about PowerShell's completion failing.
1 parent d945e84 commit 0948131

File tree

3 files changed

+61
-17
lines changed

3 files changed

+61
-17
lines changed

Diff for: src/PowerShellEditorServices/Services/TextDocument/Handlers/CompletionHandler.cs

+19-10
Original file line numberDiff line numberDiff line change
@@ -69,16 +69,25 @@ public override async Task<CompletionList> Handle(CompletionParams request, Canc
6969
int cursorColumn = request.Position.Character + 1;
7070

7171
ScriptFile scriptFile = _workspaceService.GetFile(request.TextDocument.Uri);
72-
(bool isIncomplete, IReadOnlyList<CompletionItem> completionResults) = await GetCompletionsInFileAsync(
73-
scriptFile,
74-
cursorLine,
75-
cursorColumn,
76-
cancellationToken).ConfigureAwait(false);
77-
78-
// Treat completions trigged by space as incomplete so that `gci `
79-
// and then typing `-` doesn't just filter the list of parameter values
80-
// (typically files) returned by the space completion
81-
return new CompletionList(completionResults, isIncomplete || request?.Context?.TriggerCharacter is " ");
72+
try
73+
{
74+
(bool isIncomplete, IReadOnlyList<CompletionItem> completionResults) = await GetCompletionsInFileAsync(
75+
scriptFile,
76+
cursorLine,
77+
cursorColumn,
78+
cancellationToken).ConfigureAwait(false);
79+
80+
// Treat completions triggered by space as incomplete so that `gci `
81+
// and then typing `-` doesn't just filter the list of parameter values
82+
// (typically files) returned by the space completion
83+
return new CompletionList(completionResults, isIncomplete || request?.Context?.TriggerCharacter is " ");
84+
}
85+
// We can't do anything about completions failing.
86+
catch (Exception e)
87+
{
88+
_logger.LogWarning(e, "Exception occurred while running handling completion request");
89+
return new CompletionList(isIncomplete: true);
90+
}
8291
}
8392

8493
// Handler for "completionItem/resolve". In VSCode this is fired when a completion item is highlighted in the completion list.

Diff for: test/PowerShellEditorServices.Test.E2E/LSPTestsFixures.cs

+9-7
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,9 @@ public class LSPTestsFixture : IAsyncLifetime
3333
private const bool IsDebugAdapterTests = false;
3434

3535
public ILanguageClient PsesLanguageClient { get; private set; }
36-
public List<Diagnostic> Diagnostics { get; set; }
37-
internal List<PsesTelemetryEvent> TelemetryEvents { get; set; }
36+
public List<LogMessageParams> Messages = new();
37+
public List<Diagnostic> Diagnostics = new();
38+
internal List<PsesTelemetryEvent> TelemetryEvents = new();
3839
public ITestOutputHelper Output { get; set; }
3940

4041
protected PsesStdioProcess _psesProcess;
@@ -46,20 +47,21 @@ public async Task InitializeAsync()
4647
_psesProcess = new PsesStdioProcess(factory, IsDebugAdapterTests);
4748
await _psesProcess.Start().ConfigureAwait(false);
4849

49-
Diagnostics = new List<Diagnostic>();
50-
TelemetryEvents = new List<PsesTelemetryEvent>();
51-
DirectoryInfo testdir =
50+
DirectoryInfo testDir =
5251
Directory.CreateDirectory(Path.Combine(s_binDir, Path.GetRandomFileName()));
5352

5453
PsesLanguageClient = LanguageClient.PreInit(options =>
5554
{
5655
options
5756
.WithInput(_psesProcess.OutputStream)
5857
.WithOutput(_psesProcess.InputStream)
59-
.WithWorkspaceFolder(DocumentUri.FromFileSystemPath(testdir.FullName), "testdir")
58+
.WithWorkspaceFolder(DocumentUri.FromFileSystemPath(testDir.FullName), "testdir")
6059
.WithInitializationOptions(new { EnableProfileLoading = false })
6160
.OnPublishDiagnostics(diagnosticParams => Diagnostics.AddRange(diagnosticParams.Diagnostics.Where(d => d != null)))
62-
.OnLogMessage(logMessageParams => Output?.WriteLine($"{logMessageParams.Type}: {logMessageParams.Message}"))
61+
.OnLogMessage(logMessageParams => {
62+
Output?.WriteLine($"{logMessageParams.Type}: {logMessageParams.Message}");
63+
Messages.Add(logMessageParams);
64+
})
6365
.OnTelemetryEvent(telemetryEventParams => TelemetryEvents.Add(
6466
new PsesTelemetryEvent
6567
{

Diff for: test/PowerShellEditorServices.Test.E2E/LanguageServerProtocolMessageTests.cs

+33
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ public class LanguageServerProtocolMessageTests : IClassFixture<LSPTestsFixture>
3838
Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
3939

4040
private readonly ILanguageClient PsesLanguageClient;
41+
private readonly List<LogMessageParams> Messages;
4142
private readonly List<Diagnostic> Diagnostics;
4243
private readonly List<PsesTelemetryEvent> TelemetryEvents;
4344
private readonly string PwshExe;
@@ -46,6 +47,8 @@ public LanguageServerProtocolMessageTests(ITestOutputHelper output, LSPTestsFixt
4647
{
4748
data.Output = output;
4849
PsesLanguageClient = data.PsesLanguageClient;
50+
Messages = data.Messages;
51+
Messages.Clear();
4952
Diagnostics = data.Diagnostics;
5053
Diagnostics.Clear();
5154
TelemetryEvents = data.TelemetryEvents;
@@ -957,6 +960,36 @@ public async Task CanSendCompletionAndCompletionResolveRequestAsync()
957960
Assert.Contains("Writes customized output to a host", updatedCompletionItem.Documentation.String);
958961
}
959962

963+
// Regression test for https://github.com/PowerShell/PowerShellEditorServices/issues/1926
964+
[SkippableFact]
965+
public async Task CanRequestCompletionsAndHandleExceptions()
966+
{
967+
Skip.IfNot(VersionUtils.PSEdition == "Core", "This is a temporary bug in PowerShell 7, the fix is making its way upstream.");
968+
string filePath = NewTestFile(@"
969+
@() | ForEach-Object {
970+
if ($false) {
971+
return
972+
}
973+
974+
@{key=$}
975+
}");
976+
977+
Messages.Clear(); // On some systems there's a warning message about configuration items too.
978+
CompletionList completionItems = await PsesLanguageClient.TextDocument.RequestCompletion(
979+
new CompletionParams
980+
{
981+
TextDocument = new TextDocumentIdentifier
982+
{
983+
Uri = DocumentUri.FromFileSystemPath(filePath)
984+
},
985+
Position = new Position(line: 6, character: 11)
986+
});
987+
988+
Assert.Empty(completionItems);
989+
LogMessageParams message = Assert.Single(Messages);
990+
Assert.Contains("Exception occurred while running handling completion request", message.Message);
991+
}
992+
960993
[SkippableFact(Skip = "Completion for Expand-SlowArchive is flaky.")]
961994
public async Task CanSendCompletionResolveWithModulePrefixRequestAsync()
962995
{

0 commit comments

Comments
 (0)