Move cargo metadata off the main loop

This commit is contained in:
Aleksey Kladov 2020-07-02 16:47:42 +02:00
parent 83f3cdca4f
commit 6c7578bd7a
4 changed files with 56 additions and 43 deletions

View file

@ -150,7 +150,7 @@ impl ProjectManifest {
impl ProjectWorkspace { impl ProjectWorkspace {
pub fn load( pub fn load(
manifest: ProjectManifest, manifest: ProjectManifest,
cargo_features: &CargoConfig, cargo_config: &CargoConfig,
with_sysroot: bool, with_sysroot: bool,
) -> Result<ProjectWorkspace> { ) -> Result<ProjectWorkspace> {
let res = match manifest { let res = match manifest {
@ -166,7 +166,7 @@ impl ProjectWorkspace {
ProjectWorkspace::Json { project } ProjectWorkspace::Json { project }
} }
ProjectManifest::CargoToml(cargo_toml) => { ProjectManifest::CargoToml(cargo_toml) => {
let cargo = CargoWorkspace::from_cargo_metadata(&cargo_toml, cargo_features) let cargo = CargoWorkspace::from_cargo_metadata(&cargo_toml, cargo_config)
.with_context(|| { .with_context(|| {
format!( format!(
"Failed to read Cargo metadata from Cargo.toml file {}", "Failed to read Cargo metadata from Cargo.toml file {}",

View file

@ -21,6 +21,7 @@ use crate::{
lsp_utils::{apply_document_changes, is_canceled, notification_is, Progress}, lsp_utils::{apply_document_changes, is_canceled, notification_is, Progress},
Result, Result,
}; };
use ra_project_model::ProjectWorkspace;
pub fn main_loop(config: Config, connection: Connection) -> Result<()> { pub fn main_loop(config: Config, connection: Connection) -> Result<()> {
log::info!("initial config: {:#?}", config); log::info!("initial config: {:#?}", config);
@ -58,6 +59,7 @@ enum Event {
pub(crate) enum Task { pub(crate) enum Task {
Response(Response), Response(Response),
Diagnostics(Vec<(FileId, Vec<lsp_types::Diagnostic>)>), Diagnostics(Vec<(FileId, Vec<lsp_types::Diagnostic>)>),
Workspaces(Vec<anyhow::Result<ProjectWorkspace>>),
Unit, Unit,
} }
@ -111,6 +113,14 @@ impl GlobalState {
} }
fn run(mut self, inbox: Receiver<lsp_server::Message>) -> Result<()> { fn run(mut self, inbox: Receiver<lsp_server::Message>) -> Result<()> {
if self.config.linked_projects.is_empty() && self.config.notifications.cargo_toml_not_found
{
self.show_message(
lsp_types::MessageType::Error,
"rust-analyzer failed to discover workspace".to_string(),
);
};
let registration_options = lsp_types::TextDocumentRegistrationOptions { let registration_options = lsp_types::TextDocumentRegistrationOptions {
document_selector: Some(vec![ document_selector: Some(vec![
lsp_types::DocumentFilter { lsp_types::DocumentFilter {
@ -140,7 +150,7 @@ impl GlobalState {
|_, _| (), |_, _| (),
); );
self.reload(); self.fetch_workspaces();
while let Some(event) = self.next_event(&inbox) { while let Some(event) = self.next_event(&inbox) {
if let Event::Lsp(lsp_server::Message::Notification(not)) = &event { if let Event::Lsp(lsp_server::Message::Notification(not)) = &event {
@ -182,6 +192,7 @@ impl GlobalState {
self.diagnostics.set_native_diagnostics(file_id, diagnostics) self.diagnostics.set_native_diagnostics(file_id, diagnostics)
} }
} }
Task::Workspaces(workspaces) => self.switch_workspaces(workspaces),
Task::Unit => (), Task::Unit => (),
} }
self.analysis_host.maybe_collect_garbage(); self.analysis_host.maybe_collect_garbage();
@ -320,7 +331,7 @@ impl GlobalState {
self.register_request(&req, request_received); self.register_request(&req, request_received);
RequestDispatcher { req: Some(req), global_state: self } RequestDispatcher { req: Some(req), global_state: self }
.on_sync::<lsp_ext::ReloadWorkspace>(|s, ()| Ok(s.reload()))? .on_sync::<lsp_ext::ReloadWorkspace>(|s, ()| Ok(s.fetch_workspaces()))?
.on_sync::<lsp_ext::JoinLines>(|s, p| handlers::handle_join_lines(s.snapshot(), p))? .on_sync::<lsp_ext::JoinLines>(|s, p| handlers::handle_join_lines(s.snapshot(), p))?
.on_sync::<lsp_ext::OnEnter>(|s, p| handlers::handle_on_enter(s.snapshot(), p))? .on_sync::<lsp_ext::OnEnter>(|s, p| handlers::handle_on_enter(s.snapshot(), p))?
.on_sync::<lsp_types::request::Shutdown>(|_, ()| Ok(()))? .on_sync::<lsp_types::request::Shutdown>(|_, ()| Ok(()))?

View file

@ -11,6 +11,7 @@ use vfs::{file_set::FileSetConfig, AbsPath};
use crate::{ use crate::{
config::{Config, FilesWatcher, LinkedProject}, config::{Config, FilesWatcher, LinkedProject},
global_state::{GlobalState, Handle}, global_state::{GlobalState, Handle},
main_loop::Task,
}; };
impl GlobalState { impl GlobalState {
@ -20,51 +21,51 @@ impl GlobalState {
self.analysis_host.update_lru_capacity(old_config.lru_capacity); self.analysis_host.update_lru_capacity(old_config.lru_capacity);
} }
if self.config.linked_projects != old_config.linked_projects { if self.config.linked_projects != old_config.linked_projects {
self.reload() self.fetch_workspaces()
} else if self.config.flycheck != old_config.flycheck { } else if self.config.flycheck != old_config.flycheck {
self.reload_flycheck(); self.reload_flycheck();
} }
} }
pub(crate) fn reload(&mut self) { pub(crate) fn fetch_workspaces(&mut self) {
log::info!("reloading projects: {:?}", self.config.linked_projects); self.task_pool.handle.spawn({
if self.config.linked_projects.is_empty() && self.config.notifications.cargo_toml_not_found let linked_projects = self.config.linked_projects.clone();
{ let cargo_config = self.config.cargo.clone();
self.show_message( let with_sysroot = self.config.with_sysroot.clone();
lsp_types::MessageType::Error, move || {
"rust-analyzer failed to discover workspace".to_string(), let workspaces = linked_projects
); .iter()
}; .map(|project| match project {
LinkedProject::ProjectManifest(manifest) => {
let workspaces = { ra_project_model::ProjectWorkspace::load(
self.config manifest.clone(),
.linked_projects &cargo_config,
.iter() with_sysroot,
.map(|project| match project { )
LinkedProject::ProjectManifest(manifest) => { }
ra_project_model::ProjectWorkspace::load( LinkedProject::InlineJsonProject(it) => {
manifest.clone(), Ok(ra_project_model::ProjectWorkspace::Json { project: it.clone() })
&self.config.cargo, }
self.config.with_sysroot,
)
}
LinkedProject::InlineJsonProject(it) => {
Ok(ra_project_model::ProjectWorkspace::Json { project: it.clone() })
}
})
.collect::<Vec<_>>()
.into_iter()
.filter_map(|res| {
res.map_err(|err| {
log::error!("failed to load workspace: {:#}", err);
self.show_message(
lsp_types::MessageType::Error,
format!("rust-analyzer failed to load workspace: {:#}", err),
);
}) })
.ok() .collect::<Vec<_>>();
Task::Workspaces(workspaces)
}
});
}
pub(crate) fn switch_workspaces(&mut self, workspaces: Vec<anyhow::Result<ProjectWorkspace>>) {
log::info!("reloading projects: {:?}", self.config.linked_projects);
let workspaces = workspaces
.into_iter()
.filter_map(|res| {
res.map_err(|err| {
log::error!("failed to load workspace: {:#}", err);
self.show_message(
lsp_types::MessageType::Error,
format!("rust-analyzer failed to load workspace: {:#}", err),
);
}) })
.collect::<Vec<_>>() .ok()
}; })
.collect::<Vec<_>>();
if let FilesWatcher::Client = self.config.files.watcher { if let FilesWatcher::Client = self.config.files.watcher {
let registration_options = lsp_types::DidChangeWatchedFilesRegistrationOptions { let registration_options = lsp_types::DidChangeWatchedFilesRegistrationOptions {

View file

@ -447,6 +447,7 @@ version = \"0.0.0\"
", ",
) )
.server(); .server();
server.wait_until_workspace_is_loaded();
server.request::<OnEnter>( server.request::<OnEnter>(
TextDocumentPositionParams { TextDocumentPositionParams {