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::{
#[derive(Debug)]
pub enum CheckTask {
Update(Url),
+ Status(WorkDoneProgress),
}
pub enum 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,
task_send.send(CheckTask::Update(location.uri)).unwrap();
}
- Message::BuildScriptExecuted(_msg) => {}
- Message::Unknown => {}
+ CheckEvent::Msg(Message::BuildScriptExecuted(_msg)) => {}
+ CheckEvent::Msg(Message::Unknown) => {}
}
}
}
/// 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>,
.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) => {
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 }
}
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
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) {
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,
'rust-analyzer/publishDecorations',
notifications.publishDecorations.handle,
],
+ [
+ '$/progress',
+ (params) => watchStatus.handleProgressNotification(params),
+ ]
];
const syntaxTreeContentProvider = new SyntaxTreeContentProvider();
const expandMacroContentProvider = new ExpandMacroContentProvider();