Skip to content
This repository was archived by the owner on Dec 29, 2022. It is now read-only.

Commit 8ab908b

Browse files
committed
Use window/progress notifications for build progress
1 parent 5d3f9e1 commit 8ab908b

File tree

11 files changed

+442
-160
lines changed

11 files changed

+442
-160
lines changed

contributing.md

+8-8
Original file line numberDiff line numberDiff line change
@@ -306,14 +306,14 @@ The RLS uses some custom extensions to the Language Server Protocol.
306306
These are all sent from the RLS to an LSP client and are only used to improve
307307
the user experience by showing progress indicators.
308308

309-
310-
* `rustDocument/beginBuild`: notification, no arguments. Sent before a
311-
build starts.
312-
* `rustDocument/diagnosticsBegin`: notification, no arguments. Sent before
313-
indexing or any diagnostics from a build are sent (build is likely in progress).
314-
* `rustDocument/diagnosticsEnd`: notification, no arguments. Sent when a build
315-
is complete (successfully or not, or even skipped) and all post-build analysis
316-
by the RLS is complete.
309+
* `window/progress`: notification, `title: "Build"`. Sent before build starts.
310+
* `window/progress`: notification with `title: "Build"`, repeated for each compile target.
311+
* When total amount of work is not known, has field `message` set to the current crate name.
312+
* When total amount of work is known, has field `percentage` set to how much of build has started.
313+
* `window/progress`: notification, `title: "Build"`, `"done": true`. Sent when build ends.
314+
* `window/progress`: notification, `title: "Diagnostics"`. Sent before analysis of build starts.
315+
* ... standard LSP `publishDiagnostics`
316+
* `window/progress`: notification, `title: "Diagnostics"`, `"done": true`. Sent when analysis ends.
317317

318318
#### LSP Client to RLS
319319

src/actions/mod.rs

+9-33
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,12 @@ use url::Url;
2121
use span;
2222
use Span;
2323

24-
use actions::post_build::{BuildResults, PostBuildHandler, Notifier};
24+
use actions::post_build::{BuildResults, PostBuildHandler};
25+
use actions::progress::{BuildProgressNotifier, BuildDiagnosticsNotifier};
2526
use build::*;
2627
use lsp_data;
2728
use lsp_data::*;
28-
use lsp_data::notification::{PublishDiagnostics, ShowMessage};
29-
use server::{Output, Notification};
29+
use server::Output;
3030

3131
use std::collections::HashMap;
3232
use std::path::{Path, PathBuf};
@@ -57,6 +57,7 @@ pub mod work_pool;
5757
pub mod post_build;
5858
pub mod requests;
5959
pub mod notifications;
60+
pub mod progress;
6061

6162
/// Persistent context shared across all requests and notifications.
6263
pub enum ActionContext {
@@ -210,29 +211,6 @@ impl InitActionContext {
210211
}
211212

212213
fn build<O: Output>(&self, project_path: &Path, priority: BuildPriority, out: &O) {
213-
struct BuildNotifier<O: Output> {
214-
out: O,
215-
active_build_count: Arc<AtomicUsize>,
216-
}
217-
218-
impl<O: Output> Notifier for BuildNotifier<O> {
219-
fn notify_begin(&self) {
220-
self.out.notify(Notification::<DiagnosticsBegin>::new(()));
221-
}
222-
fn notify_end(&self) {
223-
self.active_build_count.fetch_sub(1, Ordering::SeqCst);
224-
self.out.notify(Notification::<DiagnosticsEnd>::new(()));
225-
}
226-
fn notify_publish(&self, params: PublishDiagnosticsParams) {
227-
self.out.notify(Notification::<PublishDiagnostics>::new(params));
228-
}
229-
fn notify_error(&self, msg: &str) {
230-
self.out.notify(Notification::<ShowMessage>::new(lsp_data::ShowMessageParams {
231-
typ: lsp_data::MessageType::Error,
232-
message: msg.to_owned(),
233-
}));
234-
}
235-
}
236214

237215
let pbh = {
238216
let config = self.config.lock().unwrap();
@@ -242,18 +220,17 @@ impl InitActionContext {
242220
project_path: project_path.to_owned(),
243221
show_warnings: config.show_warnings,
244222
use_black_list: config.use_crate_blacklist,
245-
notifier: Box::new(BuildNotifier {
246-
out: out.clone(),
247-
active_build_count: self.active_build_count.clone(),
248-
}),
223+
active_build_count: self.active_build_count.clone(),
224+
notifier: Box::new(BuildDiagnosticsNotifier::new(out.clone())),
249225
blocked_threads: vec![],
250226
}
251227
};
252228

253-
out.notify(Notification::<BeginBuild>::new(()));
229+
let notifier = Box::new(BuildProgressNotifier::new(out.clone()));
230+
254231
self.active_build_count.fetch_add(1, Ordering::SeqCst);
255232
self.build_queue
256-
.request_build(project_path, priority, pbh);
233+
.request_build(project_path, priority, notifier, pbh);
257234
}
258235

259236
fn build_current_project<O: Output>(&self, priority: BuildPriority, out: &O) {
@@ -387,7 +364,6 @@ impl<'ctx> FileWatch<'ctx> {
387364
}
388365
}
389366

390-
391367
#[cfg(test)]
392368
mod test {
393369
use super::*;

src/actions/post_build.rs

+11-16
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,12 @@
1515
use std::collections::HashMap;
1616
use std::path::{Path, PathBuf};
1717
use std::sync::{Arc, Mutex};
18+
use std::sync::atomic::{AtomicUsize, Ordering};
1819
use std::thread;
1920

2021
use build::BuildResult;
2122
use lsp_data::{ls_util, PublishDiagnosticsParams};
23+
use actions::progress::DiagnosticsNotifier;
2224

2325
use analysis::AnalysisHost;
2426
use data::Analysis;
@@ -35,28 +37,20 @@ pub struct PostBuildHandler {
3537
pub project_path: PathBuf,
3638
pub show_warnings: bool,
3739
pub use_black_list: bool,
38-
pub notifier: Box<Notifier>,
40+
pub active_build_count: Arc<AtomicUsize>,
41+
pub notifier: Box<DiagnosticsNotifier>,
3942
pub blocked_threads: Vec<thread::Thread>,
4043
}
4144

42-
/// Trait for communication back to the rest of the RLS (and on to the client).
43-
// This trait only really exists to work around the object safety rules (Output
44-
// is not object-safe).
45-
pub trait Notifier: Send {
46-
fn notify_begin(&self);
47-
fn notify_end(&self);
48-
fn notify_publish(&self, PublishDiagnosticsParams);
49-
fn notify_error(&self, &str);
50-
}
5145

5246
impl PostBuildHandler {
5347
pub fn handle(mut self, result: BuildResult) {
54-
self.notifier.notify_begin();
5548

5649
match result {
5750
BuildResult::Success(cwd, messages, new_analysis) => {
5851
thread::spawn(move || {
5952
trace!("build - Success");
53+
self.notifier.notify_begin_diagnostics();
6054

6155
// Emit appropriate diagnostics using the ones from build.
6256
self.handle_messages(&cwd, &messages);
@@ -74,17 +68,18 @@ impl PostBuildHandler {
7468
t.unpark();
7569
}
7670

77-
self.notifier.notify_end();
71+
self.notifier.notify_end_diagnostics();
72+
self.active_build_count.fetch_sub(1, Ordering::SeqCst);
7873
});
7974
}
8075
BuildResult::Squashed => {
8176
trace!("build - Squashed");
82-
self.notifier.notify_end();
77+
self.active_build_count.fetch_sub(1, Ordering::SeqCst);
8378
}
8479
BuildResult::Err => {
8580
trace!("build - Error");
86-
self.notifier.notify_error("There was an error trying to build, RLS features will be limited. Try running `cargo check` for more information.");
87-
self.notifier.notify_end();
81+
self.notifier.notify_error_diagnostics("There was an error trying to build, RLS features will be limited. Try running `cargo check` for more information.");
82+
self.active_build_count.fetch_sub(1, Ordering::SeqCst);
8883
}
8984
}
9085
}
@@ -159,7 +154,7 @@ impl PostBuildHandler {
159154
.collect(),
160155
};
161156

162-
self.notifier.notify_publish(params);
157+
self.notifier.notify_publish_diagnostics(params);
163158
}
164159
}
165160
}

src/actions/progress.rs

+135
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use std::sync::atomic::{AtomicUsize, Ordering};
12+
13+
use lsp_data::{ProgressParams, PublishDiagnosticsParams, Progress, ShowMessageParams, MessageType};
14+
use server::{Output, Notification};
15+
use ls_types::notification::{PublishDiagnostics, ShowMessage};
16+
17+
/// Trait for communication of build progress back to the client.
18+
pub trait ProgressNotifier: Send {
19+
fn notify_begin_progress(&self);
20+
fn notify_progress(&self, update: ProgressUpdate);
21+
fn notify_end_progress(&self);
22+
}
23+
24+
/// Kinds of progress updates
25+
pub enum ProgressUpdate {
26+
Message(String),
27+
Percentage(f64),
28+
}
29+
30+
/// Trait for communication of diagnostics (i.e. build results) back to the rest of
31+
/// the RLS (and on to the client).
32+
// This trait only really exists to work around the object safety rules (Output
33+
// is not object-safe).
34+
pub trait DiagnosticsNotifier: Send {
35+
fn notify_begin_diagnostics(&self);
36+
fn notify_publish_diagnostics(&self, PublishDiagnosticsParams);
37+
fn notify_end_diagnostics(&self);
38+
fn notify_error_diagnostics(&self, msg: &str);
39+
}
40+
41+
/// Generate a new progress params with a unique ID and the given title.
42+
fn new_progress_params(title: String) -> ProgressParams {
43+
44+
// counter to generate unique ID for each chain-of-progress notifications.
45+
lazy_static! {
46+
static ref PROGRESS_ID_COUNTER: AtomicUsize = {
47+
AtomicUsize::new(0)
48+
};
49+
}
50+
51+
ProgressParams {
52+
id: format!("progress_{}", PROGRESS_ID_COUNTER.fetch_add(1, Ordering::SeqCst)),
53+
title: Some(title),
54+
message: None,
55+
percentage: None,
56+
done: None,
57+
}
58+
}
59+
60+
/// Notifier of progress for the build (window/progress notifications).
61+
/// the same instance is used for the entirety of one single build.
62+
pub struct BuildProgressNotifier<O: Output> {
63+
out: O,
64+
// these params are used as a template and are cloned for each
65+
// message that is actually notified.
66+
progress_params: ProgressParams,
67+
}
68+
69+
impl<O: Output> BuildProgressNotifier<O> {
70+
pub fn new(out: O) -> BuildProgressNotifier<O> {
71+
BuildProgressNotifier {
72+
out,
73+
progress_params: new_progress_params("Build".into()),
74+
}
75+
}
76+
}
77+
78+
impl<O: Output> ProgressNotifier for BuildProgressNotifier<O> {
79+
fn notify_begin_progress(&self) {
80+
let params = self.progress_params.clone();
81+
self.out.notify(Notification::<Progress>::new(params));
82+
}
83+
fn notify_progress(&self, update: ProgressUpdate) {
84+
let mut params = self.progress_params.clone();
85+
match update {
86+
ProgressUpdate::Message(s) => params.message = Some(s),
87+
ProgressUpdate::Percentage(p) => params.percentage = Some(p),
88+
}
89+
self.out.notify(Notification::<Progress>::new(params));
90+
}
91+
fn notify_end_progress(&self) {
92+
let mut params = self.progress_params.clone();
93+
params.done = Some(true);
94+
self.out.notify(Notification::<Progress>::new(params));
95+
}
96+
}
97+
98+
99+
/// Notifier of diagnostics after the build has completed.
100+
pub struct BuildDiagnosticsNotifier<O: Output> {
101+
out: O,
102+
// these params are used as a template and are cloned for each
103+
// message that is actually notified.
104+
progress_params: ProgressParams,
105+
}
106+
107+
impl<O: Output> BuildDiagnosticsNotifier<O> {
108+
pub fn new(out: O) -> BuildDiagnosticsNotifier<O> {
109+
BuildDiagnosticsNotifier {
110+
out,
111+
progress_params: new_progress_params("Diagnostics".into()),
112+
}
113+
}
114+
}
115+
116+
impl<O: Output> DiagnosticsNotifier for BuildDiagnosticsNotifier<O> {
117+
fn notify_begin_diagnostics(&self) {
118+
let params = self.progress_params.clone();
119+
self.out.notify(Notification::<Progress>::new(params));
120+
}
121+
fn notify_publish_diagnostics(&self, params: PublishDiagnosticsParams) {
122+
self.out.notify(Notification::<PublishDiagnostics>::new(params));
123+
}
124+
fn notify_end_diagnostics(&self) {
125+
let mut params = self.progress_params.clone();
126+
params.done = Some(true);
127+
self.out.notify(Notification::<Progress>::new(params));
128+
}
129+
fn notify_error_diagnostics(&self, msg: &str) {
130+
self.out.notify(Notification::<ShowMessage>::new(ShowMessageParams {
131+
typ: MessageType::Error,
132+
message: msg.to_owned(),
133+
}));
134+
}
135+
}

0 commit comments

Comments
 (0)