Re-implement status display using LSP 3.15 progress event

This commit is contained in:
Emil Lauridsen 2019-12-25 19:08:44 +01:00
parent 500fe46e6c
commit 178c23f505
4 changed files with 103 additions and 9 deletions

View file

@ -9,7 +9,8 @@ use cargo_metadata::{
use crossbeam_channel::{select, unbounded, Receiver, RecvError, Sender, TryRecvError}; use crossbeam_channel::{select, unbounded, Receiver, RecvError, Sender, TryRecvError};
use lsp_types::{ use lsp_types::{
Diagnostic, DiagnosticRelatedInformation, DiagnosticSeverity, DiagnosticTag, Location, Diagnostic, DiagnosticRelatedInformation, DiagnosticSeverity, DiagnosticTag, Location,
NumberOrString, Position, Range, Url, NumberOrString, Position, Range, Url, WorkDoneProgress, WorkDoneProgressBegin,
WorkDoneProgressEnd, WorkDoneProgressReport,
}; };
use parking_lot::RwLock; use parking_lot::RwLock;
use std::{ use std::{
@ -132,6 +133,7 @@ impl CheckWatcherSharedState {
#[derive(Debug)] #[derive(Debug)]
pub enum CheckTask { pub enum CheckTask {
Update(Url), Update(Url),
Status(WorkDoneProgress),
} }
pub enum CheckCommand { pub enum CheckCommand {
@ -204,13 +206,38 @@ impl CheckWatcherState {
} }
} }
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 { match msg {
Message::CompilerArtifact(_msg) => { CheckEvent::Begin => {
// TODO: Status display 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 = let map_result =
match map_rust_diagnostic_to_lsp(&msg.message, &self.workspace_root) { match map_rust_diagnostic_to_lsp(&msg.message, &self.workspace_root) {
Some(map_result) => map_result, Some(map_result) => map_result,
@ -232,8 +259,8 @@ impl CheckWatcherState {
task_send.send(CheckTask::Update(location.uri)).unwrap(); task_send.send(CheckTask::Update(location.uri)).unwrap();
} }
Message::BuildScriptExecuted(_msg) => {} CheckEvent::Msg(Message::BuildScriptExecuted(_msg)) => {}
Message::Unknown => {} CheckEvent::Msg(Message::Unknown) => {}
} }
} }
} }
@ -244,10 +271,16 @@ impl CheckWatcherState {
/// have to wrap sub-processes output handling in a thread and pass messages /// have to wrap sub-processes output handling in a thread and pass messages
/// back over a channel. /// back over a channel.
struct WatchThread { struct WatchThread {
message_recv: Receiver<cargo_metadata::Message>, message_recv: Receiver<CheckEvent>,
cancel_send: Sender<()>, cancel_send: Sender<()>,
} }
enum CheckEvent {
Begin,
Msg(cargo_metadata::Message),
End,
}
impl WatchThread { impl WatchThread {
fn new( fn new(
check_command: Option<&String>, check_command: Option<&String>,
@ -273,6 +306,7 @@ impl WatchThread {
.spawn() .spawn()
.expect("couldn't launch cargo"); .expect("couldn't launch cargo");
message_send.send(CheckEvent::Begin).unwrap();
for message in cargo_metadata::parse_messages(command.stdout.take().unwrap()) { for message in cargo_metadata::parse_messages(command.stdout.take().unwrap()) {
match cancel_recv.try_recv() { match cancel_recv.try_recv() {
Ok(()) | Err(TryRecvError::Disconnected) => { Ok(()) | Err(TryRecvError::Disconnected) => {
@ -281,8 +315,9 @@ impl WatchThread {
Err(TryRecvError::Empty) => (), 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 } WatchThread { message_recv, cancel_send }
} }

View file

@ -338,6 +338,14 @@ fn loop_turn(
task_sender.send(Task::Notify(not)).unwrap(); 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 { Event::Msg(msg) => match msg {
Message::Request(req) => on_request( Message::Request(req) => on_request(

View file

@ -57,7 +57,50 @@ export class StatusDisplay implements vscode.Disposable {
this.statusBarItem.dispose(); 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() { private frame() {
return spinnerFrames[(this.i = ++this.i % spinnerFrames.length)]; 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
}

View file

@ -8,6 +8,7 @@ import { SyntaxTreeContentProvider } from './commands/syntaxTree';
import * as events from './events'; import * as events from './events';
import * as notifications from './notifications'; import * as notifications from './notifications';
import { Server } from './server'; import { Server } from './server';
import { StatusDisplay } from './commands/watch_status';
export async function activate(context: vscode.ExtensionContext) { export async function activate(context: vscode.ExtensionContext) {
function disposeOnDeactivation(disposable: vscode.Disposable) { function disposeOnDeactivation(disposable: vscode.Disposable) {
@ -83,6 +84,9 @@ export async function activate(context: vscode.ExtensionContext) {
overrideCommand('type', commands.onEnter.handle); overrideCommand('type', commands.onEnter.handle);
} }
const watchStatus = new StatusDisplay(Server.config.cargoCheckOptions.command || 'check');
disposeOnDeactivation(watchStatus);
// Notifications are events triggered by the language server // Notifications are events triggered by the language server
const allNotifications: Iterable<[ const allNotifications: Iterable<[
string, string,
@ -92,6 +96,10 @@ export async function activate(context: vscode.ExtensionContext) {
'rust-analyzer/publishDecorations', 'rust-analyzer/publishDecorations',
notifications.publishDecorations.handle, notifications.publishDecorations.handle,
], ],
[
'$/progress',
(params) => watchStatus.handleProgressNotification(params),
]
]; ];
const syntaxTreeContentProvider = new SyntaxTreeContentProvider(); const syntaxTreeContentProvider = new SyntaxTreeContentProvider();
const expandMacroContentProvider = new ExpandMacroContentProvider(); const expandMacroContentProvider = new ExpandMacroContentProvider();