Skip to content

Commit d012c04

Browse files
committed
receive diagnostics and display them
1 parent 8e58fa8 commit d012c04

File tree

3 files changed

+91
-5
lines changed

3 files changed

+91
-5
lines changed

src/lsptoolshost/roslynLanguageServer.ts

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import {
2626
SocketMessageReader,
2727
MessageTransports,
2828
RAL,
29+
CancellationToken,
2930
} from 'vscode-languageclient/node';
3031
import { PlatformInformation } from '../shared/platform';
3132
import { readConfigurations } from './configurationMiddleware';
@@ -93,6 +94,13 @@ export class RoslynLanguageServer {
9394
/** The project files previously opened; we hold onto this for the same reason as _solutionFile. */
9495
private _projectFiles: vscode.Uri[] = new Array<vscode.Uri>();
9596

97+
/** The diagnostic results from build displayed by VS Code. When live diagnostics are available for a file, these are errors that only build knows about.
98+
* When live diagnostics aren't loaded for a file, then these are all of the diagnostics reported by the build.*/
99+
private _diagnosticsReportedByBuild: vscode.DiagnosticCollection;
100+
101+
/** All the build results sent by the DevKit extension. */
102+
private _allBuildDiagnostics: Array<[vscode.Uri, vscode.Diagnostic[]]> = [];
103+
96104
constructor(
97105
private _languageClient: RoslynLanguageClient,
98106
private _platformInfo: PlatformInformation,
@@ -107,6 +115,9 @@ export class RoslynLanguageServer {
107115
this.registerExtensionsChanged();
108116
this.registerTelemetryChanged();
109117

118+
this._diagnosticsReportedByBuild = vscode.languages.createDiagnosticCollection('csharp-build');
119+
this.addDiagnostics();
120+
110121
// Register Razor dynamic file info handling
111122
this.registerDynamicFileInfo();
112123

@@ -568,7 +579,7 @@ export class RoslynLanguageServer {
568579
});
569580
});
570581

571-
// The server process will create the named pipe used for communcation. Wait for it to be created,
582+
// The server process will create the named pipe used for communication. Wait for it to be created,
572583
// and listen for the server to pass back the connection information via stdout.
573584
const namedPipeConnectionPromise = new Promise<NamedPipeInformation>((resolve) => {
574585
_channel.appendLine('waiting for named pipe information from server...');
@@ -694,6 +705,70 @@ export class RoslynLanguageServer {
694705
);
695706
}
696707

708+
private addDiagnostics() {
709+
this._languageClient.addDisposable(
710+
vscode.workspace.onDidOpenTextDocument(async (event) => this._onFileOpened(event))
711+
);
712+
}
713+
714+
public clearDiagnostics() {
715+
this._diagnosticsReportedByBuild.clear();
716+
}
717+
718+
public async setBuildDiagnostics(buildDiagnostics: Array<[vscode.Uri, vscode.Diagnostic[]]>) {
719+
this._allBuildDiagnostics = buildDiagnostics;
720+
const buildOnlyIds = await this.getBuildOnlyDiagnosticIds(CancellationToken.None);
721+
const displayedBuildDiagnostics = new Array<[vscode.Uri, vscode.Diagnostic[]]>();
722+
723+
this._allBuildDiagnostics.forEach((fileDiagnostics) => {
724+
const uri = fileDiagnostics[0];
725+
const diagnosticList = fileDiagnostics[1];
726+
727+
// Check if we have live diagnostics shown for this document
728+
const liveDiagnostics = vscode.languages.getDiagnostics(uri);
729+
if (liveDiagnostics && liveDiagnostics.length > 0) {
730+
// Show the build-only diagnostics
731+
displayedBuildDiagnostics.push([uri, this._getBuildOnlyDiagnostics(diagnosticList, buildOnlyIds)]);
732+
} else {
733+
// Document isn't shown in live diagnostics, so display everything reported by the build
734+
displayedBuildDiagnostics.push(fileDiagnostics);
735+
}
736+
});
737+
738+
this._diagnosticsReportedByBuild.set(displayedBuildDiagnostics);
739+
}
740+
741+
private compareUri(a: vscode.Uri, b: vscode.Uri): boolean {
742+
return a.path.localeCompare(b.path, undefined, { sensitivity: 'accent' }) === 0;
743+
}
744+
745+
private async _onFileOpened(document: vscode.TextDocument) {
746+
const uri = document.uri;
747+
const buildIds = await this.getBuildOnlyDiagnosticIds(CancellationToken.None);
748+
const currentFileBuildDiagnostics = this._allBuildDiagnostics.find(([u]) => this.compareUri(u, uri));
749+
750+
// The document is now open in the editor and live diagnostics are being shown. Filter diagnostics
751+
// reported by the build to show build-only problems.
752+
if (currentFileBuildDiagnostics) {
753+
const buildDiagnostics = this._getBuildOnlyDiagnostics(currentFileBuildDiagnostics[1], buildIds);
754+
this._diagnosticsReportedByBuild.set(uri, buildDiagnostics);
755+
}
756+
}
757+
758+
private _getBuildOnlyDiagnostics(diagnosticList: vscode.Diagnostic[], buildOnlyIds: string[]): vscode.Diagnostic[] {
759+
const buildOnlyDiagnostics: vscode.Diagnostic[] = [];
760+
diagnosticList.forEach((d) => {
761+
if (d.code) {
762+
// Include diagnostic in the list if it is build
763+
if (buildOnlyIds.find((b_id) => b_id === d.code)) {
764+
buildOnlyDiagnostics.push(d);
765+
}
766+
}
767+
});
768+
769+
return buildOnlyDiagnostics;
770+
}
771+
697772
private registerExtensionsChanged() {
698773
// subscribe to extension change events so that we can get notified if C# Dev Kit is added/removed later.
699774
this._languageClient.addDisposable(

src/lsptoolshost/services/buildResultReporterService.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,30 @@
22
* Copyright (c) Microsoft Corporation. All rights reserved.
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
5-
import { CancellationToken } from 'vscode';
5+
import { CancellationToken, Diagnostic, Uri } from 'vscode';
6+
import { RoslynLanguageServer } from '../roslynLanguageServer';
67

78
interface IBuildResultDiagnostics {
89
buildStarted(cancellationToken?: CancellationToken): Promise<void>;
9-
reportBuildResult(buildDiagnostics: RegExpExecArray[], cancellationToken?: CancellationToken): Promise<void>;
10+
reportBuildResult(
11+
buildDiagnostics: Array<[Uri, Diagnostic[]]>,
12+
cancellationToken?: CancellationToken
13+
): Promise<void>;
1014
}
1115

1216
export class BuildResultDiagnostics implements IBuildResultDiagnostics {
17+
constructor(private _languageServerPromise: Promise<RoslynLanguageServer>) {}
18+
1319
public async buildStarted(): Promise<void> {
1420
console.log('build started');
21+
const langServer = await this._languageServerPromise;
22+
langServer.clearDiagnostics();
1523
}
1624

17-
public async reportBuildResult(buildDiagnostics: RegExpExecArray[]): Promise<void> {
25+
public async reportBuildResult(buildDiagnostics: Array<[Uri, Diagnostic[]]>): Promise<void> {
1826
console.log('received ' + buildDiagnostics.length + ' diagnostics');
27+
28+
const langServer = await this._languageServerPromise;
29+
langServer.setBuildDiagnostics(buildDiagnostics);
1930
}
2031
}

src/main.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -431,7 +431,7 @@ function profferBrokeredServices(
431431
),
432432
serviceContainer.profferServiceFactory(
433433
Descriptors.csharpExtensionBuildResultService,
434-
(_mk, _op, _sb) => new BuildResultDiagnostics()
434+
(_mk, _op, _sb) => new BuildResultDiagnostics(languageServerPromise)
435435
)
436436
);
437437
}

0 commit comments

Comments
 (0)