Skip to content

Commit cef2d62

Browse files
committed
Add a workspace config-based approach to reloading discovered projects.
1 parent 2fec838 commit cef2d62

File tree

4 files changed

+54
-23
lines changed

4 files changed

+54
-23
lines changed

editors/code/src/client.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ import * as lc from "vscode-languageclient/node";
33
import * as vscode from "vscode";
44
import * as ra from "../src/lsp_ext";
55
import * as Is from "vscode-languageclient/lib/common/utils/is";
6-
import { assert } from "./util";
6+
import { assert, log } from "./util";
77
import * as diagnostics from "./diagnostics";
88
import { WorkspaceEdit } from "vscode";
9-
import { Config, substituteVSCodeVariables } from "./config";
9+
import { Config, prepareVSCodeConfig } from "./config";
1010
import { randomUUID } from "crypto";
1111

1212
export interface Env {
@@ -95,7 +95,9 @@ export async function createClient(
9595
const resp = await next(params, token);
9696
if (resp && Array.isArray(resp)) {
9797
return resp.map((val) => {
98-
return substituteVSCodeVariables(val);
98+
return prepareVSCodeConfig(val, (key, cfg) => {
99+
cfg[key] = config.discoveredWorkspaces;
100+
});
99101
});
100102
} else {
101103
return resp;

editors/code/src/commands.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -750,14 +750,20 @@ export function addProject(ctx: CtxInit): Cmd {
750750

751751
const workspaces: JsonProject[] = await Promise.all(
752752
vscode.workspace.workspaceFolders!.map(async (folder): Promise<JsonProject> => {
753-
return discoverWorkspace(vscode.workspace.textDocuments, discoverProjectCommand, {
753+
const rustDocuments = vscode.workspace.textDocuments.filter(isRustDocument);
754+
return discoverWorkspace(rustDocuments, discoverProjectCommand, {
754755
cwd: folder.uri.fsPath,
755756
});
756757
})
757758
);
758759

759-
await ctx.client.sendRequest(ra.addProject, {
760-
project: workspaces,
760+
ctx.addToDiscoveredWorkspaces(workspaces);
761+
762+
// this is a workaround to avoid needing writing the `rust-project.json` into
763+
// a workspace-level VS Code-specific settings folder. We'd like to keep the
764+
// `rust-project.json` entirely in-memory.
765+
await ctx.client?.sendNotification(lc.DidChangeConfigurationNotification.type, {
766+
settings: "",
761767
});
762768
};
763769
}

editors/code/src/config.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ export class Config {
3434

3535
constructor(ctx: vscode.ExtensionContext) {
3636
this.globalStorageUri = ctx.globalStorageUri;
37+
this.discoveredWorkspaces = [];
3738
vscode.workspace.onDidChangeConfiguration(
3839
this.onDidChangeConfiguration,
3940
this,
@@ -55,6 +56,8 @@ export class Config {
5556
log.info("Using configuration", Object.fromEntries(cfg));
5657
}
5758

59+
public discoveredWorkspaces: JsonProject[];
60+
5861
private async onDidChangeConfiguration(event: vscode.ConfigurationChangeEvent) {
5962
this.refreshLogging();
6063

@@ -191,7 +194,7 @@ export class Config {
191194
* So this getter handles this quirk by not requiring the caller to use postfix `!`
192195
*/
193196
private get<T>(path: string): T | undefined {
194-
return substituteVSCodeVariables(this.cfg.get<T>(path));
197+
return prepareVSCodeConfig(this.cfg.get<T>(path));
195198
}
196199

197200
get serverPath() {
@@ -284,18 +287,24 @@ export class Config {
284287
}
285288
}
286289

287-
export function substituteVSCodeVariables<T>(resp: T): T {
290+
export function prepareVSCodeConfig<T>(
291+
resp: T,
292+
cb?: (key: Extract<keyof T, string>, res: { [key: string]: any }) => void
293+
): T {
288294
if (Is.string(resp)) {
289295
return substituteVSCodeVariableInString(resp) as T;
290296
} else if (resp && Is.array<any>(resp)) {
291297
return resp.map((val) => {
292-
return substituteVSCodeVariables(val);
298+
return prepareVSCodeConfig(val);
293299
}) as T;
294300
} else if (resp && typeof resp === "object") {
295301
const res: { [key: string]: any } = {};
296302
for (const key in resp) {
297303
const val = resp[key];
298-
res[key] = substituteVSCodeVariables(val);
304+
res[key] = prepareVSCodeConfig(val);
305+
if (cb) {
306+
cb(key, res);
307+
}
299308
}
300309
return res as T;
301310
}

editors/code/src/ctx.ts

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import * as vscode from "vscode";
22
import * as lc from "vscode-languageclient/node";
33
import * as ra from "./lsp_ext";
44

5-
import { Config, substituteVSCodeVariables } from "./config";
5+
import { Config, prepareVSCodeConfig } from "./config";
66
import { createClient } from "./client";
77
import {
88
executeDiscoverProject,
@@ -54,7 +54,7 @@ export async function discoverWorkspace(
5454
command: string[],
5555
options: ExecOptions
5656
): Promise<JsonProject> {
57-
const paths = files.map((f) => f.uri.fsPath).join(" ");
57+
const paths = files.map((f) => `"${f.uri.fsPath}"`).join(" ");
5858
const joinedCommand = command.join(" ");
5959
const data = await executeDiscoverProject(`${joinedCommand} ${paths}`, options);
6060
return JSON.parse(data) as JsonProject;
@@ -71,7 +71,7 @@ export type CtxInit = Ctx & {
7171

7272
export class Ctx {
7373
readonly statusBar: vscode.StatusBarItem;
74-
readonly config: Config;
74+
config: Config;
7575
readonly workspace: Workspace;
7676

7777
private _client: lc.LanguageClient | undefined;
@@ -82,7 +82,6 @@ export class Ctx {
8282
private state: PersistentState;
8383
private commandFactories: Record<string, CommandFactory>;
8484
private commandDisposables: Disposable[];
85-
private discoveredWorkspaces: JsonProject[] | undefined;
8685

8786
get client() {
8887
return this._client;
@@ -193,20 +192,24 @@ export class Ctx {
193192
if (discoverProjectCommand) {
194193
const workspaces: JsonProject[] = await Promise.all(
195194
vscode.workspace.workspaceFolders!.map(async (folder): Promise<JsonProject> => {
196-
return discoverWorkspace(
197-
vscode.workspace.textDocuments,
198-
discoverProjectCommand,
199-
{ cwd: folder.uri.fsPath }
200-
);
195+
const rustDocuments = vscode.workspace.textDocuments.filter(isRustDocument);
196+
return discoverWorkspace(rustDocuments, discoverProjectCommand, {
197+
cwd: folder.uri.fsPath,
198+
});
201199
})
202200
);
203201

204-
this.discoveredWorkspaces = workspaces;
202+
this.addToDiscoveredWorkspaces(workspaces);
205203
}
206204

207-
const initializationOptions = substituteVSCodeVariables(rawInitializationOptions);
208-
// this appears to be load-bearing, for better or worse.
209-
await initializationOptions.update("linkedProjects", this.discoveredWorkspaces);
205+
const initializationOptions = prepareVSCodeConfig(
206+
rawInitializationOptions,
207+
(key, obj) => {
208+
if (key === "linkedProjects") {
209+
obj["linkedProjects"] = this.config.discoveredWorkspaces;
210+
}
211+
}
212+
);
210213

211214
this._client = await createClient(
212215
this.traceOutputChannel,
@@ -288,6 +291,17 @@ export class Ctx {
288291
return this._serverPath;
289292
}
290293

294+
addToDiscoveredWorkspaces(workspaces: JsonProject[]) {
295+
for (const workspace of workspaces) {
296+
const index = this.config.discoveredWorkspaces.indexOf(workspace);
297+
if (~index) {
298+
this.config.discoveredWorkspaces[index] = workspace;
299+
} else {
300+
this.config.discoveredWorkspaces.push(workspace);
301+
}
302+
}
303+
}
304+
291305
private updateCommands(forceDisable?: "disable") {
292306
this.commandDisposables.forEach((disposable) => disposable.dispose());
293307
this.commandDisposables = [];

0 commit comments

Comments
 (0)