From 178c23f50549298aad0dc0f098f8ed510a57f9d6 Mon Sep 17 00:00:00 2001 From: Emil Lauridsen Date: Wed, 25 Dec 2019 19:08:44 +0100 Subject: [PATCH] Re-implement status display using LSP 3.15 progress event --- crates/ra_lsp_server/src/cargo_check.rs | 53 +++++++++++++++++++---- crates/ra_lsp_server/src/main_loop.rs | 8 ++++ editors/code/src/commands/watch_status.ts | 43 ++++++++++++++++++ editors/code/src/extension.ts | 8 ++++ 4 files changed, 103 insertions(+), 9 deletions(-) diff --git a/crates/ra_lsp_server/src/cargo_check.rs b/crates/ra_lsp_server/src/cargo_check.rs index 5a6a209eba..dd8c5d407a 100644 --- a/crates/ra_lsp_server/src/cargo_check.rs +++ b/crates/ra_lsp_server/src/cargo_check.rs @@ -9,7 +9,8 @@ use cargo_metadata::{ 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 @@ impl CheckWatcherSharedState { #[derive(Debug)] pub enum CheckTask { Update(Url), + Status(WorkDoneProgress), } pub enum CheckCommand { @@ -204,13 +206,38 @@ impl CheckWatcherState { } } - fn handle_message(&mut self, msg: cargo_metadata::Message, task_send: &Sender) { + fn handle_message(&mut self, msg: CheckEvent, task_send: &Sender) { 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 @@ impl CheckWatcherState { 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 @@ impl CheckWatcherState { /// have to wrap sub-processes output handling in a thread and pass messages /// back over a channel. struct WatchThread { - message_recv: Receiver, + message_recv: Receiver, cancel_send: Sender<()>, } +enum CheckEvent { + Begin, + Msg(cargo_metadata::Message), + End, +} + impl WatchThread { fn new( check_command: Option<&String>, @@ -273,6 +306,7 @@ impl WatchThread { .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 @@ impl WatchThread { 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 } } diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs index 1f6175699a..045e4660dd 100644 --- a/crates/ra_lsp_server/src/main_loop.rs +++ b/crates/ra_lsp_server/src/main_loop.rs @@ -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::(params); + task_sender.send(Task::Notify(not)).unwrap(); + } }, Event::Msg(msg) => match msg { Message::Request(req) => on_request( diff --git a/editors/code/src/commands/watch_status.ts b/editors/code/src/commands/watch_status.ts index 8d64394c7b..2404c3f164 100644 --- a/editors/code/src/commands/watch_status.ts +++ b/editors/code/src/commands/watch_status.ts @@ -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 diff --git a/editors/code/src/extension.ts b/editors/code/src/extension.ts index 72a4d4bf25..1507cb26ea 100644 --- a/editors/code/src/extension.ts +++ b/editors/code/src/extension.ts @@ -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();