]> git.lizzy.rs Git - rust.git/blob - editors/code/src/ctx.ts
More robust status notifications
[rust.git] / editors / code / src / ctx.ts
1 import * as vscode from 'vscode';
2 import * as lc from 'vscode-languageclient/node';
3 import * as ra from './lsp_ext';
4
5 import { Config } from './config';
6 import { createClient } from './client';
7 import { isRustEditor, RustEditor } from './util';
8 import { ServerStatusParams } from './lsp_ext';
9
10 export class Ctx {
11     private constructor(
12         readonly config: Config,
13         private readonly extCtx: vscode.ExtensionContext,
14         readonly client: lc.LanguageClient,
15         readonly serverPath: string,
16         readonly statusBar: vscode.StatusBarItem,
17     ) {
18
19     }
20
21     static async create(
22         config: Config,
23         extCtx: vscode.ExtensionContext,
24         serverPath: string,
25         cwd: string,
26     ): Promise<Ctx> {
27         const client = createClient(serverPath, cwd, config.serverExtraEnv);
28
29         const statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left);
30         extCtx.subscriptions.push(statusBar);
31         statusBar.text = "rust-analyzer";
32         statusBar.tooltip = "ready";
33         statusBar.show();
34
35         const res = new Ctx(config, extCtx, client, serverPath, statusBar);
36
37         res.pushCleanup(client.start());
38         await client.onReady();
39         client.onNotification(ra.serverStatus, (params) => res.setServerStatus(params));
40         return res;
41     }
42
43     get activeRustEditor(): RustEditor | undefined {
44         const editor = vscode.window.activeTextEditor;
45         return editor && isRustEditor(editor)
46             ? editor
47             : undefined;
48     }
49
50     get visibleRustEditors(): RustEditor[] {
51         return vscode.window.visibleTextEditors.filter(isRustEditor);
52     }
53
54     registerCommand(name: string, factory: (ctx: Ctx) => Cmd) {
55         const fullName = `rust-analyzer.${name}`;
56         const cmd = factory(this);
57         const d = vscode.commands.registerCommand(fullName, cmd);
58         this.pushCleanup(d);
59     }
60
61     get globalState(): vscode.Memento {
62         return this.extCtx.globalState;
63     }
64
65     get subscriptions(): Disposable[] {
66         return this.extCtx.subscriptions;
67     }
68
69     setServerStatus(status: ServerStatusParams) {
70         this.statusBar.tooltip = status.message ?? "Ready";
71         let icon = "";
72         switch (status.health) {
73             case "ok":
74                 this.statusBar.color = undefined;
75                 break;
76             case "warning":
77                 this.statusBar.tooltip += "\nClick to reload."
78                 this.statusBar.command = "rust-analyzer.reloadWorkspace";
79                 this.statusBar.color = new vscode.ThemeColor("notificationsWarningIcon.foreground");
80                 icon = "$(warning) ";
81                 break;
82             case "error":
83                 this.statusBar.tooltip += "\nClick to reload."
84                 this.statusBar.command = "rust-analyzer.reloadWorkspace";
85                 this.statusBar.color = new vscode.ThemeColor("notificationsErrorIcon.foreground");
86                 icon = "$(error) ";
87                 break;
88         }
89         if (!status.quiescent) icon = "$(sync~spin) ";
90         this.statusBar.text = `${icon} rust-analyzer`;
91     }
92
93     pushCleanup(d: Disposable) {
94         this.extCtx.subscriptions.push(d);
95     }
96 }
97
98 export interface Disposable {
99     dispose(): void;
100 }
101 export type Cmd = (...args: any[]) => unknown;