Skip to content

Commit d498a45

Browse files
committed
Ensure folders are added to sourcekit-lsp in multi root workspaces
`addFolder` in the LSP client was checking to see if the folder being added was a root folder. If the user is working in a multi root workspace this meant folders may not be added, and so indexing would not occur. This also prevented the test explorer from properly initializing. Check to see if the folder being added is in the list of VS Code workspace folders, and add if it is. Issue: #1669
1 parent da07bbd commit d498a45

File tree

6 files changed

+187
-172
lines changed

6 files changed

+187
-172
lines changed

src/FolderContext.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,25 @@ export class FolderContext implements vscode.Disposable {
211211
});
212212
return target;
213213
}
214+
215+
/**
216+
* Called whenever we have new document symbols
217+
*/
218+
onDocumentSymbols(
219+
document: vscode.TextDocument,
220+
symbols: vscode.DocumentSymbol[] | null | undefined
221+
) {
222+
const uri = document?.uri;
223+
if (
224+
this.testExplorer &&
225+
symbols &&
226+
uri &&
227+
uri.scheme === "file" &&
228+
isPathInsidePath(uri.fsPath, this.folder.fsPath)
229+
) {
230+
void this.testExplorer.getDocumentTests(this, uri, symbols);
231+
}
232+
}
214233
}
215234

216235
export interface EditedPackage {

src/TestExplorer/TestExplorer.ts

Lines changed: 22 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
import * as vscode from "vscode";
1616
import { FolderContext } from "../FolderContext";
1717
import { getErrorDescription } from "../utilities/utilities";
18-
import { isPathInsidePath } from "../utilities/filesystem";
1918
import { FolderOperation, WorkspaceContext } from "../WorkspaceContext";
2019
import { TestRunProxy, TestRunner } from "./TestRunner";
2120
import { LSPTestDiscovery } from "./LSPTestDiscovery";
@@ -141,7 +140,6 @@ export class TestExplorer {
141140
if (targets.length === 0) {
142141
return;
143142
}
144-
145143
folder.addTestExplorer();
146144
// discover tests in workspace but only if disableAutoResolve is not on.
147145
// discover tests will kick off a resolve if required
@@ -196,45 +194,29 @@ export class TestExplorer {
196194
});
197195
}
198196

199-
/**
200-
* Called whenever we have new document symbols
201-
*/
202-
static onDocumentSymbols(
197+
async getDocumentTests(
203198
folder: FolderContext,
204-
document: vscode.TextDocument,
205-
symbols: vscode.DocumentSymbol[] | null | undefined
206-
) {
207-
const uri = document?.uri;
208-
const testExplorer = folder?.testExplorer;
209-
if (testExplorer && symbols && uri && uri.scheme === "file") {
210-
if (isPathInsidePath(uri.fsPath, folder.folder.fsPath)) {
211-
void folder.swiftPackage.getTarget(uri.fsPath).then(target => {
212-
if (target && target.type === "test") {
213-
testExplorer.lspTestDiscovery
214-
.getDocumentTests(folder.swiftPackage, uri)
215-
.then(tests => {
216-
TestDiscovery.updateTestsForTarget(
217-
testExplorer.controller,
218-
{ id: target.c99name, label: target.name },
219-
tests,
220-
uri
221-
);
222-
testExplorer.onTestItemsDidChangeEmitter.fire(
223-
testExplorer.controller
224-
);
225-
})
226-
// Fallback to parsing document symbols for XCTests only
227-
.catch(() => {
228-
const tests = parseTestsFromDocumentSymbols(
229-
target.name,
230-
symbols,
231-
uri
232-
);
233-
testExplorer.updateTests(testExplorer.controller, tests, uri);
234-
});
235-
}
236-
});
237-
}
199+
uri: vscode.Uri,
200+
symbols: vscode.DocumentSymbol[]
201+
): Promise<void> {
202+
const target = await folder.swiftPackage.getTarget(uri.fsPath);
203+
if (!target || target.type !== "test") {
204+
return;
205+
}
206+
207+
try {
208+
const tests = await this.lspTestDiscovery.getDocumentTests(folder.swiftPackage, uri);
209+
TestDiscovery.updateTestsForTarget(
210+
this.controller,
211+
{ id: target.c99name, label: target.name },
212+
tests,
213+
uri
214+
);
215+
this.onTestItemsDidChangeEmitter.fire(this.controller);
216+
} catch {
217+
// Fallback to parsing document symbols for XCTests only
218+
const tests = parseTestsFromDocumentSymbols(target.name, symbols, uri);
219+
this.updateTests(this.controller, tests, uri);
238220
}
239221
}
240222

src/WorkspaceContext.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ import { isValidWorkspaceFolder, searchForPackages } from "./utilities/workspace
3737
import { SwiftPluginTaskProvider } from "./tasks/SwiftPluginTaskProvider";
3838
import { SwiftTaskProvider } from "./tasks/SwiftTaskProvider";
3939
import { LLDBDebugConfigurationProvider } from "./debugger/debugAdapterFactory";
40-
import { TestExplorer } from "./TestExplorer/TestExplorer";
4140

4241
/**
4342
* Context for whole workspace. Holds array of contexts for each workspace folder
@@ -82,7 +81,7 @@ export class WorkspaceContext implements vscode.Disposable {
8281
this.buildStatus = new SwiftBuildStatus(this.statusItem);
8382
this.languageClientManager = new LanguageClientToolchainCoordinator(this, {
8483
onDocumentSymbols: (folder, document, symbols) => {
85-
TestExplorer.onDocumentSymbols(folder, document, symbols);
84+
folder.onDocumentSymbols(document, symbols);
8685
},
8786
});
8887
this.tasks = new TaskManager(this);

src/sourcekit-lsp/LanguageClientManager.ts

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ export class LanguageClientManager implements vscode.Disposable {
9797
private singleServerSupport: boolean;
9898
// used by single server support to keep a record of the project folders
9999
// that are not at the root of their workspace
100-
public subFolderWorkspaces: vscode.Uri[];
100+
public subFolderWorkspaces: FolderContext[];
101101
private namedOutputChannels: Map<string, LSPOutputChannel> = new Map();
102102
private swiftVersion: Version;
103103
private activeDocumentManager = new LSPActiveDocumentManager();
@@ -242,10 +242,10 @@ export class LanguageClientManager implements vscode.Disposable {
242242
}
243243

244244
async addFolder(folderContext: FolderContext) {
245-
if (!folderContext.isRootFolder) {
245+
if (!folderContext.isRootFolder || this.isFolderInWorkspace(folderContext.folder)) {
246246
await this.useLanguageClient(async client => {
247247
const uri = folderContext.folder;
248-
this.subFolderWorkspaces.push(folderContext.folder);
248+
this.subFolderWorkspaces.push(folderContext);
249249

250250
const workspaceFolder = {
251251
uri: client.code2ProtocolConverter.asUri(uri),
@@ -262,7 +262,9 @@ export class LanguageClientManager implements vscode.Disposable {
262262
if (!folderContext.isRootFolder) {
263263
await this.useLanguageClient(async client => {
264264
const uri = folderContext.folder;
265-
this.subFolderWorkspaces = this.subFolderWorkspaces.filter(item => item !== uri);
265+
this.subFolderWorkspaces = this.subFolderWorkspaces.filter(
266+
item => item.folder !== uri
267+
);
266268

267269
const workspaceFolder = {
268270
uri: client.code2ProtocolConverter.asUri(uri),
@@ -275,11 +277,19 @@ export class LanguageClientManager implements vscode.Disposable {
275277
}
276278
}
277279

280+
private isFolderInWorkspace(folder: vscode.Uri): boolean {
281+
return (
282+
vscode.workspace.workspaceFolders?.find(
283+
workspaceFolder => workspaceFolder.uri.fsPath === folder.fsPath
284+
) !== undefined
285+
);
286+
}
287+
278288
private async addSubFolderWorkspaces(client: LanguageClient) {
279-
for (const uri of this.subFolderWorkspaces) {
289+
for (const folderContext of this.subFolderWorkspaces) {
280290
const workspaceFolder = {
281-
uri: client.code2ProtocolConverter.asUri(uri),
282-
name: FolderContext.uriName(uri),
291+
uri: client.code2ProtocolConverter.asUri(folderContext.folder),
292+
name: FolderContext.uriName(folderContext.folder),
283293
};
284294
await client.sendNotification(DidChangeWorkspaceFoldersNotification.type, {
285295
event: { added: [workspaceFolder], removed: [] },
@@ -440,7 +450,20 @@ export class LanguageClientManager implements vscode.Disposable {
440450
this.activeDocumentManager,
441451
errorHandler,
442452
(document, symbols) => {
443-
this.options.onDocumentSymbols?.(this.folderContext, document, symbols);
453+
const documentFolderContext = [
454+
this.folderContext,
455+
...this.subFolderWorkspaces,
456+
].find(folderContext =>
457+
document.uri.fsPath.startsWith(folderContext.folder.fsPath)
458+
);
459+
if (!documentFolderContext) {
460+
this.languageClientOutputChannel?.log(
461+
"Unable to find folder for document: " + document.uri.fsPath,
462+
"WARN"
463+
);
464+
return;
465+
}
466+
this.options.onDocumentSymbols?.(documentFolderContext, document, symbols);
444467
}
445468
);
446469

test/integration-tests/ExtensionActivation.test.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,9 @@ suite("Extension Activation/Deactivation Tests", () => {
116116
assert(folder);
117117

118118
const languageClient = workspaceContext.languageClientManager.get(folder);
119-
const lspWorkspaces = languageClient.subFolderWorkspaces.map(({ fsPath }) => fsPath);
119+
const lspWorkspaces = languageClient.subFolderWorkspaces.map(
120+
({ folder }) => folder.fsPath
121+
);
120122
assertContains(lspWorkspaces, testAssetUri("cmake").fsPath);
121123
});
122124

@@ -125,7 +127,9 @@ suite("Extension Activation/Deactivation Tests", () => {
125127
assert(folder);
126128

127129
const languageClient = workspaceContext.languageClientManager.get(folder);
128-
const lspWorkspaces = languageClient.subFolderWorkspaces.map(({ fsPath }) => fsPath);
130+
const lspWorkspaces = languageClient.subFolderWorkspaces.map(
131+
({ folder }) => folder.fsPath
132+
);
129133
assertContains(lspWorkspaces, testAssetUri("cmake-compile-flags").fsPath);
130134
});
131135
});

0 commit comments

Comments
 (0)