]> git.lizzy.rs Git - rust.git/commitdiff
Implement StatusBar
authorAleksey Kladov <aleksey.kladov@gmail.com>
Thu, 2 Jul 2020 10:37:04 +0000 (12:37 +0200)
committerAleksey Kladov <aleksey.kladov@gmail.com>
Thu, 2 Jul 2020 13:32:14 +0000 (15:32 +0200)
crates/rust-analyzer/src/config.rs
crates/rust-analyzer/src/global_state.rs
crates/rust-analyzer/src/lsp_ext.rs
crates/rust-analyzer/src/main_loop.rs
docs/dev/lsp-extensions.md
editors/code/src/client.ts
editors/code/src/ctx.ts
editors/code/src/lsp_ext.ts

index 6c311648a9d506bb8ee358883b09f419511c1596..21acfe6445e2dc80118a1456b14146f860bf9510 100644 (file)
@@ -130,6 +130,7 @@ pub struct ClientCapsConfig {
     pub code_action_group: bool,
     pub resolve_code_action: bool,
     pub hover_actions: bool,
+    pub status_notification: bool,
 }
 
 impl Config {
@@ -365,6 +366,7 @@ pub fn update_caps(&mut self, caps: &ClientCapabilities) {
             self.client_caps.code_action_group = get_bool("codeActionGroup");
             self.client_caps.resolve_code_action = get_bool("resolveCodeAction");
             self.client_caps.hover_actions = get_bool("hoverActions");
+            self.client_caps.status_notification = get_bool("statusNotification");
         }
     }
 }
index b7b4edf6611ff3fd78ea8f19aff728fc43f2abaf..5e9cae3f842282aa7db386bb78f574948d197bb2 100644 (file)
@@ -31,6 +31,7 @@
 pub(crate) enum Status {
     Loading,
     Ready,
+    Invalid,
 }
 
 impl Default for Status {
index 82207bbb8b490594471f93ae18e8d145cd983adb..d225ad5ff3bfc673413a7c182e14b6c89e9aa217 100644 (file)
@@ -3,7 +3,7 @@
 use std::{collections::HashMap, path::PathBuf};
 
 use lsp_types::request::Request;
-use lsp_types::{Position, Range, TextDocumentIdentifier};
+use lsp_types::{notification::Notification, Position, Range, TextDocumentIdentifier};
 use serde::{Deserialize, Serialize};
 
 pub enum AnalyzerStatus {}
@@ -208,6 +208,22 @@ pub struct SsrParams {
     pub parse_only: bool,
 }
 
+pub enum StatusNotification {}
+
+#[serde(rename_all = "camelCase")]
+#[derive(Serialize, Deserialize)]
+pub enum Status {
+    Loading,
+    Ready,
+    NeedsReload,
+    Invalid,
+}
+
+impl Notification for StatusNotification {
+    type Params = Status;
+    const METHOD: &'static str = "rust-analyzer/status";
+}
+
 pub enum CodeActionRequest {}
 
 impl Request for CodeActionRequest {
index e03038b25827a5adc37b5e87c1a93710b108347f..a5a8c17a070e337ce4da1e52acbe4aa6c575fb8f 100644 (file)
@@ -169,16 +169,16 @@ fn handle_event(&mut self, event: Event) -> Result<()> {
                 }
                 vfs::loader::Message::Progress { n_total, n_done } => {
                     if n_total == 0 {
-                        self.status = Status::Ready;
+                        self.transition(Status::Invalid);
                     } else {
                         let state = if n_done == 0 {
-                            self.status = Status::Loading;
+                            self.transition(Status::Loading);
                             Progress::Begin
                         } else if n_done < n_total {
                             Progress::Report
                         } else {
                             assert_eq!(n_done, n_total);
-                            self.status = Status::Ready;
+                            self.transition(Status::Ready);
                             Progress::End
                         };
                         self.report_progress(
@@ -274,6 +274,18 @@ fn handle_event(&mut self, event: Event) -> Result<()> {
         Ok(())
     }
 
+    fn transition(&mut self, new_status: Status) {
+        self.status = Status::Ready;
+        if self.config.client_caps.status_notification {
+            let lsp_status = match new_status {
+                Status::Loading => lsp_ext::Status::Loading,
+                Status::Ready => lsp_ext::Status::Ready,
+                Status::Invalid => lsp_ext::Status::Invalid,
+            };
+            self.send_notification::<lsp_ext::StatusNotification>(lsp_status);
+        }
+    }
+
     fn on_request(&mut self, request_received: Instant, req: Request) -> Result<()> {
         self.register_request(&req, request_received);
 
index c0afb16d3b201aeca34737bf951e773590f2dac0..6d6bbac7ca1d959e54098917110f7c8132a031fc 100644 (file)
@@ -399,6 +399,18 @@ Returns internal status message, mostly for debugging purposes.
 
 Reloads project information (that is, re-executes `cargo metadata`).
 
+## Status Notification
+
+**Client Capability:** `{ "statusNotification": boolean }`
+
+**Method:** `rust-analyzer/status`
+
+**Notification:** `"loading" | "ready" | "invalid" | "needsReload"`
+
+This notification is sent from server to client.
+The client can use it to display persistent status to the user (in modline).
+For `needsReload` state, the client can provide a context-menu action to run `rust-analyzer/reloadWorkspace` request.
+
 ## Syntax Tree
 
 **Method:** `rust-analyzer/syntaxTree`
index 65ad573d8c919ec4e1577a72d60e2150cca94524..3e5915c28d4bd059a1d97680ecff6401187de5f4 100644 (file)
@@ -161,6 +161,7 @@ class ExperimentalFeatures implements lc.StaticFeature {
         caps.codeActionGroup = true;
         caps.resolveCodeAction = true;
         caps.hoverActions = true;
+        caps.statusNotification = true;
         capabilities.experimental = caps;
     }
     initialize(_capabilities: lc.ServerCapabilities<any>, _documentSelector: lc.DocumentSelector | undefined): void {
index 41df119910a4416e99ec78fffc75bdd2526eda2e..6e767babf449ea20cc6595e91b4606a7b895d34b 100644 (file)
@@ -1,9 +1,11 @@
 import * as vscode from 'vscode';
 import * as lc from 'vscode-languageclient';
+import * as ra from './lsp_ext';
 
 import { Config } from './config';
 import { createClient } from './client';
 import { isRustEditor, RustEditor } from './util';
+import { Status } from './lsp_ext';
 
 export class Ctx {
     private constructor(
@@ -11,6 +13,7 @@ export class Ctx {
         private readonly extCtx: vscode.ExtensionContext,
         readonly client: lc.LanguageClient,
         readonly serverPath: string,
+        readonly statusBar: vscode.StatusBarItem,
     ) {
 
     }
@@ -22,9 +25,18 @@ export class Ctx {
         cwd: string,
     ): Promise<Ctx> {
         const client = createClient(serverPath, cwd);
-        const res = new Ctx(config, extCtx, client, serverPath);
+
+        const statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left);
+        extCtx.subscriptions.push(statusBar);
+        statusBar.text = "rust-analyzer";
+        statusBar.tooltip = "ready";
+        statusBar.show();
+
+        const res = new Ctx(config, extCtx, client, serverPath, statusBar);
+
         res.pushCleanup(client.start());
         await client.onReady();
+        client.onNotification(ra.status, (status) => res.setStatus(status));
         return res;
     }
 
@@ -54,6 +66,35 @@ export class Ctx {
         return this.extCtx.subscriptions;
     }
 
+    setStatus(status: Status) {
+        switch (status) {
+            case "loading":
+                this.statusBar.text = "$(sync~spin) rust-analyzer";
+                this.statusBar.tooltip = "Loading the project";
+                this.statusBar.command = undefined;
+                this.statusBar.color = undefined;
+                break;
+            case "ready":
+                this.statusBar.text = "rust-analyzer";
+                this.statusBar.tooltip = "Ready";
+                this.statusBar.command = undefined;
+                this.statusBar.color = undefined;
+                break;
+            case "invalid":
+                this.statusBar.text = "$(error) rust-analyzer";
+                this.statusBar.tooltip = "Failed to load the project";
+                this.statusBar.command = undefined;
+                this.statusBar.color = new vscode.ThemeColor("notificationsErrorIcon.foreground");
+                break;
+            case "needsReload":
+                this.statusBar.text = "$(warning) rust-analyzer";
+                this.statusBar.tooltip = "Click to reload";
+                this.statusBar.command = "rust-analyzer.reloadWorkspace";
+                this.statusBar.color = new vscode.ThemeColor("notificationsWarningIcon.foreground");
+                break;
+        }
+    }
+
     pushCleanup(d: Disposable) {
         this.extCtx.subscriptions.push(d);
     }
index 981b6f40ecbeac025bec5fe0f60fe87e01506b22..bf4703239d1e21a4f7d7783cdf00eb9d6969b777 100644 (file)
@@ -6,6 +6,9 @@ import * as lc from "vscode-languageclient";
 
 export const analyzerStatus = new lc.RequestType<null, string, void>("rust-analyzer/analyzerStatus");
 
+export type Status = "loading" | "ready" | "invalid" | "needsReload";
+export const status = new lc.NotificationType<Status>("rust-analyzer/status");
+
 export const reloadWorkspace = new lc.RequestType<null, null, void>("rust-analyzer/reloadWorkspace");
 
 export interface SyntaxTreeParams {