Automatically reload project info on Cargo.toml changes

This commit is contained in:
Aleksey Kladov
2020-07-10 15:27:34 +02:00
parent 5fa8f8e376
commit d0a8f6a3eb
7 changed files with 57 additions and 28 deletions

View File

@@ -29,6 +29,7 @@ pub struct Config {
pub files: FilesConfig,
pub notifications: NotificationsConfig,
pub cargo_autoreload: bool,
pub cargo: CargoConfig,
pub rustfmt: RustfmtConfig,
pub flycheck: Option<FlycheckConfig>,
@@ -141,6 +142,7 @@ impl Config {
files: FilesConfig { watcher: FilesWatcher::Notify, exclude: Vec::new() },
notifications: NotificationsConfig { cargo_toml_not_found: true },
cargo_autoreload: true,
cargo: CargoConfig::default(),
rustfmt: RustfmtConfig::Rustfmt { extra_args: Vec::new() },
flycheck: Some(FlycheckConfig::CargoCommand {
@@ -189,6 +191,7 @@ impl Config {
};
self.notifications =
NotificationsConfig { cargo_toml_not_found: data.notifications_cargoTomlNotFound };
self.cargo_autoreload = data.cargo_autoreload;
self.cargo = CargoConfig {
no_default_features: data.cargo_noDefaultFeatures,
all_features: data.cargo_allFeatures,
@@ -364,6 +367,7 @@ config_data! {
struct ConfigData {
callInfo_full: bool = true,
cargo_autoreload: bool = true,
cargo_allFeatures: bool = false,
cargo_features: Vec<String> = Vec::new(),
cargo_loadOutDirsFromCheck: bool = false,

View File

@@ -314,19 +314,6 @@ impl GlobalState {
Ok(())
}
fn transition(&mut self, new_status: Status) {
self.status = Status::Ready;
if self.config.client_caps.status_notification {
let lsp_status = match new_status {
Status::Loading => lsp_ext::Status::Loading,
Status::Ready => lsp_ext::Status::Ready,
Status::Invalid => lsp_ext::Status::Invalid,
Status::NeedsReload => lsp_ext::Status::NeedsReload,
};
self.send_notification::<lsp_ext::StatusNotification>(lsp_status);
}
}
fn on_request(&mut self, request_received: Instant, req: Request) -> Result<()> {
self.register_request(&req, request_received);
@@ -441,12 +428,7 @@ impl GlobalState {
if let Some(flycheck) = &this.flycheck {
flycheck.handle.update();
}
let uri = params.text_document.uri.as_str();
if uri.ends_with("Cargo.toml") || uri.ends_with("Cargo.lock") {
if matches!(this.status, Status::Ready | Status::Invalid) {
this.transition(Status::NeedsReload);
}
}
this.maybe_refresh(params.text_document.uri.as_str());
Ok(())
})?
.on::<lsp_types::notification::DidChangeConfiguration>(|this, _params| {

View File

@@ -10,7 +10,8 @@ use vfs::{file_set::FileSetConfig, AbsPath};
use crate::{
config::{Config, FilesWatcher, LinkedProject},
global_state::{GlobalState, Handle},
global_state::{GlobalState, Handle, Status},
lsp_ext,
main_loop::Task,
};
@@ -26,6 +27,32 @@ impl GlobalState {
self.reload_flycheck();
}
}
pub(crate) fn maybe_refresh(&mut self, saved_doc_url: &str) {
if !(saved_doc_url.ends_with("Cargo.toml") || saved_doc_url.ends_with("Cargo.lock")) {
return;
}
match self.status {
Status::Loading | Status::NeedsReload => return,
Status::Ready | Status::Invalid => (),
}
if self.config.cargo_autoreload {
self.fetch_workspaces();
} else {
self.transition(Status::NeedsReload);
}
}
pub(crate) fn transition(&mut self, new_status: Status) {
self.status = new_status;
if self.config.client_caps.status_notification {
let lsp_status = match new_status {
Status::Loading => lsp_ext::Status::Loading,
Status::Ready => lsp_ext::Status::Ready,
Status::Invalid => lsp_ext::Status::Invalid,
Status::NeedsReload => lsp_ext::Status::NeedsReload,
};
self.send_notification::<lsp_ext::StatusNotification>(lsp_status);
}
}
pub(crate) fn fetch_workspaces(&mut self) {
self.task_pool.handle.spawn({
let linked_projects = self.config.linked_projects.clone();
@@ -53,10 +80,13 @@ impl GlobalState {
}
pub(crate) fn switch_workspaces(&mut self, workspaces: Vec<anyhow::Result<ProjectWorkspace>>) {
log::info!("reloading projects: {:?}", self.config.linked_projects);
let mut has_errors = false;
let workspaces = workspaces
.into_iter()
.filter_map(|res| {
res.map_err(|err| {
has_errors = true;
log::error!("failed to load workspace: {:#}", err);
self.show_message(
lsp_types::MessageType::Error,
@@ -67,6 +97,14 @@ impl GlobalState {
})
.collect::<Vec<_>>();
if &*self.workspaces == &workspaces {
return;
}
if !self.workspaces.is_empty() && has_errors {
return;
}
if let FilesWatcher::Client = self.config.files.watcher {
let registration_options = lsp_types::DidChangeWatchedFilesRegistrationOptions {
watchers: workspaces