about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDavid Barsky <me@davidbarsky.com>2023-03-10 19:35:05 -0500
committerDavid Barsky <me@davidbarsky.com>2023-03-13 13:30:19 -0400
commit8d9bff0c74518d514d59a1638e4717f14caa1d71 (patch)
tree03af8d47e23c64e857a15784aeed2cd67975811f
parent91371494eec262d6e8966f905497ee2e3c384181 (diff)
downloadrust-8d9bff0c74518d514d59a1638e4717f14caa1d71.tar.gz
rust-8d9bff0c74518d514d59a1638e4717f14caa1d71.zip
Add a workspace config-based approach to reloading discovered projects.
-rw-r--r--editors/code/src/client.ts8
-rw-r--r--editors/code/src/commands.ts12
-rw-r--r--editors/code/src/config.ts17
-rw-r--r--editors/code/src/ctx.ts40
4 files changed, 54 insertions, 23 deletions
diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts
index 62980ca0464..9103ef2f8fd 100644
--- a/editors/code/src/client.ts
+++ b/editors/code/src/client.ts
@@ -3,10 +3,10 @@ import * as lc from "vscode-languageclient/node";
 import * as vscode from "vscode";
 import * as ra from "../src/lsp_ext";
 import * as Is from "vscode-languageclient/lib/common/utils/is";
-import { assert } from "./util";
+import { assert, log } from "./util";
 import * as diagnostics from "./diagnostics";
 import { WorkspaceEdit } from "vscode";
-import { Config, substituteVSCodeVariables } from "./config";
+import { Config, prepareVSCodeConfig } from "./config";
 import { randomUUID } from "crypto";
 
 export interface Env {
@@ -95,7 +95,9 @@ export async function createClient(
                     const resp = await next(params, token);
                     if (resp && Array.isArray(resp)) {
                         return resp.map((val) => {
-                            return substituteVSCodeVariables(val);
+                            return prepareVSCodeConfig(val, (key, cfg) => {
+                                cfg[key] = config.discoveredWorkspaces;
+                            });
                         });
                     } else {
                         return resp;
diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts
index a8ec75a78aa..8a953577e99 100644
--- a/editors/code/src/commands.ts
+++ b/editors/code/src/commands.ts
@@ -758,14 +758,20 @@ export function addProject(ctx: CtxInit): Cmd {
 
         const workspaces: JsonProject[] = await Promise.all(
             vscode.workspace.workspaceFolders!.map(async (folder): Promise<JsonProject> => {
-                return discoverWorkspace(vscode.workspace.textDocuments, discoverProjectCommand, {
+                const rustDocuments = vscode.workspace.textDocuments.filter(isRustDocument);
+                return discoverWorkspace(rustDocuments, discoverProjectCommand, {
                     cwd: folder.uri.fsPath,
                 });
             })
         );
 
-        await ctx.client.sendRequest(ra.addProject, {
-            project: workspaces,
+        ctx.addToDiscoveredWorkspaces(workspaces);
+
+        // this is a workaround to avoid needing writing the `rust-project.json` into
+        // a workspace-level VS Code-specific settings folder. We'd like to keep the
+        // `rust-project.json` entirely in-memory.
+        await ctx.client?.sendNotification(lc.DidChangeConfigurationNotification.type, {
+            settings: "",
         });
     };
 }
diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts
index 1dae603714d..75403725479 100644
--- a/editors/code/src/config.ts
+++ b/editors/code/src/config.ts
@@ -34,6 +34,7 @@ export class Config {
 
     constructor(ctx: vscode.ExtensionContext) {
         this.globalStorageUri = ctx.globalStorageUri;
+        this.discoveredWorkspaces = [];
         vscode.workspace.onDidChangeConfiguration(
             this.onDidChangeConfiguration,
             this,
@@ -55,6 +56,8 @@ export class Config {
         log.info("Using configuration", Object.fromEntries(cfg));
     }
 
+    public discoveredWorkspaces: JsonProject[];
+
     private async onDidChangeConfiguration(event: vscode.ConfigurationChangeEvent) {
         this.refreshLogging();
 
@@ -191,7 +194,7 @@ export class Config {
      * So this getter handles this quirk by not requiring the caller to use postfix `!`
      */
     private get<T>(path: string): T | undefined {
-        return substituteVSCodeVariables(this.cfg.get<T>(path));
+        return prepareVSCodeConfig(this.cfg.get<T>(path));
     }
 
     get serverPath() {
@@ -284,18 +287,24 @@ export class Config {
     }
 }
 
-export function substituteVSCodeVariables<T>(resp: T): T {
+export function prepareVSCodeConfig<T>(
+    resp: T,
+    cb?: (key: Extract<keyof T, string>, res: { [key: string]: any }) => void
+): T {
     if (Is.string(resp)) {
         return substituteVSCodeVariableInString(resp) as T;
     } else if (resp && Is.array<any>(resp)) {
         return resp.map((val) => {
-            return substituteVSCodeVariables(val);
+            return prepareVSCodeConfig(val);
         }) as T;
     } else if (resp && typeof resp === "object") {
         const res: { [key: string]: any } = {};
         for (const key in resp) {
             const val = resp[key];
-            res[key] = substituteVSCodeVariables(val);
+            res[key] = prepareVSCodeConfig(val);
+            if (cb) {
+                cb(key, res);
+            }
         }
         return res as T;
     }
diff --git a/editors/code/src/ctx.ts b/editors/code/src/ctx.ts
index 407d976bab9..ca30d239c95 100644
--- a/editors/code/src/ctx.ts
+++ b/editors/code/src/ctx.ts
@@ -2,7 +2,7 @@ import * as vscode from "vscode";
 import * as lc from "vscode-languageclient/node";
 import * as ra from "./lsp_ext";
 
-import { Config, substituteVSCodeVariables } from "./config";
+import { Config, prepareVSCodeConfig } from "./config";
 import { createClient } from "./client";
 import {
     executeDiscoverProject,
@@ -54,7 +54,7 @@ export async function discoverWorkspace(
     command: string[],
     options: ExecOptions
 ): Promise<JsonProject> {
-    const paths = files.map((f) => f.uri.fsPath).join(" ");
+    const paths = files.map((f) => `"${f.uri.fsPath}"`).join(" ");
     const joinedCommand = command.join(" ");
     const data = await executeDiscoverProject(`${joinedCommand} ${paths}`, options);
     return JSON.parse(data) as JsonProject;
@@ -71,7 +71,7 @@ export type CtxInit = Ctx & {
 
 export class Ctx {
     readonly statusBar: vscode.StatusBarItem;
-    readonly config: Config;
+    config: Config;
     readonly workspace: Workspace;
 
     private _client: lc.LanguageClient | undefined;
@@ -82,7 +82,6 @@ export class Ctx {
     private state: PersistentState;
     private commandFactories: Record<string, CommandFactory>;
     private commandDisposables: Disposable[];
-    private discoveredWorkspaces: JsonProject[] | undefined;
 
     get client() {
         return this._client;
@@ -193,20 +192,24 @@ export class Ctx {
             if (discoverProjectCommand) {
                 const workspaces: JsonProject[] = await Promise.all(
                     vscode.workspace.workspaceFolders!.map(async (folder): Promise<JsonProject> => {
-                        return discoverWorkspace(
-                            vscode.workspace.textDocuments,
-                            discoverProjectCommand,
-                            { cwd: folder.uri.fsPath }
-                        );
+                        const rustDocuments = vscode.workspace.textDocuments.filter(isRustDocument);
+                        return discoverWorkspace(rustDocuments, discoverProjectCommand, {
+                            cwd: folder.uri.fsPath,
+                        });
                     })
                 );
 
-                this.discoveredWorkspaces = workspaces;
+                this.addToDiscoveredWorkspaces(workspaces);
             }
 
-            const initializationOptions = substituteVSCodeVariables(rawInitializationOptions);
-            // this appears to be load-bearing, for better or worse.
-            await initializationOptions.update("linkedProjects", this.discoveredWorkspaces);
+            const initializationOptions = prepareVSCodeConfig(
+                rawInitializationOptions,
+                (key, obj) => {
+                    if (key === "linkedProjects") {
+                        obj["linkedProjects"] = this.config.discoveredWorkspaces;
+                    }
+                }
+            );
 
             this._client = await createClient(
                 this.traceOutputChannel,
@@ -288,6 +291,17 @@ export class Ctx {
         return this._serverPath;
     }
 
+    addToDiscoveredWorkspaces(workspaces: JsonProject[]) {
+        for (const workspace of workspaces) {
+            const index = this.config.discoveredWorkspaces.indexOf(workspace);
+            if (~index) {
+                this.config.discoveredWorkspaces[index] = workspace;
+            } else {
+                this.config.discoveredWorkspaces.push(workspace);
+            }
+        }
+    }
+
     private updateCommands(forceDisable?: "disable") {
         this.commandDisposables.forEach((disposable) => disposable.dispose());
         this.commandDisposables = [];