aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2020-06-25 06:56:47 +0100
committerAleksey Kladov <[email protected]>2020-06-25 06:56:47 +0100
commit76a530242a12f75e2a8456f952cef07e2d564f67 (patch)
treec172661c9be87bea10b796bffd32f4c32c65ab7a
parent78e94e4570f09c8cbe1f8c6802df9b112ca37f08 (diff)
parent6e81c9a921b975be7f2efb927dab4f3cfd505ebc (diff)
Merge branch 'Veetaha-feat/sync-branch'
-rw-r--r--Cargo.lock13
-rw-r--r--crates/ra_flycheck/Cargo.toml1
-rw-r--r--crates/ra_flycheck/src/lib.rs62
-rw-r--r--crates/ra_progress/Cargo.toml8
-rw-r--r--crates/ra_progress/src/lib.rs129
-rw-r--r--crates/rust-analyzer/Cargo.toml1
-rw-r--r--crates/rust-analyzer/src/global_state.rs23
-rw-r--r--crates/rust-analyzer/src/lsp_utils.rs52
-rw-r--r--crates/rust-analyzer/src/main_loop.rs36
-rw-r--r--crates/rust-analyzer/tests/heavy_tests/support.rs4
-rw-r--r--editors/code/src/main.ts3
-rw-r--r--editors/code/src/status_display.ts100
12 files changed, 299 insertions, 133 deletions
diff --git a/Cargo.lock b/Cargo.lock
index c2d00adeb..bed9acf8f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -967,6 +967,7 @@ dependencies = [
967 "crossbeam-channel", 967 "crossbeam-channel",
968 "jod-thread", 968 "jod-thread",
969 "log", 969 "log",
970 "ra_progress",
970 "ra_toolchain", 971 "ra_toolchain",
971 "serde_json", 972 "serde_json",
972] 973]
@@ -1080,7 +1081,11 @@ dependencies = [
1080 "ra_hir", 1081 "ra_hir",
1081 "ra_ide_db", 1082 "ra_ide_db",
1082 "ra_prof", 1083 "ra_prof",
1084<<<<<<< HEAD
1083 "ra_ssr", 1085 "ra_ssr",
1086=======
1087 "ra_progress",
1088>>>>>>> Veetaha-feat/sync-branch
1084 "ra_syntax", 1089 "ra_syntax",
1085 "ra_text_edit", 1090 "ra_text_edit",
1086 "rand", 1091 "rand",
@@ -1169,6 +1174,13 @@ dependencies = [
1169] 1174]
1170 1175
1171[[package]] 1176[[package]]
1177name = "ra_progress"
1178version = "0.1.0"
1179dependencies = [
1180 "crossbeam-channel",
1181]
1182
1183[[package]]
1172name = "ra_project_model" 1184name = "ra_project_model"
1173version = "0.1.0" 1185version = "0.1.0"
1174dependencies = [ 1186dependencies = [
@@ -1392,6 +1404,7 @@ dependencies = [
1392 "ra_mbe", 1404 "ra_mbe",
1393 "ra_proc_macro_srv", 1405 "ra_proc_macro_srv",
1394 "ra_prof", 1406 "ra_prof",
1407 "ra_progress",
1395 "ra_project_model", 1408 "ra_project_model",
1396 "ra_syntax", 1409 "ra_syntax",
1397 "ra_text_edit", 1410 "ra_text_edit",
diff --git a/crates/ra_flycheck/Cargo.toml b/crates/ra_flycheck/Cargo.toml
index 1aa39bade..838973963 100644
--- a/crates/ra_flycheck/Cargo.toml
+++ b/crates/ra_flycheck/Cargo.toml
@@ -14,3 +14,4 @@ cargo_metadata = "0.10.0"
14serde_json = "1.0.48" 14serde_json = "1.0.48"
15jod-thread = "0.1.1" 15jod-thread = "0.1.1"
16ra_toolchain = { path = "../ra_toolchain" } 16ra_toolchain = { path = "../ra_toolchain" }
17ra_progress = { path = "../ra_progress" }
diff --git a/crates/ra_flycheck/src/lib.rs b/crates/ra_flycheck/src/lib.rs
index 6c4170529..7b9f48eb0 100644
--- a/crates/ra_flycheck/src/lib.rs
+++ b/crates/ra_flycheck/src/lib.rs
@@ -3,6 +3,7 @@
3//! LSP diagnostics based on the output of the command. 3//! LSP diagnostics based on the output of the command.
4 4
5use std::{ 5use std::{
6 fmt,
6 io::{self, BufReader}, 7 io::{self, BufReader},
7 path::PathBuf, 8 path::PathBuf,
8 process::{Command, Stdio}, 9 process::{Command, Stdio},
@@ -16,6 +17,9 @@ pub use cargo_metadata::diagnostic::{
16 Applicability, Diagnostic, DiagnosticLevel, DiagnosticSpan, DiagnosticSpanMacroExpansion, 17 Applicability, Diagnostic, DiagnosticLevel, DiagnosticSpan, DiagnosticSpanMacroExpansion,
17}; 18};
18 19
20type Progress = ra_progress::Progress<(), String>;
21type ProgressSource = ra_progress::ProgressSource<(), String>;
22
19#[derive(Clone, Debug, PartialEq, Eq)] 23#[derive(Clone, Debug, PartialEq, Eq)]
20pub enum FlycheckConfig { 24pub enum FlycheckConfig {
21 CargoCommand { 25 CargoCommand {
@@ -31,6 +35,17 @@ pub enum FlycheckConfig {
31 }, 35 },
32} 36}
33 37
38impl fmt::Display for FlycheckConfig {
39 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40 match self {
41 FlycheckConfig::CargoCommand { command, .. } => write!(f, "cargo {}", command),
42 FlycheckConfig::CustomCommand { command, args } => {
43 write!(f, "{} {}", command, args.join(" "))
44 }
45 }
46 }
47}
48
34/// Flycheck wraps the shared state and communication machinery used for 49/// Flycheck wraps the shared state and communication machinery used for
35/// running `cargo check` (or other compatible command) and providing 50/// running `cargo check` (or other compatible command) and providing
36/// diagnostics based on the output. 51/// diagnostics based on the output.
@@ -44,11 +59,15 @@ pub struct Flycheck {
44} 59}
45 60
46impl Flycheck { 61impl Flycheck {
47 pub fn new(config: FlycheckConfig, workspace_root: PathBuf) -> Flycheck { 62 pub fn new(
63 config: FlycheckConfig,
64 workspace_root: PathBuf,
65 progress_src: ProgressSource,
66 ) -> Flycheck {
48 let (task_send, task_recv) = unbounded::<CheckTask>(); 67 let (task_send, task_recv) = unbounded::<CheckTask>();
49 let (cmd_send, cmd_recv) = unbounded::<CheckCommand>(); 68 let (cmd_send, cmd_recv) = unbounded::<CheckCommand>();
50 let handle = jod_thread::spawn(move || { 69 let handle = jod_thread::spawn(move || {
51 FlycheckThread::new(config, workspace_root).run(&task_send, &cmd_recv); 70 FlycheckThread::new(config, workspace_root, progress_src).run(&task_send, &cmd_recv);
52 }); 71 });
53 Flycheck { task_recv, cmd_send, handle } 72 Flycheck { task_recv, cmd_send, handle }
54 } 73 }
@@ -66,16 +85,6 @@ pub enum CheckTask {
66 85
67 /// Request adding a diagnostic with fixes included to a file 86 /// Request adding a diagnostic with fixes included to a file
68 AddDiagnostic { workspace_root: PathBuf, diagnostic: Diagnostic }, 87 AddDiagnostic { workspace_root: PathBuf, diagnostic: Diagnostic },
69
70 /// Request check progress notification to client
71 Status(Status),
72}
73
74#[derive(Debug)]
75pub enum Status {
76 Being,
77 Progress(String),
78 End,
79} 88}
80 89
81pub enum CheckCommand { 90pub enum CheckCommand {
@@ -87,6 +96,8 @@ struct FlycheckThread {
87 config: FlycheckConfig, 96 config: FlycheckConfig,
88 workspace_root: PathBuf, 97 workspace_root: PathBuf,
89 last_update_req: Option<Instant>, 98 last_update_req: Option<Instant>,
99 progress_src: ProgressSource,
100 progress: Option<Progress>,
90 // XXX: drop order is significant 101 // XXX: drop order is significant
91 message_recv: Receiver<CheckEvent>, 102 message_recv: Receiver<CheckEvent>,
92 /// WatchThread exists to wrap around the communication needed to be able to 103 /// WatchThread exists to wrap around the communication needed to be able to
@@ -98,11 +109,17 @@ struct FlycheckThread {
98} 109}
99 110
100impl FlycheckThread { 111impl FlycheckThread {
101 fn new(config: FlycheckConfig, workspace_root: PathBuf) -> FlycheckThread { 112 fn new(
113 config: FlycheckConfig,
114 workspace_root: PathBuf,
115 progress_src: ProgressSource,
116 ) -> FlycheckThread {
102 FlycheckThread { 117 FlycheckThread {
103 config, 118 config,
104 workspace_root, 119 workspace_root,
120 progress_src,
105 last_update_req: None, 121 last_update_req: None,
122 progress: None,
106 message_recv: never(), 123 message_recv: never(),
107 check_process: None, 124 check_process: None,
108 } 125 }
@@ -140,9 +157,9 @@ impl FlycheckThread {
140 } 157 }
141 } 158 }
142 159
143 fn clean_previous_results(&self, task_send: &Sender<CheckTask>) { 160 fn clean_previous_results(&mut self, task_send: &Sender<CheckTask>) {
144 task_send.send(CheckTask::ClearDiagnostics).unwrap(); 161 task_send.send(CheckTask::ClearDiagnostics).unwrap();
145 task_send.send(CheckTask::Status(Status::End)).unwrap(); 162 self.progress = None;
146 } 163 }
147 164
148 fn should_recheck(&mut self) -> bool { 165 fn should_recheck(&mut self) -> bool {
@@ -161,18 +178,17 @@ impl FlycheckThread {
161 } 178 }
162 } 179 }
163 180
164 fn handle_message(&self, msg: CheckEvent, task_send: &Sender<CheckTask>) { 181 fn handle_message(&mut self, msg: CheckEvent, task_send: &Sender<CheckTask>) {
165 match msg { 182 match msg {
166 CheckEvent::Begin => { 183 CheckEvent::Begin => {
167 task_send.send(CheckTask::Status(Status::Being)).unwrap(); 184 self.progress = Some(self.progress_src.begin(()));
168 } 185 }
169 186 CheckEvent::End => self.progress = None,
170 CheckEvent::End => {
171 task_send.send(CheckTask::Status(Status::End)).unwrap();
172 }
173
174 CheckEvent::Msg(Message::CompilerArtifact(msg)) => { 187 CheckEvent::Msg(Message::CompilerArtifact(msg)) => {
175 task_send.send(CheckTask::Status(Status::Progress(msg.target.name))).unwrap(); 188 self.progress
189 .as_mut()
190 .expect("check process reported progress without the 'Begin' notification")
191 .report(msg.target.name);
176 } 192 }
177 193
178 CheckEvent::Msg(Message::CompilerMessage(msg)) => { 194 CheckEvent::Msg(Message::CompilerMessage(msg)) => {
diff --git a/crates/ra_progress/Cargo.toml b/crates/ra_progress/Cargo.toml
new file mode 100644
index 000000000..c7f7c6dd3
--- /dev/null
+++ b/crates/ra_progress/Cargo.toml
@@ -0,0 +1,8 @@
1[package]
2name = "ra_progress"
3version = "0.1.0"
4authors = ["rust-analyzer developers"]
5edition = "2018"
6
7[dependencies]
8crossbeam-channel = { version = "0.4" }
diff --git a/crates/ra_progress/src/lib.rs b/crates/ra_progress/src/lib.rs
new file mode 100644
index 000000000..0ff1f846c
--- /dev/null
+++ b/crates/ra_progress/src/lib.rs
@@ -0,0 +1,129 @@
1//! General-purpose instrumentation for progress reporting.
2//!
3//! Note:
4//! Most of the methods accept `&mut self` just to be more restrictive (for forward compat)
5//! even tho for some of them we can weaken this requirement to shared reference (`&self`).
6
7use crossbeam_channel::Receiver;
8use std::fmt;
9
10#[derive(Debug)]
11pub enum ProgressStatus<B, P> {
12 Begin(B),
13 Progress(P),
14 End,
15}
16
17pub struct Progress<B, P>(Option<crossbeam_channel::Sender<ProgressStatus<B, P>>>);
18impl<B, P> Progress<B, P> {
19 pub fn report(&mut self, payload: P) {
20 self.report_with(|| payload);
21 }
22
23 pub fn report_with(&mut self, payload: impl FnOnce() -> P) {
24 self.send_status(|| ProgressStatus::Progress(payload()));
25 }
26
27 fn send_status(&self, status: impl FnOnce() -> ProgressStatus<B, P>) {
28 if let Some(sender) = &self.0 {
29 sender.try_send(status()).expect("progress report must not block");
30 }
31 }
32}
33
34impl<B, P> Drop for Progress<B, P> {
35 fn drop(&mut self) {
36 self.send_status(|| ProgressStatus::End);
37 }
38}
39
40pub struct ProgressSource<B, P>(Option<crossbeam_channel::Sender<ProgressStatus<B, P>>>);
41impl<B, P> ProgressSource<B, P> {
42 pub fn real_if(real: bool) -> (Receiver<ProgressStatus<B, P>>, Self) {
43 if real {
44 let (sender, receiver) = crossbeam_channel::unbounded();
45 (receiver, Self(Some(sender)))
46 } else {
47 (crossbeam_channel::never(), Self(None))
48 }
49 }
50
51 pub fn begin(&mut self, payload: B) -> Progress<B, P> {
52 self.begin_with(|| payload)
53 }
54
55 pub fn begin_with(&mut self, payload: impl FnOnce() -> B) -> Progress<B, P> {
56 let progress = Progress(self.0.clone());
57 progress.send_status(|| ProgressStatus::Begin(payload()));
58 progress
59 }
60}
61
62impl<B, P> Clone for ProgressSource<B, P> {
63 fn clone(&self) -> Self {
64 Self(self.0.clone())
65 }
66}
67
68impl<B, P> fmt::Debug for ProgressSource<B, P> {
69 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70 f.debug_tuple("ProgressSource").field(&self.0).finish()
71 }
72}
73
74pub type U32ProgressStatus = ProgressStatus<U32ProgressReport, U32ProgressReport>;
75
76#[derive(Debug)]
77pub struct U32ProgressReport {
78 pub processed: u32,
79 pub total: u32,
80}
81impl U32ProgressReport {
82 pub fn percentage(&self) -> f64 {
83 f64::from(100 * self.processed) / f64::from(self.total)
84 }
85 pub fn to_message(&self, prefix: &str, unit: &str) -> String {
86 format!("{} ({}/{} {})", prefix, self.processed, self.total, unit)
87 }
88}
89
90pub struct U32Progress {
91 inner: Progress<U32ProgressReport, U32ProgressReport>,
92 processed: u32,
93 total: u32,
94}
95
96#[derive(Debug, Eq, PartialEq)]
97pub struct IsDone(pub bool);
98
99impl U32Progress {
100 pub fn report(&mut self, new_processed: u32) -> IsDone {
101 if self.processed < new_processed {
102 self.processed = new_processed;
103 self.inner.report(U32ProgressReport { processed: new_processed, total: self.total });
104 }
105 IsDone(self.processed >= self.total)
106 }
107}
108
109#[derive(Clone)]
110pub struct U32ProgressSource {
111 inner: ProgressSource<U32ProgressReport, U32ProgressReport>,
112}
113
114impl U32ProgressSource {
115 pub fn real_if(
116 real: bool,
117 ) -> (Receiver<ProgressStatus<U32ProgressReport, U32ProgressReport>>, Self) {
118 let (recv, inner) = ProgressSource::real_if(real);
119 (recv, Self { inner })
120 }
121
122 pub fn begin(&mut self, initial: u32, total: u32) -> U32Progress {
123 U32Progress {
124 inner: self.inner.begin(U32ProgressReport { processed: initial, total }),
125 processed: initial,
126 total,
127 }
128 }
129}
diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml
index 68d04f3e3..2bbed395f 100644
--- a/crates/rust-analyzer/Cargo.toml
+++ b/crates/rust-analyzer/Cargo.toml
@@ -48,6 +48,7 @@ hir = { path = "../ra_hir", package = "ra_hir" }
48hir_def = { path = "../ra_hir_def", package = "ra_hir_def" } 48hir_def = { path = "../ra_hir_def", package = "ra_hir_def" }
49hir_ty = { path = "../ra_hir_ty", package = "ra_hir_ty" } 49hir_ty = { path = "../ra_hir_ty", package = "ra_hir_ty" }
50ra_proc_macro_srv = { path = "../ra_proc_macro_srv" } 50ra_proc_macro_srv = { path = "../ra_proc_macro_srv" }
51ra_progress = { path = "../ra_progress" }
51 52
52[target.'cfg(windows)'.dependencies] 53[target.'cfg(windows)'.dependencies]
53winapi = "0.3.8" 54winapi = "0.3.8"
diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs
index 87f3fe4db..7759c0ae3 100644
--- a/crates/rust-analyzer/src/global_state.rs
+++ b/crates/rust-analyzer/src/global_state.rs
@@ -27,9 +27,13 @@ use crate::{
27}; 27};
28use rustc_hash::{FxHashMap, FxHashSet}; 28use rustc_hash::{FxHashMap, FxHashSet};
29 29
30fn create_flycheck(workspaces: &[ProjectWorkspace], config: &FlycheckConfig) -> Option<Flycheck> { 30fn create_flycheck(
31 workspaces: &[ProjectWorkspace],
32 config: &FlycheckConfig,
33 progress_src: &ProgressSource<(), String>,
34) -> Option<Flycheck> {
31 // FIXME: Figure out the multi-workspace situation 35 // FIXME: Figure out the multi-workspace situation
32 workspaces.iter().find_map(|w| match w { 36 workspaces.iter().find_map(move |w| match w {
33 ProjectWorkspace::Cargo { cargo, .. } => { 37 ProjectWorkspace::Cargo { cargo, .. } => {
34 let cargo_project_root = cargo.workspace_root().to_path_buf(); 38 let cargo_project_root = cargo.workspace_root().to_path_buf();
35 Some(Flycheck::new(config.clone(), cargo_project_root.into())) 39 Some(Flycheck::new(config.clone(), cargo_project_root.into()))
@@ -143,7 +147,12 @@ impl GlobalState {
143 } 147 }
144 change.set_crate_graph(crate_graph); 148 change.set_crate_graph(crate_graph);
145 149
146 let flycheck = config.check.as_ref().and_then(|c| create_flycheck(&workspaces, c)); 150 let (flycheck_progress_receiver, flycheck_progress_src) =
151 ProgressSource::real_if(config.client_caps.work_done_progress);
152 let flycheck = config
153 .check
154 .as_ref()
155 .and_then(|c| create_flycheck(&workspaces, c, &flycheck_progress_src));
147 156
148 let mut analysis_host = AnalysisHost::new(lru_capacity); 157 let mut analysis_host = AnalysisHost::new(lru_capacity);
149 analysis_host.apply_change(change); 158 analysis_host.apply_change(change);
@@ -153,6 +162,8 @@ impl GlobalState {
153 loader, 162 loader,
154 task_receiver, 163 task_receiver,
155 flycheck, 164 flycheck,
165 flycheck_progress_src,
166 flycheck_progress_receiver,
156 diagnostics: Default::default(), 167 diagnostics: Default::default(),
157 mem_docs: FxHashSet::default(), 168 mem_docs: FxHashSet::default(),
158 vfs: Arc::new(RwLock::new((vfs, FxHashMap::default()))), 169 vfs: Arc::new(RwLock::new((vfs, FxHashMap::default()))),
@@ -170,8 +181,10 @@ impl GlobalState {
170 pub(crate) fn update_configuration(&mut self, config: Config) { 181 pub(crate) fn update_configuration(&mut self, config: Config) {
171 self.analysis_host.update_lru_capacity(config.lru_capacity); 182 self.analysis_host.update_lru_capacity(config.lru_capacity);
172 if config.check != self.config.check { 183 if config.check != self.config.check {
173 self.flycheck = 184 self.flycheck = config
174 config.check.as_ref().and_then(|it| create_flycheck(&self.workspaces, it)); 185 .check
186 .as_ref()
187 .and_then(|it| create_flycheck(&self.workspaces, it, &self.flycheck_progress_src));
175 } 188 }
176 189
177 self.config = config; 190 self.config = config;
diff --git a/crates/rust-analyzer/src/lsp_utils.rs b/crates/rust-analyzer/src/lsp_utils.rs
new file mode 100644
index 000000000..c79022797
--- /dev/null
+++ b/crates/rust-analyzer/src/lsp_utils.rs
@@ -0,0 +1,52 @@
1//! Utilities for LSP-related boilerplate code.
2
3use crossbeam_channel::Sender;
4use lsp_server::{Message, Notification, Request, RequestId};
5use ra_db::Canceled;
6use serde::{de::DeserializeOwned, Serialize};
7use std::error::Error;
8
9pub fn show_message(
10 typ: lsp_types::MessageType,
11 message: impl Into<String>,
12 sender: &Sender<Message>,
13) {
14 let message = message.into();
15 let params = lsp_types::ShowMessageParams { typ, message };
16 let not = notification_new::<lsp_types::notification::ShowMessage>(params);
17 sender.send(not.into()).unwrap();
18}
19
20pub(crate) fn is_canceled(e: &(dyn Error + 'static)) -> bool {
21 e.downcast_ref::<Canceled>().is_some()
22}
23
24pub(crate) fn notification_is<N: lsp_types::notification::Notification>(
25 notification: &Notification,
26) -> bool {
27 notification.method == N::METHOD
28}
29
30pub(crate) fn notification_cast<N>(notification: Notification) -> Result<N::Params, Notification>
31where
32 N: lsp_types::notification::Notification,
33 N::Params: DeserializeOwned,
34{
35 notification.extract(N::METHOD)
36}
37
38pub(crate) fn notification_new<N>(params: N::Params) -> Notification
39where
40 N: lsp_types::notification::Notification,
41 N::Params: Serialize,
42{
43 Notification::new(N::METHOD.to_string(), params)
44}
45
46pub(crate) fn request_new<R>(id: RequestId, params: R::Params) -> Request
47where
48 R: lsp_types::request::Request,
49 R::Params: Serialize,
50{
51 Request::new(id, R::METHOD.to_string(), params)
52}
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index eb9e7f913..7ccdbd29c 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -28,6 +28,14 @@ use crate::{
28 request_metrics::RequestMetrics, 28 request_metrics::RequestMetrics,
29 LspError, Result, 29 LspError, Result,
30}; 30};
31pub use lsp_utils::show_message;
32use lsp_utils::{is_canceled, notification_cast, notification_is, notification_new, request_new};
33use ra_progress::{
34 IsDone, ProgressStatus, U32Progress, U32ProgressReport, U32ProgressSource, U32ProgressStatus,
35};
36
37const FLYCHECK_PROGRESS_TOKEN: &str = "rustAnalyzer/flycheck";
38const ROOTS_SCANNED_PROGRESS_TOKEN: &str = "rustAnalyzer/rootsScanned";
31 39
32pub fn main_loop(config: Config, connection: Connection) -> Result<()> { 40pub fn main_loop(config: Config, connection: Connection) -> Result<()> {
33 log::info!("initial config: {:#?}", config); 41 log::info!("initial config: {:#?}", config);
@@ -138,6 +146,18 @@ pub fn main_loop(config: Config, connection: Connection) -> Result<()> {
138 recv(global_state.flycheck.as_ref().map_or(&never(), |it| &it.task_recv)) -> task => match task { 146 recv(global_state.flycheck.as_ref().map_or(&never(), |it| &it.task_recv)) -> task => match task {
139 Ok(task) => Event::CheckWatcher(task), 147 Ok(task) => Event::CheckWatcher(task),
140 Err(RecvError) => return Err("check watcher died".into()), 148 Err(RecvError) => return Err("check watcher died".into()),
149 },
150 recv(global_state.flycheck_progress_receiver) -> status => match status {
151 Ok(status) => Event::ProgressReport(ProgressReport::Flycheck(status)),
152 Err(RecvError) => return Err("check watcher died".into()),
153 },
154 recv(roots_scanned_progress_receiver) -> status => match status {
155 Ok(status) => Event::ProgressReport(ProgressReport::RootsScanned(status)),
156 Err(RecvError) => {
157 // Roots analysis has finished, we no longer need this receiver
158 roots_scanned_progress_receiver = never();
159 continue;
160 }
141 } 161 }
142 }; 162 };
143 if let Event::Msg(Message::Request(req)) = &event { 163 if let Event::Msg(Message::Request(req)) = &event {
@@ -169,6 +189,7 @@ pub fn main_loop(config: Config, connection: Connection) -> Result<()> {
169enum Task { 189enum Task {
170 Respond(Response), 190 Respond(Response),
171 Notify(Notification), 191 Notify(Notification),
192 SendRequest(Request),
172 Diagnostic(DiagnosticTask), 193 Diagnostic(DiagnosticTask),
173} 194}
174 195
@@ -177,6 +198,13 @@ enum Event {
177 Task(Task), 198 Task(Task),
178 Vfs(vfs::loader::Message), 199 Vfs(vfs::loader::Message),
179 CheckWatcher(CheckTask), 200 CheckWatcher(CheckTask),
201 ProgressReport(ProgressReport),
202}
203
204#[derive(Debug)]
205enum ProgressReport {
206 Flycheck(ProgressStatus<(), String>),
207 RootsScanned(U32ProgressStatus),
180} 208}
181 209
182impl fmt::Debug for Event { 210impl fmt::Debug for Event {
@@ -212,6 +240,7 @@ impl fmt::Debug for Event {
212 Event::Task(it) => fmt::Debug::fmt(it, f), 240 Event::Task(it) => fmt::Debug::fmt(it, f),
213 Event::Vfs(it) => fmt::Debug::fmt(it, f), 241 Event::Vfs(it) => fmt::Debug::fmt(it, f),
214 Event::CheckWatcher(it) => fmt::Debug::fmt(it, f), 242 Event::CheckWatcher(it) => fmt::Debug::fmt(it, f),
243 Event::ProgressReport(it) => fmt::Debug::fmt(it, f),
215 } 244 }
216 } 245 }
217} 246}
@@ -262,6 +291,9 @@ fn loop_turn(
262 } 291 }
263 }, 292 },
264 Event::CheckWatcher(task) => on_check_task(task, global_state, task_sender)?, 293 Event::CheckWatcher(task) => on_check_task(task, global_state, task_sender)?,
294 Event::ProgressReport(report) => {
295 on_progress_report(report, task_sender, loop_state, global_state)
296 }
265 Event::Msg(msg) => match msg { 297 Event::Msg(msg) => match msg {
266 Message::Request(req) => { 298 Message::Request(req) => {
267 on_request(global_state, pool, task_sender, &connection.sender, loop_start, req)? 299 on_request(global_state, pool, task_sender, &connection.sender, loop_start, req)?
@@ -826,7 +858,7 @@ where
826 Err(e) => match e.downcast::<LspError>() { 858 Err(e) => match e.downcast::<LspError>() {
827 Ok(lsp_error) => Response::new_err(id, lsp_error.code, lsp_error.message), 859 Ok(lsp_error) => Response::new_err(id, lsp_error.code, lsp_error.message),
828 Err(e) => { 860 Err(e) => {
829 if is_canceled(&e) { 861 if is_canceled(&*e) {
830 Response::new_err( 862 Response::new_err(
831 id, 863 id,
832 ErrorCode::ContentModified as i32, 864 ErrorCode::ContentModified as i32,
@@ -853,7 +885,7 @@ fn update_file_notifications_on_threadpool(
853 for file_id in subscriptions { 885 for file_id in subscriptions {
854 match handlers::publish_diagnostics(&world, file_id) { 886 match handlers::publish_diagnostics(&world, file_id) {
855 Err(e) => { 887 Err(e) => {
856 if !is_canceled(&e) { 888 if !is_canceled(&*e) {
857 log::error!("failed to compute diagnostics: {:?}", e); 889 log::error!("failed to compute diagnostics: {:?}", e);
858 } 890 }
859 } 891 }
diff --git a/crates/rust-analyzer/tests/heavy_tests/support.rs b/crates/rust-analyzer/tests/heavy_tests/support.rs
index 49f194f7e..15d2a05a4 100644
--- a/crates/rust-analyzer/tests/heavy_tests/support.rs
+++ b/crates/rust-analyzer/tests/heavy_tests/support.rs
@@ -202,7 +202,11 @@ impl Server {
202 ProgressParams { 202 ProgressParams {
203 token: lsp_types::ProgressToken::String(ref token), 203 token: lsp_types::ProgressToken::String(ref token),
204 value: ProgressParamsValue::WorkDone(WorkDoneProgress::End(_)), 204 value: ProgressParamsValue::WorkDone(WorkDoneProgress::End(_)),
205<<<<<<< HEAD
205 } if token == "rustAnalyzer/roots scanned" => true, 206 } if token == "rustAnalyzer/roots scanned" => true,
207=======
208 } if token == "rustAnalyzer/rootsScanned" => true,
209>>>>>>> Veetaha-feat/sync-branch
206 _ => false, 210 _ => false,
207 } 211 }
208 } 212 }
diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts
index 12b4d0510..cdb63b46f 100644
--- a/editors/code/src/main.ts
+++ b/editors/code/src/main.ts
@@ -5,7 +5,6 @@ import { promises as fs, PathLike } from "fs";
5 5
6import * as commands from './commands'; 6import * as commands from './commands';
7import { activateInlayHints } from './inlay_hints'; 7import { activateInlayHints } from './inlay_hints';
8import { activateStatusDisplay } from './status_display';
9import { Ctx } from './ctx'; 8import { Ctx } from './ctx';
10import { Config, NIGHTLY_TAG } from './config'; 9import { Config, NIGHTLY_TAG } from './config';
11import { log, assert, isValidExecutable } from './util'; 10import { log, assert, isValidExecutable } from './util';
@@ -117,8 +116,6 @@ export async function activate(context: vscode.ExtensionContext) {
117 116
118 ctx.pushCleanup(activateTaskProvider(workspaceFolder)); 117 ctx.pushCleanup(activateTaskProvider(workspaceFolder));
119 118
120 activateStatusDisplay(ctx);
121
122 activateInlayHints(ctx); 119 activateInlayHints(ctx);
123 120
124 vscode.workspace.onDidChangeConfiguration( 121 vscode.workspace.onDidChangeConfiguration(
diff --git a/editors/code/src/status_display.ts b/editors/code/src/status_display.ts
deleted file mode 100644
index f9cadc8a2..000000000
--- a/editors/code/src/status_display.ts
+++ /dev/null
@@ -1,100 +0,0 @@
1import * as vscode from 'vscode';
2
3import { WorkDoneProgress, WorkDoneProgressBegin, WorkDoneProgressReport, WorkDoneProgressEnd, Disposable } from 'vscode-languageclient';
4
5import { Ctx } from './ctx';
6
7const spinnerFrames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
8
9export function activateStatusDisplay(ctx: Ctx) {
10 const statusDisplay = new StatusDisplay(ctx.config.checkOnSave.command);
11 ctx.pushCleanup(statusDisplay);
12 const client = ctx.client;
13 if (client != null) {
14 ctx.pushCleanup(client.onProgress(
15 WorkDoneProgress.type,
16 'rustAnalyzer/cargoWatcher',
17 params => statusDisplay.handleProgressNotification(params)
18 ));
19 }
20}
21
22class StatusDisplay implements Disposable {
23 packageName?: string;
24
25 private i: number = 0;
26 private statusBarItem: vscode.StatusBarItem;
27 private command: string;
28 private timer?: NodeJS.Timeout;
29
30 constructor(command: string) {
31 this.statusBarItem = vscode.window.createStatusBarItem(
32 vscode.StatusBarAlignment.Left,
33 10,
34 );
35 this.command = command;
36 this.statusBarItem.hide();
37 }
38
39 show() {
40 this.packageName = undefined;
41
42 this.timer =
43 this.timer ||
44 setInterval(() => {
45 this.tick();
46 this.refreshLabel();
47 }, 300);
48
49 this.statusBarItem.show();
50 }
51
52 hide() {
53 if (this.timer) {
54 clearInterval(this.timer);
55 this.timer = undefined;
56 }
57
58 this.statusBarItem.hide();
59 }
60
61 dispose() {
62 if (this.timer) {
63 clearInterval(this.timer);
64 this.timer = undefined;
65 }
66
67 this.statusBarItem.dispose();
68 }
69
70 refreshLabel() {
71 if (this.packageName) {
72 this.statusBarItem.text = `${spinnerFrames[this.i]} cargo ${this.command} [${this.packageName}]`;
73 } else {
74 this.statusBarItem.text = `${spinnerFrames[this.i]} cargo ${this.command}`;
75 }
76 }
77
78 handleProgressNotification(params: WorkDoneProgressBegin | WorkDoneProgressReport | WorkDoneProgressEnd) {
79 switch (params.kind) {
80 case 'begin':
81 this.show();
82 break;
83
84 case 'report':
85 if (params.message) {
86 this.packageName = params.message;
87 this.refreshLabel();
88 }
89 break;
90
91 case 'end':
92 this.hide();
93 break;
94 }
95 }
96
97 private tick() {
98 this.i = (this.i + 1) % spinnerFrames.length;
99 }
100}