Skip to content

Commit

Permalink
Migrate to showing prime chaches progress
Browse files Browse the repository at this point in the history
This is a part of rust-lang#4074
  • Loading branch information
Veetaha committed May 10, 2020
1 parent f1cb5b8 commit 6308f4e
Show file tree
Hide file tree
Showing 6 changed files with 227 additions and 101 deletions.
7 changes: 5 additions & 2 deletions crates/ra_ide/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -244,8 +244,11 @@ impl Analysis {
self.with_db(|db| status::status(&*db))
}

pub fn prime_caches(&self, files: Vec<FileId>) -> Cancelable<()> {
self.with_db(|db| prime_caches::prime_caches(db, files))
pub fn prime_caches<P>(&self, files: Vec<FileId>, report_progress: P) -> Cancelable<()>
where
P: FnMut(usize) + std::panic::UnwindSafe,
{
self.with_db(|db| prime_caches::prime_caches(db, files, report_progress))
}

/// Gets the text of the source file.
Expand Down
9 changes: 7 additions & 2 deletions crates/ra_ide/src/prime_caches.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,13 @@
use crate::{FileId, RootDatabase};

pub(crate) fn prime_caches(db: &RootDatabase, files: Vec<FileId>) {
for file in files {
pub(crate) fn prime_caches(
db: &RootDatabase,
files: Vec<FileId>,
mut report_progress: impl FnMut(usize),
) {
for (i, file) in files.into_iter().enumerate() {
let _ = crate::syntax_highlighting::highlight(db, file, None);
report_progress(i);
}
}
133 changes: 37 additions & 96 deletions crates/rust-analyzer/src/main_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
mod handlers;
mod subscriptions;
pub(crate) mod pending_requests;
mod progress;
mod lsp_utils;

use std::{
borrow::Cow,
Expand All @@ -20,11 +22,7 @@ use std::{
use crossbeam_channel::{never, select, unbounded, RecvError, Sender};
use itertools::Itertools;
use lsp_server::{Connection, ErrorCode, Message, Notification, Request, RequestId, Response};
use lsp_types::{
DidChangeTextDocumentParams, NumberOrString, TextDocumentContentChangeEvent, WorkDoneProgress,
WorkDoneProgressBegin, WorkDoneProgressCreateParams, WorkDoneProgressEnd,
WorkDoneProgressReport,
};
use lsp_types::{DidChangeTextDocumentParams, NumberOrString, TextDocumentContentChangeEvent};
use ra_flycheck::{url_from_path_with_drive_lowercasing, CheckTask};
use ra_ide::{Canceled, FileId, LibraryData, LineIndex, SourceRootId};
use ra_prof::profile;
Expand All @@ -47,6 +45,9 @@ use crate::{
world::{WorldSnapshot, WorldState},
Result,
};
pub use lsp_utils::show_message;
use lsp_utils::{is_canceled, notification_cast, notification_is, notification_new, request_new};
use progress::{IsDone, PrimeCachesProgressNotifier, WorkspaceAnalysisProgressNotifier};

#[derive(Debug)]
pub struct LspError {
Expand Down Expand Up @@ -93,6 +94,7 @@ pub fn main_loop(ws_roots: Vec<PathBuf>, config: Config, connection: Connection)
}

let mut loop_state = LoopState::default();

let mut world_state = {
let workspaces = {
// FIXME: support dynamic workspace loading.
Expand Down Expand Up @@ -174,6 +176,11 @@ pub fn main_loop(ws_roots: Vec<PathBuf>, config: Config, connection: Connection)

loop_state.roots_total = world_state.vfs.read().n_roots();
loop_state.roots_scanned = 0;
loop_state.roots_progress = Some(WorkspaceAnalysisProgressNotifier::begin(
connection.sender.clone(),
loop_state.next_request_id(),
loop_state.roots_total,
));

let pool = ThreadPool::default();
let (task_sender, task_receiver) = unbounded::<Task>();
Expand Down Expand Up @@ -299,7 +306,7 @@ struct LoopState {
in_flight_libraries: usize,
pending_libraries: Vec<(SourceRootId, Vec<(FileId, RelativePathBuf, Arc<String>)>)>,
workspace_loaded: bool,
roots_progress_reported: Option<usize>,
roots_progress: Option<WorkspaceAnalysisProgressNotifier>,
roots_scanned: usize,
roots_total: usize,
configuration_request_id: Option<RequestId>,
Expand Down Expand Up @@ -428,7 +435,7 @@ fn loop_turn(
}

if show_progress {
send_startup_progress(&connection.sender, loop_state);
send_workspace_analisys_progress(loop_state);
}

if state_changed && loop_state.workspace_loaded {
Expand All @@ -441,7 +448,22 @@ fn loop_turn(
pool.execute({
let subs = loop_state.subscriptions.subscriptions();
let snap = world_state.snapshot();
move || snap.analysis().prime_caches(subs).unwrap_or_else(|_: Canceled| ())

let total = subs.len();

let mut progress = PrimeCachesProgressNotifier::begin(
connection.sender.clone(),
loop_state.next_request_id(),
total,
);

move || {
snap.analysis()
.prime_caches(subs, move |i| {
progress.report(i + 1);
})
.unwrap_or_else(|_: Canceled| ());
}
});
}

Expand Down Expand Up @@ -774,54 +796,12 @@ fn on_diagnostic_task(task: DiagnosticTask, msg_sender: &Sender<Message>, state:
}
}

fn send_startup_progress(sender: &Sender<Message>, loop_state: &mut LoopState) {
let total: usize = loop_state.roots_total;
let prev = loop_state.roots_progress_reported;
let progress = loop_state.roots_scanned;
loop_state.roots_progress_reported = Some(progress);

match (prev, loop_state.workspace_loaded) {
(None, false) => {
let work_done_progress_create = request_new::<req::WorkDoneProgressCreate>(
loop_state.next_request_id(),
WorkDoneProgressCreateParams {
token: req::ProgressToken::String("rustAnalyzer/startup".into()),
},
);
sender.send(work_done_progress_create.into()).unwrap();
send_startup_progress_notif(
sender,
WorkDoneProgress::Begin(WorkDoneProgressBegin {
title: "rust-analyzer".into(),
cancellable: None,
message: Some(format!("{}/{} packages", progress, total)),
percentage: Some(100.0 * progress as f64 / total as f64),
}),
);
fn send_workspace_analisys_progress(loop_state: &mut LoopState) {
if let Some(progress) = &mut loop_state.roots_progress {
if loop_state.workspace_loaded || progress.report(loop_state.roots_scanned) == IsDone(true)
{
loop_state.roots_progress = None;
}
(Some(prev), false) if progress != prev => send_startup_progress_notif(
sender,
WorkDoneProgress::Report(WorkDoneProgressReport {
cancellable: None,
message: Some(format!("{}/{} packages", progress, total)),
percentage: Some(100.0 * progress as f64 / total as f64),
}),
),
(_, true) => send_startup_progress_notif(
sender,
WorkDoneProgress::End(WorkDoneProgressEnd {
message: Some(format!("rust-analyzer loaded, {} packages", progress)),
}),
),
_ => {}
}

fn send_startup_progress_notif(sender: &Sender<Message>, work_done_progress: WorkDoneProgress) {
let notif = notification_new::<req::Progress>(req::ProgressParams {
token: req::ProgressToken::String("rustAnalyzer/startup".into()),
value: req::ProgressParamsValue::WorkDone(work_done_progress),
});
sender.send(notif.into()).unwrap();
}
}

Expand Down Expand Up @@ -944,7 +924,7 @@ where
}
}
Err(e) => {
if is_canceled(&e) {
if is_canceled(&*e) {
Response::new_err(
id,
ErrorCode::ContentModified as i32,
Expand All @@ -971,7 +951,7 @@ fn update_file_notifications_on_threadpool(
for file_id in subscriptions {
match handlers::publish_diagnostics(&world, file_id) {
Err(e) => {
if !is_canceled(&e) {
if !is_canceled(&*e) {
log::error!("failed to compute diagnostics: {:?}", e);
}
}
Expand All @@ -984,45 +964,6 @@ fn update_file_notifications_on_threadpool(
}
}

pub fn show_message(typ: req::MessageType, message: impl Into<String>, sender: &Sender<Message>) {
let message = message.into();
let params = req::ShowMessageParams { typ, message };
let not = notification_new::<req::ShowMessage>(params);
sender.send(not.into()).unwrap();
}

fn is_canceled(e: &Box<dyn std::error::Error + Send + Sync>) -> bool {
e.downcast_ref::<Canceled>().is_some()
}

fn notification_is<N: lsp_types::notification::Notification>(notification: &Notification) -> bool {
notification.method == N::METHOD
}

fn notification_cast<N>(notification: Notification) -> std::result::Result<N::Params, Notification>
where
N: lsp_types::notification::Notification,
N::Params: DeserializeOwned,
{
notification.extract(N::METHOD)
}

fn notification_new<N>(params: N::Params) -> Notification
where
N: lsp_types::notification::Notification,
N::Params: Serialize,
{
Notification::new(N::METHOD.to_string(), params)
}

fn request_new<R>(id: RequestId, params: R::Params) -> Request
where
R: lsp_types::request::Request,
R::Params: Serialize,
{
Request::new(id, R::METHOD.to_string(), params)
}

#[cfg(test)]
mod tests {
use std::borrow::Cow;
Expand Down
47 changes: 47 additions & 0 deletions crates/rust-analyzer/src/main_loop/lsp_utils.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
use crate::req;
use crossbeam_channel::Sender;
use lsp_server::{Message, Notification, Request, RequestId};
use ra_db::Canceled;
use serde::{de::DeserializeOwned, Serialize};
use std::error::Error;

pub fn show_message(typ: req::MessageType, message: impl Into<String>, sender: &Sender<Message>) {
let message = message.into();
let params = req::ShowMessageParams { typ, message };
let not = notification_new::<req::ShowMessage>(params);
sender.send(not.into()).unwrap();
}

pub(crate) fn is_canceled(e: &(dyn Error + 'static)) -> bool {
e.downcast_ref::<Canceled>().is_some()
}

pub(crate) fn notification_is<N: lsp_types::notification::Notification>(
notification: &Notification,
) -> bool {
notification.method == N::METHOD
}

pub(crate) fn notification_cast<N>(notification: Notification) -> Result<N::Params, Notification>
where
N: lsp_types::notification::Notification,
N::Params: DeserializeOwned,
{
notification.extract(N::METHOD)
}

pub(crate) fn notification_new<N>(params: N::Params) -> Notification
where
N: lsp_types::notification::Notification,
N::Params: Serialize,
{
Notification::new(N::METHOD.to_string(), params)
}

pub(crate) fn request_new<R>(id: RequestId, params: R::Params) -> Request
where
R: lsp_types::request::Request,
R::Params: Serialize,
{
Request::new(id, R::METHOD.to_string(), params)
}
Loading

0 comments on commit 6308f4e

Please sign in to comment.