Skip to content

Commit 552fb4b

Browse files
committed
Capture sourcekit-lsp diagnostics
1 parent 3453dd0 commit 552fb4b

File tree

4 files changed

+108
-44
lines changed

4 files changed

+108
-44
lines changed

src/commands/captureDiagnostics.ts

Lines changed: 42 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -26,21 +26,12 @@ export async function captureDiagnostics(ctx: WorkspaceContext) {
2626
`vscode-diagnostics-${formatDateString(new Date())}`
2727
);
2828

29-
const environmentOutputChannel = new SwiftOutputChannel();
30-
ctx.toolchain.logDiagnostics(environmentOutputChannel);
31-
environmentOutputChannel.log(
32-
JSON.stringify(vscode.workspace.getConfiguration("swift"), null, 2)
33-
);
34-
35-
const logs = ctx.outputChannel.logs.join("\n");
36-
const environmentLogs = environmentOutputChannel.logs.join("\n");
37-
const diagnosticLogs = buildDiagnostics();
38-
3929
try {
4030
await fs.mkdir(diagnosticsDir);
41-
await fs.writeFile(path.join(diagnosticsDir, "logs.txt"), logs);
42-
await fs.writeFile(path.join(diagnosticsDir, "environment.txt"), environmentLogs);
43-
await fs.writeFile(path.join(diagnosticsDir, "diagnostics.txt"), diagnosticLogs);
31+
await writeLogFile(diagnosticsDir, "logs.txt", extensionLogs(ctx));
32+
await writeLogFile(diagnosticsDir, "environment.txt", environmentLogs(ctx));
33+
await writeLogFile(diagnosticsDir, "sourcekit-lsp.txt", sourceKitLogs(ctx));
34+
await writeLogFile(diagnosticsDir, "diagnostics.txt", diagnosticLogs());
4435

4536
ctx.outputChannel.log(`Saved diagnostics to ${diagnosticsDir}`);
4637

@@ -68,6 +59,44 @@ export async function captureDiagnostics(ctx: WorkspaceContext) {
6859
}
6960
}
7061

62+
async function writeLogFile(dir: string, name: string, logs: string) {
63+
if (logs.length === 0) {
64+
return;
65+
}
66+
await fs.writeFile(path.join(dir, name), logs);
67+
}
68+
69+
function extensionLogs(ctx: WorkspaceContext): string {
70+
return ctx.outputChannel.logs.join("\n");
71+
}
72+
73+
function environmentLogs(ctx: WorkspaceContext): string {
74+
const environmentOutputChannel = new SwiftOutputChannel("Swift");
75+
ctx.toolchain.logDiagnostics(environmentOutputChannel);
76+
environmentOutputChannel.log("Extension Settings:");
77+
environmentOutputChannel.log(
78+
JSON.stringify(vscode.workspace.getConfiguration("swift"), null, 2)
79+
);
80+
return environmentOutputChannel.logs.join("\n");
81+
}
82+
83+
function diagnosticLogs(): string {
84+
const diagnosticToString = (diagnostic: vscode.Diagnostic) => {
85+
return `${severityToString(diagnostic.severity)} - ${diagnostic.message} [Ln ${diagnostic.range.start.line}, Col ${diagnostic.range.start.character}]`;
86+
};
87+
88+
return vscode.languages
89+
.getDiagnostics()
90+
.map(
91+
([uri, diagnostics]) => `${uri}\n\t${diagnostics.map(diagnosticToString).join("\n\t")}`
92+
)
93+
.join("\n");
94+
}
95+
96+
function sourceKitLogs(ctx: WorkspaceContext) {
97+
return (ctx.languageClientManager.languageClientOutputChannel?.logs ?? []).join("\n");
98+
}
99+
71100
function showDirectoryCommand(dir: string): string {
72101
switch (process.platform) {
73102
case "win32":
@@ -90,19 +119,6 @@ function showCommandType(): string {
90119
}
91120
}
92121

93-
function buildDiagnostics(): string {
94-
const diagnosticToString = (diagnostic: vscode.Diagnostic) => {
95-
return `${severityToString(diagnostic.severity)} - ${diagnostic.message} [Ln ${diagnostic.range.start.line}, Col ${diagnostic.range.start.character}]`;
96-
};
97-
98-
return vscode.languages
99-
.getDiagnostics()
100-
.map(
101-
([uri, diagnostics]) => `${uri}\n\t${diagnostics.map(diagnosticToString).join("\n\t")}`
102-
)
103-
.join("\n");
104-
}
105-
106122
function severityToString(severity: vscode.DiagnosticSeverity): string {
107123
switch (severity) {
108124
case vscode.DiagnosticSeverity.Error:

src/extension.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ export async function activate(context: vscode.ExtensionContext): Promise<Api |
5050
try {
5151
console.debug("Activating Swift for Visual Studio Code...");
5252

53-
const outputChannel = new SwiftOutputChannel();
53+
const outputChannel = new SwiftOutputChannel("Swift");
5454
const toolchain: SwiftToolchain | undefined = await SwiftToolchain.create()
5555
.then(toolchain => {
5656
toolchain.logDiagnostics(outputChannel);

src/sourcekit-lsp/LanguageClientManager.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import { FolderContext } from "../FolderContext";
2424
import { LanguageClient } from "vscode-languageclient/node";
2525
import { ArgumentFilter, BuildFlags } from "../toolchain/BuildFlags";
2626
import { DiagnosticsManager } from "../DiagnosticsManager";
27+
import { SwiftOutputChannel } from "../ui/SwiftOutputChannel";
2728

2829
/** Manages the creation and destruction of Language clients as we move between
2930
* workspace folders
@@ -96,7 +97,6 @@ export class LanguageClientManager {
9697
* null means in the process of restarting
9798
*/
9899
private languageClient: langclient.LanguageClient | null | undefined;
99-
private initializeResult?: langclient.InitializeResult;
100100
private cancellationToken?: vscode.CancellationTokenSource;
101101
private legacyInlayHints?: vscode.Disposable;
102102
private restartedPromise?: Promise<void>;
@@ -238,6 +238,10 @@ export class LanguageClientManager {
238238
await this.setLanguageClientFolder(this.currentWorkspaceFolder, true);
239239
}
240240

241+
get languageClientOutputChannel(): SwiftOutputChannel | undefined {
242+
return this.languageClient?.outputChannel as SwiftOutputChannel | undefined;
243+
}
244+
241245
private async addFolder(folderContext: FolderContext) {
242246
if (!folderContext.isRootFolder) {
243247
this.useLanguageClient(async client => {
@@ -439,6 +443,7 @@ export class LanguageClientManager {
439443
documentSelector: LanguageClientManager.documentSelector,
440444
revealOutputChannelOn: langclient.RevealOutputChannelOn.Never,
441445
workspaceFolder: workspaceFolder,
446+
outputChannel: new SwiftOutputChannel("SourceKit Language Server"),
442447
middleware: {
443448
provideDocumentSymbols: async (document, token, next) => {
444449
const result = await next(document, token);
@@ -534,7 +539,6 @@ export class LanguageClientManager {
534539
if (this.workspaceContext.swiftVersion.isLessThan(new Version(5, 7, 0))) {
535540
this.legacyInlayHints = activateLegacyInlayHints(client);
536541
}
537-
this.initializeResult = client.initializeResult;
538542
})
539543
.catch(reason => {
540544
this.workspaceContext.outputChannel.log(`${reason}`);

src/ui/SwiftOutputChannel.ts

Lines changed: 59 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,54 @@
1515
import * as vscode from "vscode";
1616
import configuration from "../configuration";
1717

18-
export class SwiftOutputChannel {
18+
export class SwiftOutputChannel implements vscode.OutputChannel {
1919
private channel: vscode.OutputChannel;
2020
private logStore = new RollingLog(1024 * 1024 * 5);
2121

22-
constructor() {
23-
this.channel = vscode.window.createOutputChannel("Swift");
22+
public name: string;
23+
24+
/**
25+
* Creates a vscode.OutputChannel that allows for later retrival of logs.
26+
* @param name
27+
*/
28+
constructor(name: string) {
29+
this.name = name;
30+
this.channel = vscode.window.createOutputChannel(name);
31+
}
32+
33+
append(value: string): void {
34+
this.channel.append(value);
35+
this.logStore.append(value);
36+
37+
if (process.env["CI"] !== "1") {
38+
console.log(value);
39+
}
40+
}
41+
42+
appendLine(value: string): void {
43+
this.channel.appendLine(value);
44+
this.logStore.appendLine(value);
45+
46+
if (process.env["CI"] !== "1") {
47+
console.log(value);
48+
}
49+
}
50+
51+
replace(value: string): void {
52+
this.channel.replace(value);
53+
this.logStore.replace(value);
54+
}
55+
56+
clear(): void {
57+
this.channel.clear();
58+
}
59+
60+
show(column?: unknown, preserveFocus?: boolean | undefined): void {
61+
this.channel.show(preserveFocus);
62+
}
63+
64+
hide(): void {
65+
this.channel.hide();
2466
}
2567

2668
dispose() {
@@ -34,7 +76,7 @@ export class SwiftOutputChannel {
3476
} else {
3577
fullMessage = message;
3678
}
37-
this.sendLog(`${this.nowFormatted}: ${fullMessage}`);
79+
this.appendLine(`${this.nowFormatted}: ${fullMessage}`);
3880
}
3981

4082
logDiagnostic(message: string, label?: string) {
@@ -47,16 +89,7 @@ export class SwiftOutputChannel {
4789
} else {
4890
fullMessage = message;
4991
}
50-
this.sendLog(`${this.nowFormatted}: ${fullMessage}`);
51-
}
52-
53-
private sendLog(line: string) {
54-
this.channel.appendLine(line);
55-
this.logStore.append(line);
56-
57-
if (process.env["CI"] !== "1") {
58-
console.log(line);
59-
}
92+
this.appendLine(`${this.nowFormatted}: ${fullMessage}`);
6093
}
6194

6295
get nowFormatted(): string {
@@ -83,7 +116,7 @@ class RollingLog {
83116
return [...this._logs];
84117
}
85118

86-
append(log: string) {
119+
appendLine(log: string) {
87120
// It can be costly to calculate the actual memory size of a string in Node so just
88121
// use the total number of characters in the logs as a huristic for total size.
89122
const logSize = log.length;
@@ -99,4 +132,15 @@ class RollingLog {
99132

100133
this.currentLogLength += logSize;
101134
}
135+
136+
append(log: string) {
137+
const line = this._logs.pop();
138+
this.currentLogLength -= line?.length ?? 0;
139+
this.appendLine((line ?? "") + log);
140+
}
141+
142+
replace(log: string) {
143+
this._logs = [log];
144+
this.currentLogLength = log.length;
145+
}
102146
}

0 commit comments

Comments
 (0)