diff options
author | Aleksey Kladov <[email protected]> | 2020-06-25 07:01:03 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2020-06-25 07:01:03 +0100 |
commit | 874a5f80c74851aa142a196be49b73f55bd1c619 (patch) | |
tree | 0ff97656e30c9b1fe3c4bb96b0171f33890c11ee /crates | |
parent | 76a530242a12f75e2a8456f952cef07e2d564f67 (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.toml | 1 | ||||
-rw-r--r-- | crates/ra_flycheck/src/lib.rs | 50 | ||||
-rw-r--r-- | crates/ra_progress/Cargo.toml | 8 | ||||
-rw-r--r-- | crates/ra_progress/src/lib.rs | 129 | ||||
-rw-r--r-- | crates/rust-analyzer/Cargo.toml | 1 | ||||
-rw-r--r-- | crates/rust-analyzer/src/global_state.rs | 21 | ||||
-rw-r--r-- | crates/rust-analyzer/src/lib.rs | 6 | ||||
-rw-r--r-- | crates/rust-analyzer/src/lsp_utils.rs | 12 | ||||
-rw-r--r-- | crates/rust-analyzer/src/main_loop.rs | 211 | ||||
-rw-r--r-- | crates/rust-analyzer/tests/heavy_tests/support.rs | 4 |
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" | |||
14 | serde_json = "1.0.48" | 14 | serde_json = "1.0.48" |
15 | jod-thread = "0.1.1" | 15 | jod-thread = "0.1.1" |
16 | ra_toolchain = { path = "../ra_toolchain" } | 16 | ra_toolchain = { path = "../ra_toolchain" } |
17 | ra_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 | ||
20 | type Progress = ra_progress::Progress<(), String>; | ||
21 | type ProgressSource = ra_progress::ProgressSource<(), String>; | ||
22 | |||
23 | #[derive(Clone, Debug, PartialEq, Eq)] | 20 | #[derive(Clone, Debug, PartialEq, Eq)] |
24 | pub enum FlycheckConfig { | 21 | pub enum FlycheckConfig { |
25 | CargoCommand { | 22 | CargoCommand { |
@@ -59,15 +56,11 @@ pub struct Flycheck { | |||
59 | } | 56 | } |
60 | 57 | ||
61 | impl Flycheck { | 58 | impl 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)] | ||
87 | pub enum Status { | ||
88 | Being, | ||
89 | Progress(String), | ||
90 | End, | ||
88 | } | 91 | } |
89 | 92 | ||
90 | pub enum CheckCommand { | 93 | pub 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 | ||
111 | impl FlycheckThread { | 112 | impl 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] | ||
2 | name = "ra_progress" | ||
3 | version = "0.1.0" | ||
4 | authors = ["rust-analyzer developers"] | ||
5 | edition = "2018" | ||
6 | |||
7 | [dependencies] | ||
8 | crossbeam-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 | |||
7 | use crossbeam_channel::Receiver; | ||
8 | use std::fmt; | ||
9 | |||
10 | #[derive(Debug)] | ||
11 | pub enum ProgressStatus<B, P> { | ||
12 | Begin(B), | ||
13 | Progress(P), | ||
14 | End, | ||
15 | } | ||
16 | |||
17 | pub struct Progress<B, P>(Option<crossbeam_channel::Sender<ProgressStatus<B, P>>>); | ||
18 | impl<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 | |||
34 | impl<B, P> Drop for Progress<B, P> { | ||
35 | fn drop(&mut self) { | ||
36 | self.send_status(|| ProgressStatus::End); | ||
37 | } | ||
38 | } | ||
39 | |||
40 | pub struct ProgressSource<B, P>(Option<crossbeam_channel::Sender<ProgressStatus<B, P>>>); | ||
41 | impl<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 | |||
62 | impl<B, P> Clone for ProgressSource<B, P> { | ||
63 | fn clone(&self) -> Self { | ||
64 | Self(self.0.clone()) | ||
65 | } | ||
66 | } | ||
67 | |||
68 | impl<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 | |||
74 | pub type U32ProgressStatus = ProgressStatus<U32ProgressReport, U32ProgressReport>; | ||
75 | |||
76 | #[derive(Debug)] | ||
77 | pub struct U32ProgressReport { | ||
78 | pub processed: u32, | ||
79 | pub total: u32, | ||
80 | } | ||
81 | impl 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 | |||
90 | pub struct U32Progress { | ||
91 | inner: Progress<U32ProgressReport, U32ProgressReport>, | ||
92 | processed: u32, | ||
93 | total: u32, | ||
94 | } | ||
95 | |||
96 | #[derive(Debug, Eq, PartialEq)] | ||
97 | pub struct IsDone(pub bool); | ||
98 | |||
99 | impl 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)] | ||
110 | pub struct U32ProgressSource { | ||
111 | inner: ProgressSource<U32ProgressReport, U32ProgressReport>, | ||
112 | } | ||
113 | |||
114 | impl 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" } | |||
48 | hir_def = { path = "../ra_hir_def", package = "ra_hir_def" } | 48 | hir_def = { path = "../ra_hir_def", package = "ra_hir_def" } |
49 | hir_ty = { path = "../ra_hir_ty", package = "ra_hir_ty" } | 49 | hir_ty = { path = "../ra_hir_ty", package = "ra_hir_ty" } |
50 | ra_proc_macro_srv = { path = "../ra_proc_macro_srv" } | 50 | ra_proc_macro_srv = { path = "../ra_proc_macro_srv" } |
51 | ra_progress = { path = "../ra_progress" } | ||
52 | 51 | ||
53 | [target.'cfg(windows)'.dependencies] | 52 | [target.'cfg(windows)'.dependencies] |
54 | winapi = "0.3.8" | 53 | winapi = "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 | }; |
28 | use rustc_hash::{FxHashMap, FxHashSet}; | 28 | use rustc_hash::{FxHashMap, FxHashSet}; |
29 | 29 | ||
30 | fn create_flycheck( | 30 | fn 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; | |||
29 | mod diagnostics; | 29 | mod diagnostics; |
30 | mod line_endings; | 30 | mod line_endings; |
31 | mod request_metrics; | 31 | mod request_metrics; |
32 | mod lsp_utils; | ||
32 | pub mod lsp_ext; | 33 | pub mod lsp_ext; |
33 | pub mod config; | 34 | pub mod config; |
34 | 35 | ||
35 | use serde::de::DeserializeOwned; | 36 | use serde::de::DeserializeOwned; |
36 | 37 | ||
37 | pub type Result<T, E = Box<dyn std::error::Error + Send + Sync>> = std::result::Result<T, E>; | 38 | pub type Result<T, E = Box<dyn std::error::Error + Send + Sync>> = std::result::Result<T, E>; |
38 | pub use crate::{ | 39 | pub 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 | }; | ||
42 | use std::fmt; | 40 | use std::fmt; |
43 | 41 | ||
44 | pub fn from_json<T: DeserializeOwned>(what: &'static str, json: serde_json::Value) -> Result<T> { | 42 | pub 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. |
2 | use std::error::Error; | ||
2 | 3 | ||
3 | use crossbeam_channel::Sender; | 4 | use crossbeam_channel::Sender; |
4 | use lsp_server::{Message, Notification, Request, RequestId}; | 5 | use lsp_server::{Message, Notification}; |
5 | use ra_db::Canceled; | 6 | use ra_db::Canceled; |
6 | use serde::{de::DeserializeOwned, Serialize}; | 7 | use serde::{de::DeserializeOwned, Serialize}; |
7 | use std::error::Error; | ||
8 | 8 | ||
9 | pub fn show_message( | 9 | pub 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 | |||
46 | pub(crate) fn request_new<R>(id: RequestId, params: R::Params) -> Request | ||
47 | where | ||
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 | }; |
31 | pub use lsp_utils::show_message; | ||
32 | use lsp_utils::{is_canceled, notification_cast, notification_is, notification_new, request_new}; | ||
33 | use ra_progress::{ | ||
34 | IsDone, ProgressStatus, U32Progress, U32ProgressReport, U32ProgressSource, U32ProgressStatus, | ||
35 | }; | ||
36 | |||
37 | const FLYCHECK_PROGRESS_TOKEN: &str = "rustAnalyzer/flycheck"; | ||
38 | const ROOTS_SCANNED_PROGRESS_TOKEN: &str = "rustAnalyzer/rootsScanned"; | ||
39 | 32 | ||
40 | pub fn main_loop(config: Config, connection: Connection) -> Result<()> { | 33 | pub 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)] |
189 | enum Task { | 170 | enum 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)] | ||
205 | enum ProgressReport { | ||
206 | Flycheck(ProgressStatus<(), String>), | ||
207 | RootsScanned(U32ProgressStatus), | ||
208 | } | 180 | } |
209 | 181 | ||
210 | impl fmt::Debug for Event { | 182 | impl 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)] | ||
657 | enum ProgressState { | ||
658 | Start, | ||
659 | Report, | ||
660 | End, | ||
661 | } | ||
662 | |||
663 | fn percentage(done: usize, total: usize) -> f64 { | ||
664 | (done as f64 / total.max(1) as f64) * 100.0 | ||
665 | } | ||
666 | |||
706 | fn report_progress( | 667 | fn 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 | ||
901 | pub 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 | |||
912 | fn is_canceled(e: &Box<dyn std::error::Error + Send + Sync>) -> bool { | ||
913 | e.downcast_ref::<Canceled>().is_some() | ||
914 | } | ||
915 | |||
916 | fn notification_is<N: lsp_types::notification::Notification>(notification: &Notification) -> bool { | ||
917 | notification.method == N::METHOD | ||
918 | } | ||
919 | |||
920 | fn notification_cast<N>(notification: Notification) -> std::result::Result<N::Params, Notification> | ||
921 | where | ||
922 | N: lsp_types::notification::Notification, | ||
923 | N::Params: DeserializeOwned, | ||
924 | { | ||
925 | notification.extract(N::METHOD) | ||
926 | } | ||
927 | |||
928 | fn notification_new<N>(params: N::Params) -> Notification | ||
929 | where | ||
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)] |
937 | mod tests { | 868 | mod 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 | } |