Skip to content

Commit 8fe20b1

Browse files
committed
More robust status notifications
1 parent 9143e39 commit 8fe20b1

File tree

11 files changed

+165
-150
lines changed

11 files changed

+165
-150
lines changed

crates/rust-analyzer/src/config.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -445,8 +445,8 @@ impl Config {
445445
pub fn hover_actions(&self) -> bool {
446446
self.experimental("hoverActions")
447447
}
448-
pub fn status_notification(&self) -> bool {
449-
self.experimental("statusNotification")
448+
pub fn server_status_notification(&self) -> bool {
449+
self.experimental("serverStatusNotification")
450450
}
451451

452452
pub fn publish_diagnostics(&self) -> bool {

crates/rust-analyzer/src/global_state.rs

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ use crate::{
2323
document::DocumentData,
2424
from_proto,
2525
line_index::{LineEndings, LineIndex},
26+
lsp_ext,
2627
main_loop::Task,
2728
op_queue::OpQueue,
2829
reload::SourceRootConfig,
@@ -32,20 +33,6 @@ use crate::{
3233
Result,
3334
};
3435

35-
#[derive(Eq, PartialEq, Copy, Clone)]
36-
pub(crate) enum Status {
37-
Loading,
38-
Ready { partial: bool },
39-
Invalid,
40-
NeedsReload,
41-
}
42-
43-
impl Default for Status {
44-
fn default() -> Self {
45-
Status::Loading
46-
}
47-
}
48-
4936
// Enforces drop order
5037
pub(crate) struct Handle<H, C> {
5138
pub(crate) handle: H,
@@ -73,7 +60,7 @@ pub(crate) struct GlobalState {
7360
pub(crate) mem_docs: FxHashMap<VfsPath, DocumentData>,
7461
pub(crate) semantic_tokens_cache: Arc<Mutex<FxHashMap<Url, SemanticTokens>>>,
7562
pub(crate) shutdown_requested: bool,
76-
pub(crate) status: Status,
63+
pub(crate) last_reported_status: Option<lsp_ext::ServerStatusParams>,
7764
pub(crate) source_root_config: SourceRootConfig,
7865
pub(crate) proc_macro_client: Option<ProcMacroClient>,
7966

@@ -83,6 +70,7 @@ pub(crate) struct GlobalState {
8370

8471
pub(crate) vfs: Arc<RwLock<(vfs::Vfs, FxHashMap<FileId, LineEndings>)>>,
8572
pub(crate) vfs_config_version: u32,
73+
pub(crate) vfs_progress_config_version: u32,
8674
pub(crate) vfs_progress_n_total: usize,
8775
pub(crate) vfs_progress_n_done: usize,
8876

@@ -141,7 +129,7 @@ impl GlobalState {
141129
mem_docs: FxHashMap::default(),
142130
semantic_tokens_cache: Arc::new(Default::default()),
143131
shutdown_requested: false,
144-
status: Status::default(),
132+
last_reported_status: None,
145133
source_root_config: SourceRootConfig::default(),
146134
proc_macro_client: None,
147135

@@ -151,14 +139,15 @@ impl GlobalState {
151139

152140
vfs: Arc::new(RwLock::new((vfs::Vfs::default(), FxHashMap::default()))),
153141
vfs_config_version: 0,
142+
vfs_progress_config_version: 0,
154143
vfs_progress_n_total: 0,
155144
vfs_progress_n_done: 0,
156145

157146
workspaces: Arc::new(Vec::new()),
158147
fetch_workspaces_queue: OpQueue::default(),
159148
workspace_build_data: None,
160-
fetch_build_data_queue: OpQueue::default(),
161149

150+
fetch_build_data_queue: OpQueue::default(),
162151
latest_requests: Default::default(),
163152
}
164153
}

crates/rust-analyzer/src/lsp_ext.rs

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -241,26 +241,26 @@ pub struct SsrParams {
241241
pub selections: Vec<lsp_types::Range>,
242242
}
243243

244-
pub enum StatusNotification {}
244+
pub enum ServerStatusNotification {}
245245

246-
#[derive(Serialize, Deserialize)]
247-
#[serde(rename_all = "camelCase")]
248-
pub enum Status {
249-
Loading,
250-
ReadyPartial,
251-
Ready,
252-
NeedsReload,
253-
Invalid,
246+
impl Notification for ServerStatusNotification {
247+
type Params = ServerStatusParams;
248+
const METHOD: &'static str = "experimental/serverStatus";
254249
}
255250

256-
#[derive(Deserialize, Serialize)]
257-
pub struct StatusParams {
258-
pub status: Status,
251+
#[derive(Deserialize, Serialize, PartialEq, Eq, Clone)]
252+
pub struct ServerStatusParams {
253+
pub health: Health,
254+
pub quiescent: bool,
255+
pub message: Option<String>,
259256
}
260257

261-
impl Notification for StatusNotification {
262-
type Params = StatusParams;
263-
const METHOD: &'static str = "rust-analyzer/status";
258+
#[derive(Serialize, Deserialize, Clone, Copy, PartialEq, Eq)]
259+
#[serde(rename_all = "camelCase")]
260+
pub enum Health {
261+
Ok,
262+
Warning,
263+
Error,
264264
}
265265

266266
pub enum CodeActionRequest {}

crates/rust-analyzer/src/main_loop.rs

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use crate::{
2121
dispatch::{NotificationDispatcher, RequestDispatcher},
2222
document::DocumentData,
2323
from_proto,
24-
global_state::{file_id_to_url, url_to_file_id, GlobalState, Status},
24+
global_state::{file_id_to_url, url_to_file_id, GlobalState},
2525
handlers, lsp_ext,
2626
lsp_utils::{apply_document_changes, is_canceled, notification_is, Progress},
2727
reload::{BuildDataProgress, ProjectWorkspaceProgress},
@@ -189,7 +189,7 @@ impl GlobalState {
189189
log::info!("task queue len: {}", task_queue_len);
190190
}
191191

192-
let mut new_status = self.status;
192+
let was_quiescent = self.is_quiescent();
193193
match event {
194194
Event::Lsp(msg) => match msg {
195195
lsp_server::Message::Request(req) => self.on_request(loop_start, req)?,
@@ -314,9 +314,12 @@ impl GlobalState {
314314
}
315315
}
316316
vfs::loader::Message::Progress { n_total, n_done, config_version } => {
317+
always!(config_version <= self.vfs_config_version);
318+
319+
self.vfs_progress_config_version = config_version;
317320
self.vfs_progress_n_total = n_total;
318321
self.vfs_progress_n_done = n_done;
319-
always!(config_version <= self.vfs_config_version);
322+
320323
let state = if n_done == 0 {
321324
Progress::Begin
322325
} else if n_done < n_total {
@@ -406,18 +409,14 @@ impl GlobalState {
406409
}
407410

408411
let state_changed = self.process_changes();
409-
let prev_status = self.status;
410-
if prev_status != new_status {
411-
self.transition(new_status);
412-
}
413-
let is_ready = matches!(self.status, Status::Ready { .. });
414-
if prev_status == Status::Loading && is_ready {
412+
413+
if self.is_quiescent() && !was_quiescent {
415414
for flycheck in &self.flycheck {
416415
flycheck.update();
417416
}
418417
}
419418

420-
if is_ready && (state_changed || prev_status == Status::Loading) {
419+
if self.is_quiescent() && (!was_quiescent || state_changed) {
421420
self.update_file_notifications_on_threadpool();
422421

423422
// Refresh semantic tokens if the client supports it.
@@ -451,6 +450,8 @@ impl GlobalState {
451450
}
452451
self.fetch_build_data_if_needed();
453452

453+
self.report_new_status_if_needed();
454+
454455
let loop_duration = loop_start.elapsed();
455456
if loop_duration > Duration::from_millis(100) {
456457
log::warn!("overly long loop turn: {:?}", loop_duration);
@@ -477,7 +478,8 @@ impl GlobalState {
477478
return Ok(());
478479
}
479480

480-
if self.status == Status::Loading && req.method != "shutdown" {
481+
// Avoid flashing a bunch of unresolved references during initial load.
482+
if self.workspaces.is_empty() && !self.is_quiescent() {
481483
self.respond(lsp_server::Response::new_err(
482484
req.id,
483485
// FIXME: i32 should impl From<ErrorCode> (from() guarantees lossless conversion)

crates/rust-analyzer/src/op_queue.rs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,27 @@
22
//! at a time.
33
44
pub(crate) struct OpQueue<Args, Output> {
5-
op_scheduled: Option<Args>,
5+
op_requested: Option<Args>,
66
op_in_progress: bool,
77
last_op_result: Output,
88
}
99

1010
impl<Args, Output: Default> Default for OpQueue<Args, Output> {
1111
fn default() -> Self {
12-
Self { op_scheduled: None, op_in_progress: false, last_op_result: Default::default() }
12+
Self { op_requested: None, op_in_progress: false, last_op_result: Default::default() }
1313
}
1414
}
1515

1616
impl<Args, Output> OpQueue<Args, Output> {
1717
pub(crate) fn request_op(&mut self, data: Args) {
18-
self.op_scheduled = Some(data);
18+
self.op_requested = Some(data);
1919
}
2020
pub(crate) fn should_start_op(&mut self) -> Option<Args> {
2121
if self.op_in_progress {
2222
return None;
2323
}
24-
self.op_in_progress = self.op_scheduled.is_some();
25-
self.op_scheduled.take()
24+
self.op_in_progress = self.op_requested.is_some();
25+
self.op_requested.take()
2626
}
2727
pub(crate) fn op_completed(&mut self, result: Output) {
2828
assert!(self.op_in_progress);
@@ -34,4 +34,10 @@ impl<Args, Output> OpQueue<Args, Output> {
3434
pub(crate) fn last_op_result(&self) -> &Output {
3535
&self.last_op_result
3636
}
37+
pub(crate) fn op_in_progress(&self) -> bool {
38+
self.op_in_progress
39+
}
40+
pub(crate) fn op_requested(&self) -> bool {
41+
self.op_requested.is_some()
42+
}
3743
}

0 commit comments

Comments
 (0)