about summary refs log tree commit diff
path: root/editors/code/src
diff options
context:
space:
mode:
authorLukas Wirth <lukastw97@gmail.com>2022-10-17 14:53:46 +0200
committerLukas Wirth <lukastw97@gmail.com>2022-10-17 14:53:46 +0200
commit8aaafddee8ad709438a663084e6eec8f458bfd50 (patch)
treea59fcf975ca14a638de588694f0da455df203eca /editors/code/src
parent6f435977df34e722b45d787d7eadac23cf5b040e (diff)
downloadrust-8aaafddee8ad709438a663084e6eec8f458bfd50.tar.gz
rust-8aaafddee8ad709438a663084e6eec8f458bfd50.zip
Properly reload changed configs for server start
Diffstat (limited to 'editors/code/src')
-rw-r--r--editors/code/src/commands.ts4
-rw-r--r--editors/code/src/config.ts4
-rw-r--r--editors/code/src/ctx.ts58
-rw-r--r--editors/code/src/main.ts42
4 files changed, 51 insertions, 57 deletions
diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts
index cbdeb28c99f..cb088fc6c68 100644
--- a/editors/code/src/commands.ts
+++ b/editors/code/src/commands.ts
@@ -310,6 +310,10 @@ export function ssr(ctx: Ctx): Cmd {
 
 export function serverVersion(ctx: Ctx): Cmd {
     return async () => {
+        if (!ctx.serverPath) {
+            void vscode.window.showWarningMessage(`rust-analyzer server is not running`);
+            return;
+        }
         const { stdout } = spawnSync(ctx.serverPath, ["--version"], { encoding: "utf8" });
         const versionString = stdout.slice(`rust-analyzer `.length).trim();
 
diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts
index 199db6e30fc..10e243dc896 100644
--- a/editors/code/src/config.ts
+++ b/editors/code/src/config.ts
@@ -14,8 +14,6 @@ export class Config {
 
     readonly rootSection = "rust-analyzer";
     private readonly requiresWorkspaceReloadOpts = [
-        "serverPath",
-        "server",
         // FIXME: This shouldn't be here, changing this setting should reload
         // `continueCommentsOnNewline` behavior without restart
         "typing",
@@ -23,6 +21,8 @@ export class Config {
     private readonly requiresReloadOpts = [
         "cargo",
         "procMacro",
+        "serverPath",
+        "server",
         "files",
         "lens", // works as lens.*
     ]
diff --git a/editors/code/src/ctx.ts b/editors/code/src/ctx.ts
index d4f5ab3c88c..f62ccd1a652 100644
--- a/editors/code/src/ctx.ts
+++ b/editors/code/src/ctx.ts
@@ -6,6 +6,8 @@ import { Config, substituteVariablesInEnv, substituteVSCodeVariables } from "./c
 import { createClient } from "./client";
 import { isRustEditor, log, RustEditor } from "./util";
 import { ServerStatusParams } from "./lsp_ext";
+import { PersistentState } from "./persistent_state";
+import { bootstrap } from "./bootstrap";
 
 export type Workspace =
     | {
@@ -17,28 +19,18 @@ export type Workspace =
       };
 
 export class Ctx {
-    private client: lc.LanguageClient | undefined;
-    readonly config: Config;
-    serverPath: string;
     readonly statusBar: vscode.StatusBarItem;
+    readonly config: Config;
+
+    private client: lc.LanguageClient | undefined;
 
     traceOutputChannel: vscode.OutputChannel | undefined;
     outputChannel: vscode.OutputChannel | undefined;
-
-    serverOptions:
-        | {
-              run: lc.Executable;
-              debug: lc.Executable;
-          }
-        | undefined;
     workspace: Workspace;
+    state: PersistentState;
+    serverPath: string | undefined;
 
-    constructor(
-        readonly extCtx: vscode.ExtensionContext,
-        config: Config,
-        serverPath: string,
-        workspace: Workspace
-    ) {
+    constructor(readonly extCtx: vscode.ExtensionContext, workspace: Workspace) {
         this.statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left);
         extCtx.subscriptions.push(this.statusBar);
         extCtx.subscriptions.push({
@@ -50,9 +42,10 @@ export class Ctx {
         this.statusBar.tooltip = "ready";
         this.statusBar.command = "rust-analyzer.analyzerStatus";
         this.statusBar.show();
-        this.serverPath = serverPath;
-        this.config = config;
         this.workspace = workspace;
+
+        this.state = new PersistentState(extCtx.globalState);
+        this.config = new Config(extCtx);
     }
 
     clientFetcher() {
@@ -64,6 +57,7 @@ export class Ctx {
     }
 
     async getClient() {
+        // if server path changes -> dispose
         if (!this.traceOutputChannel) {
             this.traceOutputChannel = vscode.window.createOutputChannel(
                 "Rust Analyzer Language Server Trace"
@@ -72,8 +66,20 @@ export class Ctx {
         if (!this.outputChannel) {
             this.outputChannel = vscode.window.createOutputChannel("Rust Analyzer Language Server");
         }
-        if (!this.serverOptions) {
-            log.info("Creating server options client");
+
+        if (!this.client) {
+            log.info("Creating language client");
+
+            this.serverPath = await bootstrap(this.extCtx, this.config, this.state).catch((err) => {
+                let message = "bootstrap error. ";
+
+                message +=
+                    'See the logs in "OUTPUT > Rust Analyzer Client" (should open automatically). ';
+                message += 'To enable verbose logs use { "rust-analyzer.trace.extension": true }';
+
+                log.error("Bootstrap error", err);
+                throw new Error(message);
+            });
             const newEnv = substituteVariablesInEnv(
                 Object.assign({}, process.env, this.config.serverExtraEnv)
             );
@@ -81,16 +87,11 @@ export class Ctx {
                 command: this.serverPath,
                 options: { env: newEnv },
             };
-            this.serverOptions = {
+            const serverOptions = {
                 run,
                 debug: run,
             };
-        } else {
-            this.serverOptions.run.command = this.serverPath;
-            this.serverOptions.debug.command = this.serverPath;
-        }
-        if (!this.client) {
-            log.info("Creating language client");
+
             let rawInitializationOptions = vscode.workspace.getConfiguration("rust-analyzer");
 
             if (this.workspace.kind === "Detached Files") {
@@ -106,7 +107,7 @@ export class Ctx {
                 this.traceOutputChannel,
                 this.outputChannel,
                 initializationOptions,
-                this.serverOptions
+                serverOptions
             );
             this.client.onNotification(ra.serverStatus, (params) => this.setServerStatus(params));
         }
@@ -128,6 +129,7 @@ export class Ctx {
     async disposeClient() {
         log.info("Deactivating language client");
         await this.client?.dispose();
+        this.serverPath = undefined;
         this.client = undefined;
     }
 
diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts
index 4ff27e0b551..84f0a5810f9 100644
--- a/editors/code/src/main.ts
+++ b/editors/code/src/main.ts
@@ -3,12 +3,9 @@ import * as lc from "vscode-languageclient/node";
 
 import * as commands from "./commands";
 import { Ctx, Workspace } from "./ctx";
-import { log, isRustDocument } from "./util";
-import { PersistentState } from "./persistent_state";
+import { isRustDocument } from "./util";
 import { activateTaskProvider } from "./tasks";
 import { setContextValue } from "./util";
-import { bootstrap } from "./bootstrap";
-import { Config } from "./config";
 
 const RUST_PROJECT_CONTEXT_NAME = "inRustProject";
 
@@ -56,24 +53,13 @@ export async function activate(
               }
             : { kind: "Workspace Folder" };
 
-    const state = new PersistentState(context.globalState);
-    const config = new Config(context);
-
-    const serverPath = await bootstrap(context, config, state).catch((err) => {
-        let message = "bootstrap error. ";
-
-        message += 'See the logs in "OUTPUT > Rust Analyzer Client" (should open automatically). ';
-        message += 'To enable verbose logs use { "rust-analyzer.trace.extension": true }';
-
-        log.error("Bootstrap error", err);
-        throw new Error(message);
-    });
-
-    const ctx = new Ctx(context, config, serverPath, workspace);
+    const ctx = new Ctx(context, workspace);
     // VS Code doesn't show a notification when an extension fails to activate
     // so we do it ourselves.
     return await activateServer(ctx).catch((err) => {
-        void vscode.window.showErrorMessage(`Cannot activate rust-analyzer: ${err.message}`);
+        void vscode.window.showErrorMessage(
+            `Cannot activate rust-analyzer extension: ${err.message}`
+        );
         throw err;
     });
 }
@@ -83,7 +69,6 @@ async function activateServer(ctx: Ctx): Promise<RustAnalyzerExtensionApi> {
         ctx.pushExtCleanup(activateTaskProvider(ctx.config));
     }
 
-    await ctx.activate();
     await initCommonContext(ctx);
 
     if (ctx.config.typingContinueCommentsOnNewline) {
@@ -91,17 +76,19 @@ async function activateServer(ctx: Ctx): Promise<RustAnalyzerExtensionApi> {
     }
 
     vscode.workspace.onDidChangeConfiguration(
-        (_) =>
-            ctx
-                .getClient()
-                .then((it) =>
-                    it.sendNotification("workspace/didChangeConfiguration", { settings: "" })
-                )
-                .catch(log.error),
+        async (_) => {
+            await ctx
+                .clientFetcher()
+                .client?.sendNotification("workspace/didChangeConfiguration", { settings: "" });
+        },
         null,
         ctx.subscriptions
     );
 
+    await ctx.activate().catch((err) => {
+        void vscode.window.showErrorMessage(`Cannot activate rust-analyzer server: ${err.message}`);
+    });
+
     return ctx.clientFetcher();
 }
 
@@ -130,6 +117,7 @@ async function initCommonContext(ctx: Ctx) {
     // Commands which invokes manually via command palette, shortcut, etc.
     ctx.registerCommand("reload", (_) => async () => {
         void vscode.window.showInformationMessage("Reloading rust-analyzer...");
+        // FIXME: We should re-use the client, that is ctx.deactivate() if none of the configs have changed
         await ctx.disposeClient();
         await ctx.activate();
     });