mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 13:03:31 +00:00
Merge branch 'Veetaha-feat/sync-branch'
This commit is contained in:
commit
76a530242a
12 changed files with 299 additions and 133 deletions
13
Cargo.lock
generated
13
Cargo.lock
generated
|
@ -967,6 +967,7 @@ dependencies = [
|
||||||
"crossbeam-channel",
|
"crossbeam-channel",
|
||||||
"jod-thread",
|
"jod-thread",
|
||||||
"log",
|
"log",
|
||||||
|
"ra_progress",
|
||||||
"ra_toolchain",
|
"ra_toolchain",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
]
|
]
|
||||||
|
@ -1080,7 +1081,11 @@ dependencies = [
|
||||||
"ra_hir",
|
"ra_hir",
|
||||||
"ra_ide_db",
|
"ra_ide_db",
|
||||||
"ra_prof",
|
"ra_prof",
|
||||||
|
<<<<<<< HEAD
|
||||||
"ra_ssr",
|
"ra_ssr",
|
||||||
|
=======
|
||||||
|
"ra_progress",
|
||||||
|
>>>>>>> Veetaha-feat/sync-branch
|
||||||
"ra_syntax",
|
"ra_syntax",
|
||||||
"ra_text_edit",
|
"ra_text_edit",
|
||||||
"rand",
|
"rand",
|
||||||
|
@ -1168,6 +1173,13 @@ dependencies = [
|
||||||
"ra_arena",
|
"ra_arena",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ra_progress"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-channel",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ra_project_model"
|
name = "ra_project_model"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@ -1392,6 +1404,7 @@ dependencies = [
|
||||||
"ra_mbe",
|
"ra_mbe",
|
||||||
"ra_proc_macro_srv",
|
"ra_proc_macro_srv",
|
||||||
"ra_prof",
|
"ra_prof",
|
||||||
|
"ra_progress",
|
||||||
"ra_project_model",
|
"ra_project_model",
|
||||||
"ra_syntax",
|
"ra_syntax",
|
||||||
"ra_text_edit",
|
"ra_text_edit",
|
||||||
|
|
|
@ -14,3 +14,4 @@ cargo_metadata = "0.10.0"
|
||||||
serde_json = "1.0.48"
|
serde_json = "1.0.48"
|
||||||
jod-thread = "0.1.1"
|
jod-thread = "0.1.1"
|
||||||
ra_toolchain = { path = "../ra_toolchain" }
|
ra_toolchain = { path = "../ra_toolchain" }
|
||||||
|
ra_progress = { path = "../ra_progress" }
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
//! LSP diagnostics based on the output of the command.
|
//! LSP diagnostics based on the output of the command.
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
|
fmt,
|
||||||
io::{self, BufReader},
|
io::{self, BufReader},
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
process::{Command, Stdio},
|
process::{Command, Stdio},
|
||||||
|
@ -16,6 +17,9 @@ pub use cargo_metadata::diagnostic::{
|
||||||
Applicability, Diagnostic, DiagnosticLevel, DiagnosticSpan, DiagnosticSpanMacroExpansion,
|
Applicability, Diagnostic, DiagnosticLevel, DiagnosticSpan, DiagnosticSpanMacroExpansion,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type Progress = ra_progress::Progress<(), String>;
|
||||||
|
type ProgressSource = ra_progress::ProgressSource<(), String>;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum FlycheckConfig {
|
pub enum FlycheckConfig {
|
||||||
CargoCommand {
|
CargoCommand {
|
||||||
|
@ -31,6 +35,17 @@ pub enum FlycheckConfig {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for FlycheckConfig {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
FlycheckConfig::CargoCommand { command, .. } => write!(f, "cargo {}", command),
|
||||||
|
FlycheckConfig::CustomCommand { command, args } => {
|
||||||
|
write!(f, "{} {}", command, args.join(" "))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Flycheck wraps the shared state and communication machinery used for
|
/// Flycheck wraps the shared state and communication machinery used for
|
||||||
/// running `cargo check` (or other compatible command) and providing
|
/// running `cargo check` (or other compatible command) and providing
|
||||||
/// diagnostics based on the output.
|
/// diagnostics based on the output.
|
||||||
|
@ -44,11 +59,15 @@ pub struct Flycheck {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Flycheck {
|
impl Flycheck {
|
||||||
pub fn new(config: FlycheckConfig, workspace_root: PathBuf) -> Flycheck {
|
pub fn new(
|
||||||
|
config: FlycheckConfig,
|
||||||
|
workspace_root: PathBuf,
|
||||||
|
progress_src: ProgressSource,
|
||||||
|
) -> Flycheck {
|
||||||
let (task_send, task_recv) = unbounded::<CheckTask>();
|
let (task_send, task_recv) = unbounded::<CheckTask>();
|
||||||
let (cmd_send, cmd_recv) = unbounded::<CheckCommand>();
|
let (cmd_send, cmd_recv) = unbounded::<CheckCommand>();
|
||||||
let handle = jod_thread::spawn(move || {
|
let handle = jod_thread::spawn(move || {
|
||||||
FlycheckThread::new(config, workspace_root).run(&task_send, &cmd_recv);
|
FlycheckThread::new(config, workspace_root, progress_src).run(&task_send, &cmd_recv);
|
||||||
});
|
});
|
||||||
Flycheck { task_recv, cmd_send, handle }
|
Flycheck { task_recv, cmd_send, handle }
|
||||||
}
|
}
|
||||||
|
@ -66,16 +85,6 @@ pub enum CheckTask {
|
||||||
|
|
||||||
/// Request adding a diagnostic with fixes included to a file
|
/// Request adding a diagnostic with fixes included to a file
|
||||||
AddDiagnostic { workspace_root: PathBuf, diagnostic: Diagnostic },
|
AddDiagnostic { workspace_root: PathBuf, diagnostic: Diagnostic },
|
||||||
|
|
||||||
/// Request check progress notification to client
|
|
||||||
Status(Status),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum Status {
|
|
||||||
Being,
|
|
||||||
Progress(String),
|
|
||||||
End,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum CheckCommand {
|
pub enum CheckCommand {
|
||||||
|
@ -87,6 +96,8 @@ struct FlycheckThread {
|
||||||
config: FlycheckConfig,
|
config: FlycheckConfig,
|
||||||
workspace_root: PathBuf,
|
workspace_root: PathBuf,
|
||||||
last_update_req: Option<Instant>,
|
last_update_req: Option<Instant>,
|
||||||
|
progress_src: ProgressSource,
|
||||||
|
progress: Option<Progress>,
|
||||||
// XXX: drop order is significant
|
// XXX: drop order is significant
|
||||||
message_recv: Receiver<CheckEvent>,
|
message_recv: Receiver<CheckEvent>,
|
||||||
/// WatchThread exists to wrap around the communication needed to be able to
|
/// WatchThread exists to wrap around the communication needed to be able to
|
||||||
|
@ -98,11 +109,17 @@ struct FlycheckThread {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FlycheckThread {
|
impl FlycheckThread {
|
||||||
fn new(config: FlycheckConfig, workspace_root: PathBuf) -> FlycheckThread {
|
fn new(
|
||||||
|
config: FlycheckConfig,
|
||||||
|
workspace_root: PathBuf,
|
||||||
|
progress_src: ProgressSource,
|
||||||
|
) -> FlycheckThread {
|
||||||
FlycheckThread {
|
FlycheckThread {
|
||||||
config,
|
config,
|
||||||
workspace_root,
|
workspace_root,
|
||||||
|
progress_src,
|
||||||
last_update_req: None,
|
last_update_req: None,
|
||||||
|
progress: None,
|
||||||
message_recv: never(),
|
message_recv: never(),
|
||||||
check_process: None,
|
check_process: None,
|
||||||
}
|
}
|
||||||
|
@ -140,9 +157,9 @@ impl FlycheckThread {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clean_previous_results(&self, task_send: &Sender<CheckTask>) {
|
fn clean_previous_results(&mut self, task_send: &Sender<CheckTask>) {
|
||||||
task_send.send(CheckTask::ClearDiagnostics).unwrap();
|
task_send.send(CheckTask::ClearDiagnostics).unwrap();
|
||||||
task_send.send(CheckTask::Status(Status::End)).unwrap();
|
self.progress = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_recheck(&mut self) -> bool {
|
fn should_recheck(&mut self) -> bool {
|
||||||
|
@ -161,18 +178,17 @@ impl FlycheckThread {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_message(&self, msg: CheckEvent, task_send: &Sender<CheckTask>) {
|
fn handle_message(&mut self, msg: CheckEvent, task_send: &Sender<CheckTask>) {
|
||||||
match msg {
|
match msg {
|
||||||
CheckEvent::Begin => {
|
CheckEvent::Begin => {
|
||||||
task_send.send(CheckTask::Status(Status::Being)).unwrap();
|
self.progress = Some(self.progress_src.begin(()));
|
||||||
}
|
}
|
||||||
|
CheckEvent::End => self.progress = None,
|
||||||
CheckEvent::End => {
|
|
||||||
task_send.send(CheckTask::Status(Status::End)).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
CheckEvent::Msg(Message::CompilerArtifact(msg)) => {
|
CheckEvent::Msg(Message::CompilerArtifact(msg)) => {
|
||||||
task_send.send(CheckTask::Status(Status::Progress(msg.target.name))).unwrap();
|
self.progress
|
||||||
|
.as_mut()
|
||||||
|
.expect("check process reported progress without the 'Begin' notification")
|
||||||
|
.report(msg.target.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
CheckEvent::Msg(Message::CompilerMessage(msg)) => {
|
CheckEvent::Msg(Message::CompilerMessage(msg)) => {
|
||||||
|
|
8
crates/ra_progress/Cargo.toml
Normal file
8
crates/ra_progress/Cargo.toml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
[package]
|
||||||
|
name = "ra_progress"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["rust-analyzer developers"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
crossbeam-channel = { version = "0.4" }
|
129
crates/ra_progress/src/lib.rs
Normal file
129
crates/ra_progress/src/lib.rs
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
//! General-purpose instrumentation for progress reporting.
|
||||||
|
//!
|
||||||
|
//! Note:
|
||||||
|
//! Most of the methods accept `&mut self` just to be more restrictive (for forward compat)
|
||||||
|
//! even tho for some of them we can weaken this requirement to shared reference (`&self`).
|
||||||
|
|
||||||
|
use crossbeam_channel::Receiver;
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum ProgressStatus<B, P> {
|
||||||
|
Begin(B),
|
||||||
|
Progress(P),
|
||||||
|
End,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Progress<B, P>(Option<crossbeam_channel::Sender<ProgressStatus<B, P>>>);
|
||||||
|
impl<B, P> Progress<B, P> {
|
||||||
|
pub fn report(&mut self, payload: P) {
|
||||||
|
self.report_with(|| payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn report_with(&mut self, payload: impl FnOnce() -> P) {
|
||||||
|
self.send_status(|| ProgressStatus::Progress(payload()));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_status(&self, status: impl FnOnce() -> ProgressStatus<B, P>) {
|
||||||
|
if let Some(sender) = &self.0 {
|
||||||
|
sender.try_send(status()).expect("progress report must not block");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B, P> Drop for Progress<B, P> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.send_status(|| ProgressStatus::End);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ProgressSource<B, P>(Option<crossbeam_channel::Sender<ProgressStatus<B, P>>>);
|
||||||
|
impl<B, P> ProgressSource<B, P> {
|
||||||
|
pub fn real_if(real: bool) -> (Receiver<ProgressStatus<B, P>>, Self) {
|
||||||
|
if real {
|
||||||
|
let (sender, receiver) = crossbeam_channel::unbounded();
|
||||||
|
(receiver, Self(Some(sender)))
|
||||||
|
} else {
|
||||||
|
(crossbeam_channel::never(), Self(None))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn begin(&mut self, payload: B) -> Progress<B, P> {
|
||||||
|
self.begin_with(|| payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn begin_with(&mut self, payload: impl FnOnce() -> B) -> Progress<B, P> {
|
||||||
|
let progress = Progress(self.0.clone());
|
||||||
|
progress.send_status(|| ProgressStatus::Begin(payload()));
|
||||||
|
progress
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B, P> Clone for ProgressSource<B, P> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self(self.0.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B, P> fmt::Debug for ProgressSource<B, P> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_tuple("ProgressSource").field(&self.0).finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type U32ProgressStatus = ProgressStatus<U32ProgressReport, U32ProgressReport>;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct U32ProgressReport {
|
||||||
|
pub processed: u32,
|
||||||
|
pub total: u32,
|
||||||
|
}
|
||||||
|
impl U32ProgressReport {
|
||||||
|
pub fn percentage(&self) -> f64 {
|
||||||
|
f64::from(100 * self.processed) / f64::from(self.total)
|
||||||
|
}
|
||||||
|
pub fn to_message(&self, prefix: &str, unit: &str) -> String {
|
||||||
|
format!("{} ({}/{} {})", prefix, self.processed, self.total, unit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct U32Progress {
|
||||||
|
inner: Progress<U32ProgressReport, U32ProgressReport>,
|
||||||
|
processed: u32,
|
||||||
|
total: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq)]
|
||||||
|
pub struct IsDone(pub bool);
|
||||||
|
|
||||||
|
impl U32Progress {
|
||||||
|
pub fn report(&mut self, new_processed: u32) -> IsDone {
|
||||||
|
if self.processed < new_processed {
|
||||||
|
self.processed = new_processed;
|
||||||
|
self.inner.report(U32ProgressReport { processed: new_processed, total: self.total });
|
||||||
|
}
|
||||||
|
IsDone(self.processed >= self.total)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct U32ProgressSource {
|
||||||
|
inner: ProgressSource<U32ProgressReport, U32ProgressReport>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl U32ProgressSource {
|
||||||
|
pub fn real_if(
|
||||||
|
real: bool,
|
||||||
|
) -> (Receiver<ProgressStatus<U32ProgressReport, U32ProgressReport>>, Self) {
|
||||||
|
let (recv, inner) = ProgressSource::real_if(real);
|
||||||
|
(recv, Self { inner })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn begin(&mut self, initial: u32, total: u32) -> U32Progress {
|
||||||
|
U32Progress {
|
||||||
|
inner: self.inner.begin(U32ProgressReport { processed: initial, total }),
|
||||||
|
processed: initial,
|
||||||
|
total,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -48,6 +48,7 @@ hir = { path = "../ra_hir", package = "ra_hir" }
|
||||||
hir_def = { path = "../ra_hir_def", package = "ra_hir_def" }
|
hir_def = { path = "../ra_hir_def", package = "ra_hir_def" }
|
||||||
hir_ty = { path = "../ra_hir_ty", package = "ra_hir_ty" }
|
hir_ty = { path = "../ra_hir_ty", package = "ra_hir_ty" }
|
||||||
ra_proc_macro_srv = { path = "../ra_proc_macro_srv" }
|
ra_proc_macro_srv = { path = "../ra_proc_macro_srv" }
|
||||||
|
ra_progress = { path = "../ra_progress" }
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
winapi = "0.3.8"
|
winapi = "0.3.8"
|
||||||
|
|
|
@ -27,9 +27,13 @@ use crate::{
|
||||||
};
|
};
|
||||||
use rustc_hash::{FxHashMap, FxHashSet};
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
|
|
||||||
fn create_flycheck(workspaces: &[ProjectWorkspace], config: &FlycheckConfig) -> Option<Flycheck> {
|
fn create_flycheck(
|
||||||
|
workspaces: &[ProjectWorkspace],
|
||||||
|
config: &FlycheckConfig,
|
||||||
|
progress_src: &ProgressSource<(), String>,
|
||||||
|
) -> Option<Flycheck> {
|
||||||
// FIXME: Figure out the multi-workspace situation
|
// FIXME: Figure out the multi-workspace situation
|
||||||
workspaces.iter().find_map(|w| match w {
|
workspaces.iter().find_map(move |w| match w {
|
||||||
ProjectWorkspace::Cargo { cargo, .. } => {
|
ProjectWorkspace::Cargo { cargo, .. } => {
|
||||||
let cargo_project_root = cargo.workspace_root().to_path_buf();
|
let cargo_project_root = cargo.workspace_root().to_path_buf();
|
||||||
Some(Flycheck::new(config.clone(), cargo_project_root.into()))
|
Some(Flycheck::new(config.clone(), cargo_project_root.into()))
|
||||||
|
@ -143,7 +147,12 @@ impl GlobalState {
|
||||||
}
|
}
|
||||||
change.set_crate_graph(crate_graph);
|
change.set_crate_graph(crate_graph);
|
||||||
|
|
||||||
let flycheck = config.check.as_ref().and_then(|c| create_flycheck(&workspaces, c));
|
let (flycheck_progress_receiver, flycheck_progress_src) =
|
||||||
|
ProgressSource::real_if(config.client_caps.work_done_progress);
|
||||||
|
let flycheck = config
|
||||||
|
.check
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|c| create_flycheck(&workspaces, c, &flycheck_progress_src));
|
||||||
|
|
||||||
let mut analysis_host = AnalysisHost::new(lru_capacity);
|
let mut analysis_host = AnalysisHost::new(lru_capacity);
|
||||||
analysis_host.apply_change(change);
|
analysis_host.apply_change(change);
|
||||||
|
@ -153,6 +162,8 @@ impl GlobalState {
|
||||||
loader,
|
loader,
|
||||||
task_receiver,
|
task_receiver,
|
||||||
flycheck,
|
flycheck,
|
||||||
|
flycheck_progress_src,
|
||||||
|
flycheck_progress_receiver,
|
||||||
diagnostics: Default::default(),
|
diagnostics: Default::default(),
|
||||||
mem_docs: FxHashSet::default(),
|
mem_docs: FxHashSet::default(),
|
||||||
vfs: Arc::new(RwLock::new((vfs, FxHashMap::default()))),
|
vfs: Arc::new(RwLock::new((vfs, FxHashMap::default()))),
|
||||||
|
@ -170,8 +181,10 @@ impl GlobalState {
|
||||||
pub(crate) fn update_configuration(&mut self, config: Config) {
|
pub(crate) fn update_configuration(&mut self, config: Config) {
|
||||||
self.analysis_host.update_lru_capacity(config.lru_capacity);
|
self.analysis_host.update_lru_capacity(config.lru_capacity);
|
||||||
if config.check != self.config.check {
|
if config.check != self.config.check {
|
||||||
self.flycheck =
|
self.flycheck = config
|
||||||
config.check.as_ref().and_then(|it| create_flycheck(&self.workspaces, it));
|
.check
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|it| create_flycheck(&self.workspaces, it, &self.flycheck_progress_src));
|
||||||
}
|
}
|
||||||
|
|
||||||
self.config = config;
|
self.config = config;
|
||||||
|
|
52
crates/rust-analyzer/src/lsp_utils.rs
Normal file
52
crates/rust-analyzer/src/lsp_utils.rs
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
//! Utilities for LSP-related boilerplate code.
|
||||||
|
|
||||||
|
use crossbeam_channel::Sender;
|
||||||
|
use lsp_server::{Message, Notification, Request, RequestId};
|
||||||
|
use ra_db::Canceled;
|
||||||
|
use serde::{de::DeserializeOwned, Serialize};
|
||||||
|
use std::error::Error;
|
||||||
|
|
||||||
|
pub fn show_message(
|
||||||
|
typ: lsp_types::MessageType,
|
||||||
|
message: impl Into<String>,
|
||||||
|
sender: &Sender<Message>,
|
||||||
|
) {
|
||||||
|
let message = message.into();
|
||||||
|
let params = lsp_types::ShowMessageParams { typ, message };
|
||||||
|
let not = notification_new::<lsp_types::notification::ShowMessage>(params);
|
||||||
|
sender.send(not.into()).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn is_canceled(e: &(dyn Error + 'static)) -> bool {
|
||||||
|
e.downcast_ref::<Canceled>().is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn notification_is<N: lsp_types::notification::Notification>(
|
||||||
|
notification: &Notification,
|
||||||
|
) -> bool {
|
||||||
|
notification.method == N::METHOD
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn notification_cast<N>(notification: Notification) -> Result<N::Params, Notification>
|
||||||
|
where
|
||||||
|
N: lsp_types::notification::Notification,
|
||||||
|
N::Params: DeserializeOwned,
|
||||||
|
{
|
||||||
|
notification.extract(N::METHOD)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn notification_new<N>(params: N::Params) -> Notification
|
||||||
|
where
|
||||||
|
N: lsp_types::notification::Notification,
|
||||||
|
N::Params: Serialize,
|
||||||
|
{
|
||||||
|
Notification::new(N::METHOD.to_string(), params)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn request_new<R>(id: RequestId, params: R::Params) -> Request
|
||||||
|
where
|
||||||
|
R: lsp_types::request::Request,
|
||||||
|
R::Params: Serialize,
|
||||||
|
{
|
||||||
|
Request::new(id, R::METHOD.to_string(), params)
|
||||||
|
}
|
|
@ -28,6 +28,14 @@ use crate::{
|
||||||
request_metrics::RequestMetrics,
|
request_metrics::RequestMetrics,
|
||||||
LspError, Result,
|
LspError, Result,
|
||||||
};
|
};
|
||||||
|
pub use lsp_utils::show_message;
|
||||||
|
use lsp_utils::{is_canceled, notification_cast, notification_is, notification_new, request_new};
|
||||||
|
use ra_progress::{
|
||||||
|
IsDone, ProgressStatus, U32Progress, U32ProgressReport, U32ProgressSource, U32ProgressStatus,
|
||||||
|
};
|
||||||
|
|
||||||
|
const FLYCHECK_PROGRESS_TOKEN: &str = "rustAnalyzer/flycheck";
|
||||||
|
const ROOTS_SCANNED_PROGRESS_TOKEN: &str = "rustAnalyzer/rootsScanned";
|
||||||
|
|
||||||
pub fn main_loop(config: Config, connection: Connection) -> Result<()> {
|
pub fn main_loop(config: Config, connection: Connection) -> Result<()> {
|
||||||
log::info!("initial config: {:#?}", config);
|
log::info!("initial config: {:#?}", config);
|
||||||
|
@ -138,6 +146,18 @@ pub fn main_loop(config: Config, connection: Connection) -> Result<()> {
|
||||||
recv(global_state.flycheck.as_ref().map_or(&never(), |it| &it.task_recv)) -> task => match task {
|
recv(global_state.flycheck.as_ref().map_or(&never(), |it| &it.task_recv)) -> task => match task {
|
||||||
Ok(task) => Event::CheckWatcher(task),
|
Ok(task) => Event::CheckWatcher(task),
|
||||||
Err(RecvError) => return Err("check watcher died".into()),
|
Err(RecvError) => return Err("check watcher died".into()),
|
||||||
|
},
|
||||||
|
recv(global_state.flycheck_progress_receiver) -> status => match status {
|
||||||
|
Ok(status) => Event::ProgressReport(ProgressReport::Flycheck(status)),
|
||||||
|
Err(RecvError) => return Err("check watcher died".into()),
|
||||||
|
},
|
||||||
|
recv(roots_scanned_progress_receiver) -> status => match status {
|
||||||
|
Ok(status) => Event::ProgressReport(ProgressReport::RootsScanned(status)),
|
||||||
|
Err(RecvError) => {
|
||||||
|
// Roots analysis has finished, we no longer need this receiver
|
||||||
|
roots_scanned_progress_receiver = never();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if let Event::Msg(Message::Request(req)) = &event {
|
if let Event::Msg(Message::Request(req)) = &event {
|
||||||
|
@ -169,6 +189,7 @@ pub fn main_loop(config: Config, connection: Connection) -> Result<()> {
|
||||||
enum Task {
|
enum Task {
|
||||||
Respond(Response),
|
Respond(Response),
|
||||||
Notify(Notification),
|
Notify(Notification),
|
||||||
|
SendRequest(Request),
|
||||||
Diagnostic(DiagnosticTask),
|
Diagnostic(DiagnosticTask),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,6 +198,13 @@ enum Event {
|
||||||
Task(Task),
|
Task(Task),
|
||||||
Vfs(vfs::loader::Message),
|
Vfs(vfs::loader::Message),
|
||||||
CheckWatcher(CheckTask),
|
CheckWatcher(CheckTask),
|
||||||
|
ProgressReport(ProgressReport),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum ProgressReport {
|
||||||
|
Flycheck(ProgressStatus<(), String>),
|
||||||
|
RootsScanned(U32ProgressStatus),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for Event {
|
impl fmt::Debug for Event {
|
||||||
|
@ -212,6 +240,7 @@ impl fmt::Debug for Event {
|
||||||
Event::Task(it) => fmt::Debug::fmt(it, f),
|
Event::Task(it) => fmt::Debug::fmt(it, f),
|
||||||
Event::Vfs(it) => fmt::Debug::fmt(it, f),
|
Event::Vfs(it) => fmt::Debug::fmt(it, f),
|
||||||
Event::CheckWatcher(it) => fmt::Debug::fmt(it, f),
|
Event::CheckWatcher(it) => fmt::Debug::fmt(it, f),
|
||||||
|
Event::ProgressReport(it) => fmt::Debug::fmt(it, f),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -262,6 +291,9 @@ fn loop_turn(
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Event::CheckWatcher(task) => on_check_task(task, global_state, task_sender)?,
|
Event::CheckWatcher(task) => on_check_task(task, global_state, task_sender)?,
|
||||||
|
Event::ProgressReport(report) => {
|
||||||
|
on_progress_report(report, task_sender, loop_state, global_state)
|
||||||
|
}
|
||||||
Event::Msg(msg) => match msg {
|
Event::Msg(msg) => match msg {
|
||||||
Message::Request(req) => {
|
Message::Request(req) => {
|
||||||
on_request(global_state, pool, task_sender, &connection.sender, loop_start, req)?
|
on_request(global_state, pool, task_sender, &connection.sender, loop_start, req)?
|
||||||
|
@ -826,7 +858,7 @@ where
|
||||||
Err(e) => match e.downcast::<LspError>() {
|
Err(e) => match e.downcast::<LspError>() {
|
||||||
Ok(lsp_error) => Response::new_err(id, lsp_error.code, lsp_error.message),
|
Ok(lsp_error) => Response::new_err(id, lsp_error.code, lsp_error.message),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
if is_canceled(&e) {
|
if is_canceled(&*e) {
|
||||||
Response::new_err(
|
Response::new_err(
|
||||||
id,
|
id,
|
||||||
ErrorCode::ContentModified as i32,
|
ErrorCode::ContentModified as i32,
|
||||||
|
@ -853,7 +885,7 @@ fn update_file_notifications_on_threadpool(
|
||||||
for file_id in subscriptions {
|
for file_id in subscriptions {
|
||||||
match handlers::publish_diagnostics(&world, file_id) {
|
match handlers::publish_diagnostics(&world, file_id) {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
if !is_canceled(&e) {
|
if !is_canceled(&*e) {
|
||||||
log::error!("failed to compute diagnostics: {:?}", e);
|
log::error!("failed to compute diagnostics: {:?}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -202,7 +202,11 @@ impl Server {
|
||||||
ProgressParams {
|
ProgressParams {
|
||||||
token: lsp_types::ProgressToken::String(ref token),
|
token: lsp_types::ProgressToken::String(ref token),
|
||||||
value: ProgressParamsValue::WorkDone(WorkDoneProgress::End(_)),
|
value: ProgressParamsValue::WorkDone(WorkDoneProgress::End(_)),
|
||||||
|
<<<<<<< HEAD
|
||||||
} if token == "rustAnalyzer/roots scanned" => true,
|
} if token == "rustAnalyzer/roots scanned" => true,
|
||||||
|
=======
|
||||||
|
} if token == "rustAnalyzer/rootsScanned" => true,
|
||||||
|
>>>>>>> Veetaha-feat/sync-branch
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@ import { promises as fs, PathLike } from "fs";
|
||||||
|
|
||||||
import * as commands from './commands';
|
import * as commands from './commands';
|
||||||
import { activateInlayHints } from './inlay_hints';
|
import { activateInlayHints } from './inlay_hints';
|
||||||
import { activateStatusDisplay } from './status_display';
|
|
||||||
import { Ctx } from './ctx';
|
import { Ctx } from './ctx';
|
||||||
import { Config, NIGHTLY_TAG } from './config';
|
import { Config, NIGHTLY_TAG } from './config';
|
||||||
import { log, assert, isValidExecutable } from './util';
|
import { log, assert, isValidExecutable } from './util';
|
||||||
|
@ -117,8 +116,6 @@ export async function activate(context: vscode.ExtensionContext) {
|
||||||
|
|
||||||
ctx.pushCleanup(activateTaskProvider(workspaceFolder));
|
ctx.pushCleanup(activateTaskProvider(workspaceFolder));
|
||||||
|
|
||||||
activateStatusDisplay(ctx);
|
|
||||||
|
|
||||||
activateInlayHints(ctx);
|
activateInlayHints(ctx);
|
||||||
|
|
||||||
vscode.workspace.onDidChangeConfiguration(
|
vscode.workspace.onDidChangeConfiguration(
|
||||||
|
|
|
@ -1,100 +0,0 @@
|
||||||
import * as vscode from 'vscode';
|
|
||||||
|
|
||||||
import { WorkDoneProgress, WorkDoneProgressBegin, WorkDoneProgressReport, WorkDoneProgressEnd, Disposable } from 'vscode-languageclient';
|
|
||||||
|
|
||||||
import { Ctx } from './ctx';
|
|
||||||
|
|
||||||
const spinnerFrames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
||||||
|
|
||||||
export function activateStatusDisplay(ctx: Ctx) {
|
|
||||||
const statusDisplay = new StatusDisplay(ctx.config.checkOnSave.command);
|
|
||||||
ctx.pushCleanup(statusDisplay);
|
|
||||||
const client = ctx.client;
|
|
||||||
if (client != null) {
|
|
||||||
ctx.pushCleanup(client.onProgress(
|
|
||||||
WorkDoneProgress.type,
|
|
||||||
'rustAnalyzer/cargoWatcher',
|
|
||||||
params => statusDisplay.handleProgressNotification(params)
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class StatusDisplay implements Disposable {
|
|
||||||
packageName?: string;
|
|
||||||
|
|
||||||
private i: number = 0;
|
|
||||||
private statusBarItem: vscode.StatusBarItem;
|
|
||||||
private command: string;
|
|
||||||
private timer?: NodeJS.Timeout;
|
|
||||||
|
|
||||||
constructor(command: string) {
|
|
||||||
this.statusBarItem = vscode.window.createStatusBarItem(
|
|
||||||
vscode.StatusBarAlignment.Left,
|
|
||||||
10,
|
|
||||||
);
|
|
||||||
this.command = command;
|
|
||||||
this.statusBarItem.hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
show() {
|
|
||||||
this.packageName = undefined;
|
|
||||||
|
|
||||||
this.timer =
|
|
||||||
this.timer ||
|
|
||||||
setInterval(() => {
|
|
||||||
this.tick();
|
|
||||||
this.refreshLabel();
|
|
||||||
}, 300);
|
|
||||||
|
|
||||||
this.statusBarItem.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
hide() {
|
|
||||||
if (this.timer) {
|
|
||||||
clearInterval(this.timer);
|
|
||||||
this.timer = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.statusBarItem.hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
dispose() {
|
|
||||||
if (this.timer) {
|
|
||||||
clearInterval(this.timer);
|
|
||||||
this.timer = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.statusBarItem.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
refreshLabel() {
|
|
||||||
if (this.packageName) {
|
|
||||||
this.statusBarItem.text = `${spinnerFrames[this.i]} cargo ${this.command} [${this.packageName}]`;
|
|
||||||
} else {
|
|
||||||
this.statusBarItem.text = `${spinnerFrames[this.i]} cargo ${this.command}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleProgressNotification(params: WorkDoneProgressBegin | WorkDoneProgressReport | WorkDoneProgressEnd) {
|
|
||||||
switch (params.kind) {
|
|
||||||
case 'begin':
|
|
||||||
this.show();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'report':
|
|
||||||
if (params.message) {
|
|
||||||
this.packageName = params.message;
|
|
||||||
this.refreshLabel();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'end':
|
|
||||||
this.hide();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private tick() {
|
|
||||||
this.i = (this.i + 1) % spinnerFrames.length;
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in a new issue