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 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<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 @@ 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<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 @@ 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 }
}

View 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(

View 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
}

View 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();