]> git.lizzy.rs Git - rust.git/commitdiff
Re-implement status display using LSP 3.15 progress event
authorEmil Lauridsen <mine809@gmail.com>
Wed, 25 Dec 2019 18:08:44 +0000 (19:08 +0100)
committerEmil Lauridsen <mine809@gmail.com>
Wed, 25 Dec 2019 18:08:44 +0000 (19:08 +0100)
crates/ra_lsp_server/src/cargo_check.rs
crates/ra_lsp_server/src/main_loop.rs
editors/code/src/commands/watch_status.ts
editors/code/src/extension.ts

index 5a6a209eba390918b511c06db8ace57b6a5cb387..dd8c5d407af00c113c40f04c1ab56fef21eb7f74 100644 (file)
@@ -9,7 +9,8 @@
 use crossbeam_channel::{select, unbounded, Receiver, RecvError, Sender, TryRecvError};
 use lsp_types::{
     Diagnostic, DiagnosticRelatedInformation, DiagnosticSeverity, DiagnosticTag, Location,
-    NumberOrString, Position, Range, Url,
+    NumberOrString, Position, Range, Url, WorkDoneProgress, WorkDoneProgressBegin,
+    WorkDoneProgressEnd, WorkDoneProgressReport,
 };
 use parking_lot::RwLock;
 use std::{
@@ -132,6 +133,7 @@ fn add_suggested_fix_for_diagnostic(
 #[derive(Debug)]
 pub enum CheckTask {
     Update(Url),
+    Status(WorkDoneProgress),
 }
 
 pub enum CheckCommand {
@@ -204,13 +206,38 @@ fn handle_command(&mut self, cmd: CheckCommand) {
         }
     }
 
-    fn handle_message(&mut self, msg: cargo_metadata::Message, task_send: &Sender<CheckTask>) {
+    fn handle_message(&mut self, msg: CheckEvent, task_send: &Sender<CheckTask>) {
         match msg {
-            Message::CompilerArtifact(_msg) => {
-                // TODO: Status display
+            CheckEvent::Begin => {
+                task_send
+                    .send(CheckTask::Status(WorkDoneProgress::Begin(WorkDoneProgressBegin {
+                        title: "Running 'cargo check'".to_string(),
+                        cancellable: Some(false),
+                        message: None,
+                        percentage: None,
+                    })))
+                    .unwrap();
             }
 
-            Message::CompilerMessage(msg) => {
+            CheckEvent::End => {
+                task_send
+                    .send(CheckTask::Status(WorkDoneProgress::End(WorkDoneProgressEnd {
+                        message: None,
+                    })))
+                    .unwrap();
+            }
+
+            CheckEvent::Msg(Message::CompilerArtifact(msg)) => {
+                task_send
+                    .send(CheckTask::Status(WorkDoneProgress::Report(WorkDoneProgressReport {
+                        cancellable: Some(false),
+                        message: Some(msg.target.name),
+                        percentage: None,
+                    })))
+                    .unwrap();
+            }
+
+            CheckEvent::Msg(Message::CompilerMessage(msg)) => {
                 let map_result =
                     match map_rust_diagnostic_to_lsp(&msg.message, &self.workspace_root) {
                         Some(map_result) => map_result,
@@ -232,8 +259,8 @@ fn handle_message(&mut self, msg: cargo_metadata::Message, task_send: &Sender<Ch
                 task_send.send(CheckTask::Update(location.uri)).unwrap();
             }
 
-            Message::BuildScriptExecuted(_msg) => {}
-            Message::Unknown => {}
+            CheckEvent::Msg(Message::BuildScriptExecuted(_msg)) => {}
+            CheckEvent::Msg(Message::Unknown) => {}
         }
     }
 }
@@ -244,10 +271,16 @@ fn handle_message(&mut self, msg: cargo_metadata::Message, task_send: &Sender<Ch
 /// have to wrap sub-processes output handling in a thread and pass messages
 /// back over a channel.
 struct WatchThread {
-    message_recv: Receiver<cargo_metadata::Message>,
+    message_recv: Receiver<CheckEvent>,
     cancel_send: Sender<()>,
 }
 
+enum CheckEvent {
+    Begin,
+    Msg(cargo_metadata::Message),
+    End,
+}
+
 impl WatchThread {
     fn new(
         check_command: Option<&String>,
@@ -273,6 +306,7 @@ fn new(
                 .spawn()
                 .expect("couldn't launch cargo");
 
+            message_send.send(CheckEvent::Begin).unwrap();
             for message in cargo_metadata::parse_messages(command.stdout.take().unwrap()) {
                 match cancel_recv.try_recv() {
                     Ok(()) | Err(TryRecvError::Disconnected) => {
@@ -281,8 +315,9 @@ fn new(
                     Err(TryRecvError::Empty) => (),
                 }
 
-                message_send.send(message.unwrap()).unwrap();
+                message_send.send(CheckEvent::Msg(message.unwrap())).unwrap();
             }
+            message_send.send(CheckEvent::End).unwrap();
         });
         WatchThread { message_recv, cancel_send }
     }
index 1f6175699a0eb63a4ae33099d1f58d470cb3cc2a..045e4660ddd3597516a7bf905ffd5749676e23eb 100644 (file)
@@ -338,6 +338,14 @@ fn loop_turn(
                     task_sender.send(Task::Notify(not)).unwrap();
                 }
             }
+            CheckTask::Status(progress) => {
+                let params = req::ProgressParams {
+                    token: req::ProgressToken::String("rustAnalyzer/cargoWatcher".to_string()),
+                    value: req::ProgressParamsValue::WorkDone(progress),
+                };
+                let not = notification_new::<req::Progress>(params);
+                task_sender.send(Task::Notify(not)).unwrap();
+            }
         },
         Event::Msg(msg) => match msg {
             Message::Request(req) => on_request(
index 8d64394c7b696795a7164a94a9153ac305c5a060..2404c3f164df62bdac20053b8d90c4b846158c2e 100644 (file)
@@ -57,7 +57,50 @@ export class StatusDisplay implements vscode.Disposable {
         this.statusBarItem.dispose();
     }
 
+    public handleProgressNotification(params: ProgressParams) {
+        const { token, value } = params;
+        if (token !== "rustAnalyzer/cargoWatcher") {
+            return;
+        }
+
+        console.log("Got progress notification", token, value)
+        switch (value.kind) {
+            case "begin":
+                this.show();
+                break;
+
+            case "report":
+                if (value.message) {
+                    this.packageName = value.message;
+                }
+                break;
+
+            case "end":
+                this.hide();
+                break;
+        }
+    }
+
     private frame() {
         return spinnerFrames[(this.i = ++this.i % spinnerFrames.length)];
     }
 }
+
+// FIXME: Replace this once vscode-languageclient is updated to LSP 3.15
+interface ProgressParams {
+    token: string
+    value: WorkDoneProgress
+}
+
+enum WorkDoneProgressKind {
+    Begin = "begin",
+    Report = "report",
+    End = "end"
+}
+
+interface WorkDoneProgress {
+    kind: WorkDoneProgressKind,
+    message?: string
+    cancelable?: boolean
+    percentage?: string
+}
\ No newline at end of file
index 72a4d4bf255b7212ff41093a5a2a14e6b131b245..1507cb26eac48bfb208ae7595f4225ab7fea9f2d 100644 (file)
@@ -8,6 +8,7 @@ import { SyntaxTreeContentProvider } from './commands/syntaxTree';
 import * as events from './events';
 import * as notifications from './notifications';
 import { Server } from './server';
+import { StatusDisplay } from './commands/watch_status';
 
 export async function activate(context: vscode.ExtensionContext) {
     function disposeOnDeactivation(disposable: vscode.Disposable) {
@@ -83,6 +84,9 @@ export async function activate(context: vscode.ExtensionContext) {
         overrideCommand('type', commands.onEnter.handle);
     }
 
+    const watchStatus = new StatusDisplay(Server.config.cargoCheckOptions.command || 'check');
+    disposeOnDeactivation(watchStatus);
+
     // Notifications are events triggered by the language server
     const allNotifications: Iterable<[
         string,
@@ -92,6 +96,10 @@ export async function activate(context: vscode.ExtensionContext) {
             'rust-analyzer/publishDecorations',
             notifications.publishDecorations.handle,
         ],
+        [
+            '$/progress',
+            (params) => watchStatus.handleProgressNotification(params),
+        ]
     ];
     const syntaxTreeContentProvider = new SyntaxTreeContentProvider();
     const expandMacroContentProvider = new ExpandMacroContentProvider();