aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2020-06-25 07:01:03 +0100
committerAleksey Kladov <[email protected]>2020-06-25 07:01:03 +0100
commit874a5f80c74851aa142a196be49b73f55bd1c619 (patch)
tree0ff97656e30c9b1fe3c4bb96b0171f33890c11ee /crates
parent76a530242a12f75e2a8456f952cef07e2d564f67 (diff)
Scale progress down
There are two reasons why we don't want a generic ra_progress crate just yet: *First*, it introduces a common interface between separate components, and that is usually undesirable (b/c components start to fit the interface, rather than doing what makes most sense for each particular component). *Second*, it introduces a separate async channel for progress, which makes it harder to correlate progress reports with the work done. Ie, when we see 100% progress, it's not blindly obvious that the work has actually finished, we might have some pending messages still.
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_flycheck/Cargo.toml1
-rw-r--r--crates/ra_flycheck/src/lib.rs50
-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.rs21
-rw-r--r--crates/rust-analyzer/src/lib.rs6
-rw-r--r--crates/rust-analyzer/src/lsp_utils.rs12
-rw-r--r--crates/rust-analyzer/src/main_loop.rs211
-rw-r--r--crates/rust-analyzer/tests/heavy_tests/support.rs4
10 files changed, 102 insertions, 341 deletions
diff --git a/crates/ra_flycheck/Cargo.toml b/crates/ra_flycheck/Cargo.toml
index 838973963..1aa39bade 100644
--- a/crates/ra_flycheck/Cargo.toml
+++ b/crates/ra_flycheck/Cargo.toml
@@ -14,4 +14,3 @@ 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 7b9f48eb0..0e2ee8698 100644
--- a/crates/ra_flycheck/src/lib.rs
+++ b/crates/ra_flycheck/src/lib.rs
@@ -17,9 +17,6 @@ pub use cargo_metadata::diagnostic::{
17 Applicability, Diagnostic, DiagnosticLevel, DiagnosticSpan, DiagnosticSpanMacroExpansion, 17 Applicability, Diagnostic, DiagnosticLevel, DiagnosticSpan, DiagnosticSpanMacroExpansion,
18}; 18};
19 19
20type Progress = ra_progress::Progress<(), String>;
21type ProgressSource = ra_progress::ProgressSource<(), String>;
22
23#[derive(Clone, Debug, PartialEq, Eq)] 20#[derive(Clone, Debug, PartialEq, Eq)]
24pub enum FlycheckConfig { 21pub enum FlycheckConfig {
25 CargoCommand { 22 CargoCommand {
@@ -59,15 +56,11 @@ pub struct Flycheck {
59} 56}
60 57
61impl Flycheck { 58impl Flycheck {
62 pub fn new( 59 pub fn new(config: FlycheckConfig, workspace_root: PathBuf) -> Flycheck {
63 config: FlycheckConfig,
64 workspace_root: PathBuf,
65 progress_src: ProgressSource,
66 ) -> Flycheck {
67 let (task_send, task_recv) = unbounded::<CheckTask>(); 60 let (task_send, task_recv) = unbounded::<CheckTask>();
68 let (cmd_send, cmd_recv) = unbounded::<CheckCommand>(); 61 let (cmd_send, cmd_recv) = unbounded::<CheckCommand>();
69 let handle = jod_thread::spawn(move || { 62 let handle = jod_thread::spawn(move || {
70 FlycheckThread::new(config, workspace_root, progress_src).run(&task_send, &cmd_recv); 63 FlycheckThread::new(config, workspace_root).run(&task_send, &cmd_recv);
71 }); 64 });
72 Flycheck { task_recv, cmd_send, handle } 65 Flycheck { task_recv, cmd_send, handle }
73 } 66 }
@@ -85,6 +78,16 @@ pub enum CheckTask {
85 78
86 /// Request adding a diagnostic with fixes included to a file 79 /// Request adding a diagnostic with fixes included to a file
87 AddDiagnostic { workspace_root: PathBuf, diagnostic: Diagnostic }, 80 AddDiagnostic { workspace_root: PathBuf, diagnostic: Diagnostic },
81
82 /// Request check progress notification to client
83 Status(Status),
84}
85
86#[derive(Debug)]
87pub enum Status {
88 Being,
89 Progress(String),
90 End,
88} 91}
89 92
90pub enum CheckCommand { 93pub enum CheckCommand {
@@ -96,8 +99,6 @@ struct FlycheckThread {
96 config: FlycheckConfig, 99 config: FlycheckConfig,
97 workspace_root: PathBuf, 100 workspace_root: PathBuf,
98 last_update_req: Option<Instant>, 101 last_update_req: Option<Instant>,
99 progress_src: ProgressSource,
100 progress: Option<Progress>,
101 // XXX: drop order is significant 102 // XXX: drop order is significant
102 message_recv: Receiver<CheckEvent>, 103 message_recv: Receiver<CheckEvent>,
103 /// WatchThread exists to wrap around the communication needed to be able to 104 /// WatchThread exists to wrap around the communication needed to be able to
@@ -109,17 +110,11 @@ struct FlycheckThread {
109} 110}
110 111
111impl FlycheckThread { 112impl FlycheckThread {
112 fn new( 113 fn new(config: FlycheckConfig, workspace_root: PathBuf) -> FlycheckThread {
113 config: FlycheckConfig,
114 workspace_root: PathBuf,
115 progress_src: ProgressSource,
116 ) -> FlycheckThread {
117 FlycheckThread { 114 FlycheckThread {
118 config, 115 config,
119 workspace_root, 116 workspace_root,
120 progress_src,
121 last_update_req: None, 117 last_update_req: None,
122 progress: None,
123 message_recv: never(), 118 message_recv: never(),
124 check_process: None, 119 check_process: None,
125 } 120 }
@@ -157,9 +152,9 @@ impl FlycheckThread {
157 } 152 }
158 } 153 }
159 154
160 fn clean_previous_results(&mut self, task_send: &Sender<CheckTask>) { 155 fn clean_previous_results(&self, task_send: &Sender<CheckTask>) {
161 task_send.send(CheckTask::ClearDiagnostics).unwrap(); 156 task_send.send(CheckTask::ClearDiagnostics).unwrap();
162 self.progress = None; 157 task_send.send(CheckTask::Status(Status::End)).unwrap();
163 } 158 }
164 159
165 fn should_recheck(&mut self) -> bool { 160 fn should_recheck(&mut self) -> bool {
@@ -178,17 +173,18 @@ impl FlycheckThread {
178 } 173 }
179 } 174 }
180 175
181 fn handle_message(&mut self, msg: CheckEvent, task_send: &Sender<CheckTask>) { 176 fn handle_message(&self, msg: CheckEvent, task_send: &Sender<CheckTask>) {
182 match msg { 177 match msg {
183 CheckEvent::Begin => { 178 CheckEvent::Begin => {
184 self.progress = Some(self.progress_src.begin(())); 179 task_send.send(CheckTask::Status(Status::Being)).unwrap();
180 }
181
182 CheckEvent::End => {
183 task_send.send(CheckTask::Status(Status::End)).unwrap();
185 } 184 }
186 CheckEvent::End => self.progress = None, 185
187 CheckEvent::Msg(Message::CompilerArtifact(msg)) => { 186 CheckEvent::Msg(Message::CompilerArtifact(msg)) => {
188 self.progress 187 task_send.send(CheckTask::Status(Status::Progress(msg.target.name))).unwrap();
189 .as_mut()
190 .expect("check process reported progress without the 'Begin' notification")
191 .report(msg.target.name);
192 } 188 }
193 189
194 CheckEvent::Msg(Message::CompilerMessage(msg)) => { 190 CheckEvent::Msg(Message::CompilerMessage(msg)) => {
diff --git a/crates/ra_progress/Cargo.toml b/crates/ra_progress/Cargo.toml
deleted file mode 100644
index c7f7c6dd3..000000000
--- a/crates/ra_progress/Cargo.toml
+++ /dev/null
@@ -1,8 +0,0 @@
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
deleted file mode 100644
index 0ff1f846c..000000000
--- a/crates/ra_progress/src/lib.rs
+++ /dev/null
@@ -1,129 +0,0 @@
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 2bbed395f..68d04f3e3 100644
--- a/crates/rust-analyzer/Cargo.toml
+++ b/crates/rust-analyzer/Cargo.toml
@@ -48,7 +48,6 @@ 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" }
52 51
53[target.'cfg(windows)'.dependencies] 52[target.'cfg(windows)'.dependencies]
54winapi = "0.3.8" 53winapi = "0.3.8"
diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs
index 7759c0ae3..64d4e2787 100644
--- a/crates/rust-analyzer/src/global_state.rs
+++ b/crates/rust-analyzer/src/global_state.rs
@@ -27,11 +27,7 @@ use crate::{
27}; 27};
28use rustc_hash::{FxHashMap, FxHashSet}; 28use rustc_hash::{FxHashMap, FxHashSet};
29 29
30fn create_flycheck( 30fn create_flycheck(workspaces: &[ProjectWorkspace], config: &FlycheckConfig) -> Option<Flycheck> {
31 workspaces: &[ProjectWorkspace],
32 config: &FlycheckConfig,
33 progress_src: &ProgressSource<(), String>,
34) -> Option<Flycheck> {
35 // FIXME: Figure out the multi-workspace situation 31 // FIXME: Figure out the multi-workspace situation
36 workspaces.iter().find_map(move |w| match w { 32 workspaces.iter().find_map(move |w| match w {
37 ProjectWorkspace::Cargo { cargo, .. } => { 33 ProjectWorkspace::Cargo { cargo, .. } => {
@@ -147,12 +143,7 @@ impl GlobalState {
147 } 143 }
148 change.set_crate_graph(crate_graph); 144 change.set_crate_graph(crate_graph);
149 145
150 let (flycheck_progress_receiver, flycheck_progress_src) = 146 let flycheck = config.check.as_ref().and_then(|c| create_flycheck(&workspaces, c));
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));
156 147
157 let mut analysis_host = AnalysisHost::new(lru_capacity); 148 let mut analysis_host = AnalysisHost::new(lru_capacity);
158 analysis_host.apply_change(change); 149 analysis_host.apply_change(change);
@@ -162,8 +153,6 @@ impl GlobalState {
162 loader, 153 loader,
163 task_receiver, 154 task_receiver,
164 flycheck, 155 flycheck,
165 flycheck_progress_src,
166 flycheck_progress_receiver,
167 diagnostics: Default::default(), 156 diagnostics: Default::default(),
168 mem_docs: FxHashSet::default(), 157 mem_docs: FxHashSet::default(),
169 vfs: Arc::new(RwLock::new((vfs, FxHashMap::default()))), 158 vfs: Arc::new(RwLock::new((vfs, FxHashMap::default()))),
@@ -181,10 +170,8 @@ impl GlobalState {
181 pub(crate) fn update_configuration(&mut self, config: Config) { 170 pub(crate) fn update_configuration(&mut self, config: Config) {
182 self.analysis_host.update_lru_capacity(config.lru_capacity); 171 self.analysis_host.update_lru_capacity(config.lru_capacity);
183 if config.check != self.config.check { 172 if config.check != self.config.check {
184 self.flycheck = config 173 self.flycheck =
185 .check 174 config.check.as_ref().and_then(|it| create_flycheck(&self.workspaces, it));
186 .as_ref()
187 .and_then(|it| create_flycheck(&self.workspaces, it, &self.flycheck_progress_src));
188 } 175 }
189 176
190 self.config = config; 177 self.config = config;
diff --git a/crates/rust-analyzer/src/lib.rs b/crates/rust-analyzer/src/lib.rs
index d6cd04303..794286672 100644
--- a/crates/rust-analyzer/src/lib.rs
+++ b/crates/rust-analyzer/src/lib.rs
@@ -29,16 +29,14 @@ mod markdown;
29mod diagnostics; 29mod diagnostics;
30mod line_endings; 30mod line_endings;
31mod request_metrics; 31mod request_metrics;
32mod lsp_utils;
32pub mod lsp_ext; 33pub mod lsp_ext;
33pub mod config; 34pub mod config;
34 35
35use serde::de::DeserializeOwned; 36use serde::de::DeserializeOwned;
36 37
37pub type Result<T, E = Box<dyn std::error::Error + Send + Sync>> = std::result::Result<T, E>; 38pub type Result<T, E = Box<dyn std::error::Error + Send + Sync>> = std::result::Result<T, E>;
38pub use crate::{ 39pub use crate::{caps::server_capabilities, lsp_utils::show_message, main_loop::main_loop};
39 caps::server_capabilities,
40 main_loop::{main_loop, show_message},
41};
42use std::fmt; 40use std::fmt;
43 41
44pub fn from_json<T: DeserializeOwned>(what: &'static str, json: serde_json::Value) -> Result<T> { 42pub fn from_json<T: DeserializeOwned>(what: &'static str, json: serde_json::Value) -> Result<T> {
diff --git a/crates/rust-analyzer/src/lsp_utils.rs b/crates/rust-analyzer/src/lsp_utils.rs
index c79022797..078f8778e 100644
--- a/crates/rust-analyzer/src/lsp_utils.rs
+++ b/crates/rust-analyzer/src/lsp_utils.rs
@@ -1,10 +1,10 @@
1//! Utilities for LSP-related boilerplate code. 1//! Utilities for LSP-related boilerplate code.
2use std::error::Error;
2 3
3use crossbeam_channel::Sender; 4use crossbeam_channel::Sender;
4use lsp_server::{Message, Notification, Request, RequestId}; 5use lsp_server::{Message, Notification};
5use ra_db::Canceled; 6use ra_db::Canceled;
6use serde::{de::DeserializeOwned, Serialize}; 7use serde::{de::DeserializeOwned, Serialize};
7use std::error::Error;
8 8
9pub fn show_message( 9pub fn show_message(
10 typ: lsp_types::MessageType, 10 typ: lsp_types::MessageType,
@@ -42,11 +42,3 @@ where
42{ 42{
43 Notification::new(N::METHOD.to_string(), params) 43 Notification::new(N::METHOD.to_string(), params)
44} 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 7ccdbd29c..03569086a 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -25,17 +25,10 @@ use crate::{
25 from_proto, 25 from_proto,
26 global_state::{file_id_to_url, GlobalState, GlobalStateSnapshot, Status}, 26 global_state::{file_id_to_url, GlobalState, GlobalStateSnapshot, Status},
27 handlers, lsp_ext, 27 handlers, lsp_ext,
28 lsp_utils::{is_canceled, notification_cast, notification_is, notification_new, show_message},
28 request_metrics::RequestMetrics, 29 request_metrics::RequestMetrics,
29 LspError, Result, 30 LspError, Result,
30}; 31};
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";
39 32
40pub fn main_loop(config: Config, connection: Connection) -> Result<()> { 33pub fn main_loop(config: Config, connection: Connection) -> Result<()> {
41 log::info!("initial config: {:#?}", config); 34 log::info!("initial config: {:#?}", config);
@@ -147,18 +140,6 @@ pub fn main_loop(config: Config, connection: Connection) -> Result<()> {
147 Ok(task) => Event::CheckWatcher(task), 140 Ok(task) => Event::CheckWatcher(task),
148 Err(RecvError) => return Err("check watcher died".into()), 141 Err(RecvError) => return Err("check watcher died".into()),
149 }, 142 },
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 }
161 }
162 }; 143 };
163 if let Event::Msg(Message::Request(req)) = &event { 144 if let Event::Msg(Message::Request(req)) = &event {
164 if connection.handle_shutdown(&req)? { 145 if connection.handle_shutdown(&req)? {
@@ -188,8 +169,6 @@ pub fn main_loop(config: Config, connection: Connection) -> Result<()> {
188#[derive(Debug)] 169#[derive(Debug)]
189enum Task { 170enum Task {
190 Respond(Response), 171 Respond(Response),
191 Notify(Notification),
192 SendRequest(Request),
193 Diagnostic(DiagnosticTask), 172 Diagnostic(DiagnosticTask),
194} 173}
195 174
@@ -198,13 +177,6 @@ enum Event {
198 Task(Task), 177 Task(Task),
199 Vfs(vfs::loader::Message), 178 Vfs(vfs::loader::Message),
200 CheckWatcher(CheckTask), 179 CheckWatcher(CheckTask),
201 ProgressReport(ProgressReport),
202}
203
204#[derive(Debug)]
205enum ProgressReport {
206 Flycheck(ProgressStatus<(), String>),
207 RootsScanned(U32ProgressStatus),
208} 180}
209 181
210impl fmt::Debug for Event { 182impl fmt::Debug for Event {
@@ -221,11 +193,6 @@ impl fmt::Debug for Event {
221 return debug_verbose_not(not, f); 193 return debug_verbose_not(not, f);
222 } 194 }
223 } 195 }
224 Event::Task(Task::Notify(not)) => {
225 if notification_is::<lsp_types::notification::PublishDiagnostics>(not) {
226 return debug_verbose_not(not, f);
227 }
228 }
229 Event::Task(Task::Respond(resp)) => { 196 Event::Task(Task::Respond(resp)) => {
230 return f 197 return f
231 .debug_struct("Response") 198 .debug_struct("Response")
@@ -240,7 +207,6 @@ impl fmt::Debug for Event {
240 Event::Task(it) => fmt::Debug::fmt(it, f), 207 Event::Task(it) => fmt::Debug::fmt(it, f),
241 Event::Vfs(it) => fmt::Debug::fmt(it, f), 208 Event::Vfs(it) => fmt::Debug::fmt(it, f),
242 Event::CheckWatcher(it) => fmt::Debug::fmt(it, f), 209 Event::CheckWatcher(it) => fmt::Debug::fmt(it, f),
243 Event::ProgressReport(it) => fmt::Debug::fmt(it, f),
244 } 210 }
245 } 211 }
246} 212}
@@ -283,16 +249,28 @@ fn loop_turn(
283 } 249 }
284 } 250 }
285 vfs::loader::Message::Progress { n_total, n_done } => { 251 vfs::loader::Message::Progress { n_total, n_done } => {
286 if n_done == n_total { 252 let state = if n_done == 0 {
253 ProgressState::Start
254 } else if n_done < n_total {
255 ProgressState::Report
256 } else {
257 assert_eq!(n_done, n_total);
287 global_state.status = Status::Ready; 258 global_state.status = Status::Ready;
288 became_ready = true; 259 became_ready = true;
289 } 260 ProgressState::End
290 report_progress(global_state, &connection.sender, n_done, n_total, "roots scanned") 261 };
262 report_progress(
263 global_state,
264 &connection.sender,
265 "roots scanned",
266 state,
267 Some(format!("{}/{}", n_done, n_total)),
268 Some(percentage(n_done, n_total)),
269 )
291 } 270 }
292 }, 271 },
293 Event::CheckWatcher(task) => on_check_task(task, global_state, task_sender)?, 272 Event::CheckWatcher(task) => {
294 Event::ProgressReport(report) => { 273 on_check_task(task, global_state, task_sender, &connection.sender)?
295 on_progress_report(report, task_sender, loop_state, global_state)
296 } 274 }
297 Event::Msg(msg) => match msg { 275 Event::Msg(msg) => match msg {
298 Message::Request(req) => { 276 Message::Request(req) => {
@@ -367,9 +345,6 @@ fn on_task(task: Task, msg_sender: &Sender<Message>, global_state: &mut GlobalSt
367 msg_sender.send(response.into()).unwrap(); 345 msg_sender.send(response.into()).unwrap();
368 } 346 }
369 } 347 }
370 Task::Notify(n) => {
371 msg_sender.send(n.into()).unwrap();
372 }
373 Task::Diagnostic(task) => on_diagnostic_task(task, msg_sender, global_state), 348 Task::Diagnostic(task) => on_diagnostic_task(task, msg_sender, global_state),
374 } 349 }
375} 350}
@@ -621,6 +596,7 @@ fn on_check_task(
621 task: CheckTask, 596 task: CheckTask,
622 global_state: &mut GlobalState, 597 global_state: &mut GlobalState,
623 task_sender: &Sender<Task>, 598 task_sender: &Sender<Task>,
599 msg_sender: &Sender<Message>,
624) -> Result<()> { 600) -> Result<()> {
625 match task { 601 match task {
626 CheckTask::ClearDiagnostics => { 602 CheckTask::ClearDiagnostics => {
@@ -652,39 +628,13 @@ fn on_check_task(
652 } 628 }
653 629
654 CheckTask::Status(status) => { 630 CheckTask::Status(status) => {
655 if global_state.config.client_caps.work_done_progress { 631 let (state, message) = match status {
656 let progress = match status { 632 ra_flycheck::Status::Being => (ProgressState::Start, None),
657 ra_flycheck::Status::Being => { 633 ra_flycheck::Status::Progress(target) => (ProgressState::Report, Some(target)),
658 lsp_types::WorkDoneProgress::Begin(lsp_types::WorkDoneProgressBegin { 634 ra_flycheck::Status::End => (ProgressState::End, None),
659 title: "Running `cargo check`".to_string(), 635 };
660 cancellable: Some(false),
661 message: None,
662 percentage: None,
663 })
664 }
665 ra_flycheck::Status::Progress(target) => {
666 lsp_types::WorkDoneProgress::Report(lsp_types::WorkDoneProgressReport {
667 cancellable: Some(false),
668 message: Some(target),
669 percentage: None,
670 })
671 }
672 ra_flycheck::Status::End => {
673 lsp_types::WorkDoneProgress::End(lsp_types::WorkDoneProgressEnd {
674 message: None,
675 })
676 }
677 };
678 636
679 let params = lsp_types::ProgressParams { 637 report_progress(global_state, msg_sender, "cargo check", state, message, None);
680 token: lsp_types::ProgressToken::String(
681 "rustAnalyzer/cargoWatcher".to_string(),
682 ),
683 value: lsp_types::ProgressParamsValue::WorkDone(progress),
684 };
685 let not = notification_new::<lsp_types::notification::Progress>(params);
686 task_sender.send(Task::Notify(not)).unwrap();
687 }
688 } 638 }
689 }; 639 };
690 640
@@ -703,39 +653,55 @@ fn on_diagnostic_task(task: DiagnosticTask, msg_sender: &Sender<Message>, state:
703 } 653 }
704} 654}
705 655
656#[derive(Eq, PartialEq)]
657enum ProgressState {
658 Start,
659 Report,
660 End,
661}
662
663fn percentage(done: usize, total: usize) -> f64 {
664 (done as f64 / total.max(1) as f64) * 100.0
665}
666
706fn report_progress( 667fn report_progress(
707 global_state: &mut GlobalState, 668 global_state: &mut GlobalState,
708 sender: &Sender<Message>, 669 sender: &Sender<Message>,
709 done: usize, 670 title: &str,
710 total: usize, 671 state: ProgressState,
711 message: &str, 672 message: Option<String>,
673 percentage: Option<f64>,
712) { 674) {
713 let token = lsp_types::ProgressToken::String(format!("rustAnalyzer/{}", message)); 675 if !global_state.config.client_caps.work_done_progress {
714 let message = Some(format!("{}/{} {}", done, total, message)); 676 return;
715 let percentage = Some(100.0 * done as f64 / total.max(1) as f64); 677 }
716 let work_done_progress = if done == 0 { 678 let token = lsp_types::ProgressToken::String(format!("rustAnalyzer/{}", title));
717 let work_done_progress_create = global_state.req_queue.outgoing.register( 679 let work_done_progress = match state {
718 lsp_types::request::WorkDoneProgressCreate::METHOD.to_string(), 680 ProgressState::Start => {
719 lsp_types::WorkDoneProgressCreateParams { token: token.clone() }, 681 let work_done_progress_create = global_state.req_queue.outgoing.register(
720 DO_NOTHING, 682 lsp_types::request::WorkDoneProgressCreate::METHOD.to_string(),
721 ); 683 lsp_types::WorkDoneProgressCreateParams { token: token.clone() },
722 sender.send(work_done_progress_create.into()).unwrap(); 684 DO_NOTHING,
723 685 );
724 lsp_types::WorkDoneProgress::Begin(lsp_types::WorkDoneProgressBegin { 686 sender.send(work_done_progress_create.into()).unwrap();
725 title: "rust-analyzer".into(), 687
726 cancellable: None, 688 lsp_types::WorkDoneProgress::Begin(lsp_types::WorkDoneProgressBegin {
727 message, 689 title: title.into(),
728 percentage, 690 cancellable: None,
729 }) 691 message,
730 } else if done < total { 692 percentage,
731 lsp_types::WorkDoneProgress::Report(lsp_types::WorkDoneProgressReport { 693 })
732 cancellable: None, 694 }
733 message, 695 ProgressState::Report => {
734 percentage, 696 lsp_types::WorkDoneProgress::Report(lsp_types::WorkDoneProgressReport {
735 }) 697 cancellable: None,
736 } else { 698 message,
737 assert!(done == total); 699 percentage,
738 lsp_types::WorkDoneProgress::End(lsp_types::WorkDoneProgressEnd { message }) 700 })
701 }
702 ProgressState::End => {
703 lsp_types::WorkDoneProgress::End(lsp_types::WorkDoneProgressEnd { message })
704 }
739 }; 705 };
740 let notification = 706 let notification =
741 notification_new::<lsp_types::notification::Progress>(lsp_types::ProgressParams { 707 notification_new::<lsp_types::notification::Progress>(lsp_types::ProgressParams {
@@ -898,41 +864,6 @@ fn update_file_notifications_on_threadpool(
898 } 864 }
899} 865}
900 866
901pub fn show_message(
902 typ: lsp_types::MessageType,
903 message: impl Into<String>,
904 sender: &Sender<Message>,
905) {
906 let message = message.into();
907 let params = lsp_types::ShowMessageParams { typ, message };
908 let not = notification_new::<lsp_types::notification::ShowMessage>(params);
909 sender.send(not.into()).unwrap();
910}
911
912fn is_canceled(e: &Box<dyn std::error::Error + Send + Sync>) -> bool {
913 e.downcast_ref::<Canceled>().is_some()
914}
915
916fn notification_is<N: lsp_types::notification::Notification>(notification: &Notification) -> bool {
917 notification.method == N::METHOD
918}
919
920fn notification_cast<N>(notification: Notification) -> std::result::Result<N::Params, Notification>
921where
922 N: lsp_types::notification::Notification,
923 N::Params: DeserializeOwned,
924{
925 notification.extract(N::METHOD)
926}
927
928fn notification_new<N>(params: N::Params) -> Notification
929where
930 N: lsp_types::notification::Notification,
931 N::Params: Serialize,
932{
933 Notification::new(N::METHOD.to_string(), params)
934}
935
936#[cfg(test)] 867#[cfg(test)]
937mod tests { 868mod tests {
938 use lsp_types::{Position, Range, TextDocumentContentChangeEvent}; 869 use lsp_types::{Position, Range, TextDocumentContentChangeEvent};
diff --git a/crates/rust-analyzer/tests/heavy_tests/support.rs b/crates/rust-analyzer/tests/heavy_tests/support.rs
index 15d2a05a4..49f194f7e 100644
--- a/crates/rust-analyzer/tests/heavy_tests/support.rs
+++ b/crates/rust-analyzer/tests/heavy_tests/support.rs
@@ -202,11 +202,7 @@ 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
206 } if token == "rustAnalyzer/roots scanned" => true, 205 } if token == "rustAnalyzer/roots scanned" => true,
207=======
208 } if token == "rustAnalyzer/rootsScanned" => true,
209>>>>>>> Veetaha-feat/sync-branch
210 _ => false, 206 _ => false,
211 } 207 }
212 } 208 }