Prep dynamic workspace loading
This commit is contained in:
parent
73d73077fe
commit
3d0f782138
@ -7,16 +7,16 @@ use std::{convert::TryFrom, sync::Arc};
|
||||
|
||||
use crossbeam_channel::{unbounded, Receiver, Sender};
|
||||
use flycheck::{FlycheckConfig, FlycheckHandle};
|
||||
use lsp_types::Url;
|
||||
use lsp_types::{request::Request, Url};
|
||||
use parking_lot::RwLock;
|
||||
use ra_db::{CrateId, SourceRoot, VfsPath};
|
||||
use ra_ide::{Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId};
|
||||
use ra_project_model::{CargoWorkspace, ProcMacroClient, ProjectWorkspace, Target};
|
||||
use ra_project_model::{CargoWorkspace, PackageRoot, ProcMacroClient, ProjectWorkspace, Target};
|
||||
use stdx::format_to;
|
||||
use vfs::{file_set::FileSetConfig, loader::Handle, AbsPath, AbsPathBuf};
|
||||
|
||||
use crate::{
|
||||
config::{Config, FilesWatcher},
|
||||
config::{Config, FilesWatcher, LinkedProject},
|
||||
diagnostics::{CheckFixes, DiagnosticCollection},
|
||||
from_proto,
|
||||
line_endings::LineEndings,
|
||||
@ -98,10 +98,8 @@ pub(crate) struct GlobalStateSnapshot {
|
||||
impl GlobalState {
|
||||
pub(crate) fn new(
|
||||
sender: Sender<lsp_server::Message>,
|
||||
workspaces: Vec<ProjectWorkspace>,
|
||||
lru_capacity: Option<usize>,
|
||||
config: Config,
|
||||
req_queue: ReqQueue,
|
||||
) -> GlobalState {
|
||||
let (task_sender, task_receiver) = unbounded::<vfs::loader::Message>();
|
||||
|
||||
@ -117,7 +115,7 @@ impl GlobalState {
|
||||
(TaskPool::new(sender), receiver)
|
||||
};
|
||||
|
||||
let mut res = GlobalState {
|
||||
GlobalState {
|
||||
sender,
|
||||
config,
|
||||
task_pool,
|
||||
@ -129,17 +127,75 @@ impl GlobalState {
|
||||
mem_docs: FxHashSet::default(),
|
||||
vfs: Arc::new(RwLock::new((vfs::Vfs::default(), FxHashMap::default()))),
|
||||
status: Status::default(),
|
||||
req_queue,
|
||||
req_queue: ReqQueue::default(),
|
||||
latest_requests: Default::default(),
|
||||
source_root_config: SourceRootConfig::default(),
|
||||
proc_macro_client: ProcMacroClient::dummy(),
|
||||
workspaces: Arc::new(Vec::new()),
|
||||
};
|
||||
res.reload(workspaces);
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn reload(&mut self, workspaces: Vec<ProjectWorkspace>) {
|
||||
pub(crate) fn reload(&mut self) {
|
||||
let workspaces = {
|
||||
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(),
|
||||
);
|
||||
};
|
||||
|
||||
self.config
|
||||
.linked_projects
|
||||
.iter()
|
||||
.filter_map(|project| match project {
|
||||
LinkedProject::ProjectManifest(manifest) => {
|
||||
ra_project_model::ProjectWorkspace::load(
|
||||
manifest.clone(),
|
||||
&self.config.cargo,
|
||||
self.config.with_sysroot,
|
||||
)
|
||||
.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()
|
||||
}
|
||||
LinkedProject::InlineJsonProject(it) => {
|
||||
Some(ra_project_model::ProjectWorkspace::Json { project: it.clone() })
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
};
|
||||
|
||||
if let FilesWatcher::Client = self.config.files.watcher {
|
||||
let registration_options = lsp_types::DidChangeWatchedFilesRegistrationOptions {
|
||||
watchers: workspaces
|
||||
.iter()
|
||||
.flat_map(ProjectWorkspace::to_roots)
|
||||
.filter(PackageRoot::is_member)
|
||||
.map(|root| format!("{}/**/*.rs", root.path().display()))
|
||||
.map(|glob_pattern| lsp_types::FileSystemWatcher { glob_pattern, kind: None })
|
||||
.collect(),
|
||||
};
|
||||
let registration = lsp_types::Registration {
|
||||
id: "file-watcher".to_string(),
|
||||
method: "workspace/didChangeWatchedFiles".to_string(),
|
||||
register_options: Some(serde_json::to_value(registration_options).unwrap()),
|
||||
};
|
||||
let params = lsp_types::RegistrationParams { registrations: vec![registration] };
|
||||
let request = self.req_queue.outgoing.register(
|
||||
lsp_types::request::RegisterCapability::METHOD.to_string(),
|
||||
params,
|
||||
|_, _| (),
|
||||
);
|
||||
self.send(request.into());
|
||||
}
|
||||
|
||||
let mut change = AnalysisChange::new();
|
||||
|
||||
let project_folders = ProjectFolders::new(&workspaces);
|
||||
@ -275,7 +331,7 @@ impl GlobalState {
|
||||
self.send(response.into());
|
||||
}
|
||||
}
|
||||
pub(crate) fn show_message(&mut self, typ: lsp_types::MessageType, message: String) {
|
||||
pub(crate) fn show_message(&self, typ: lsp_types::MessageType, message: String) {
|
||||
show_message(typ, message, &self.sender)
|
||||
}
|
||||
}
|
||||
|
@ -11,17 +11,14 @@ use lsp_types::{notification::Notification as _, request::Request as _};
|
||||
use ra_db::VfsPath;
|
||||
use ra_ide::{Canceled, FileId};
|
||||
use ra_prof::profile;
|
||||
use ra_project_model::{PackageRoot, ProjectWorkspace};
|
||||
|
||||
use crate::{
|
||||
config::{Config, FilesWatcher, LinkedProject},
|
||||
config::Config,
|
||||
dispatch::{NotificationDispatcher, RequestDispatcher},
|
||||
from_proto,
|
||||
global_state::{file_id_to_url, GlobalState, Status},
|
||||
handlers, lsp_ext,
|
||||
lsp_utils::{
|
||||
apply_document_changes, is_canceled, notification_is, notification_new, show_message,
|
||||
},
|
||||
lsp_utils::{apply_document_changes, is_canceled, notification_is, notification_new},
|
||||
Result,
|
||||
};
|
||||
|
||||
@ -47,81 +44,8 @@ pub fn main_loop(config: Config, connection: Connection) -> Result<()> {
|
||||
SetThreadPriority(thread, thread_priority_above_normal);
|
||||
}
|
||||
|
||||
let global_state = {
|
||||
let workspaces = {
|
||||
if config.linked_projects.is_empty() && config.notifications.cargo_toml_not_found {
|
||||
show_message(
|
||||
lsp_types::MessageType::Error,
|
||||
"rust-analyzer failed to discover workspace".to_string(),
|
||||
&connection.sender,
|
||||
);
|
||||
};
|
||||
|
||||
config
|
||||
.linked_projects
|
||||
.iter()
|
||||
.filter_map(|project| match project {
|
||||
LinkedProject::ProjectManifest(manifest) => {
|
||||
ra_project_model::ProjectWorkspace::load(
|
||||
manifest.clone(),
|
||||
&config.cargo,
|
||||
config.with_sysroot,
|
||||
)
|
||||
.map_err(|err| {
|
||||
log::error!("failed to load workspace: {:#}", err);
|
||||
show_message(
|
||||
lsp_types::MessageType::Error,
|
||||
format!("rust-analyzer failed to load workspace: {:#}", err),
|
||||
&connection.sender,
|
||||
);
|
||||
})
|
||||
.ok()
|
||||
}
|
||||
LinkedProject::InlineJsonProject(it) => {
|
||||
Some(ra_project_model::ProjectWorkspace::Json { project: it.clone() })
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
};
|
||||
|
||||
let mut req_queue = ReqQueue::default();
|
||||
|
||||
if let FilesWatcher::Client = config.files.watcher {
|
||||
let registration_options = lsp_types::DidChangeWatchedFilesRegistrationOptions {
|
||||
watchers: workspaces
|
||||
.iter()
|
||||
.flat_map(ProjectWorkspace::to_roots)
|
||||
.filter(PackageRoot::is_member)
|
||||
.map(|root| format!("{}/**/*.rs", root.path().display()))
|
||||
.map(|glob_pattern| lsp_types::FileSystemWatcher { glob_pattern, kind: None })
|
||||
.collect(),
|
||||
};
|
||||
let registration = lsp_types::Registration {
|
||||
id: "file-watcher".to_string(),
|
||||
method: "workspace/didChangeWatchedFiles".to_string(),
|
||||
register_options: Some(serde_json::to_value(registration_options).unwrap()),
|
||||
};
|
||||
let params = lsp_types::RegistrationParams { registrations: vec![registration] };
|
||||
let request = req_queue.outgoing.register(
|
||||
lsp_types::request::RegisterCapability::METHOD.to_string(),
|
||||
params,
|
||||
DO_NOTHING,
|
||||
);
|
||||
connection.sender.send(request.into()).unwrap();
|
||||
}
|
||||
|
||||
GlobalState::new(
|
||||
connection.sender.clone(),
|
||||
workspaces,
|
||||
config.lru_capacity,
|
||||
config,
|
||||
req_queue,
|
||||
)
|
||||
};
|
||||
|
||||
log::info!("server initialized, serving requests");
|
||||
global_state.run(connection.receiver)?;
|
||||
Ok(())
|
||||
GlobalState::new(connection.sender.clone(), config.lru_capacity, config)
|
||||
.run(connection.receiver)
|
||||
}
|
||||
|
||||
enum Event {
|
||||
@ -188,23 +112,26 @@ impl GlobalState {
|
||||
}
|
||||
|
||||
fn run(mut self, inbox: Receiver<lsp_server::Message>) -> Result<()> {
|
||||
self.reload();
|
||||
|
||||
while let Some(event) = self.next_event(&inbox) {
|
||||
if let Event::Lsp(lsp_server::Message::Notification(not)) = &event {
|
||||
if not.method == lsp_types::notification::Exit::METHOD {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
self.loop_turn(event)?
|
||||
self.handle_event(event)?
|
||||
}
|
||||
|
||||
Err("client exited without proper shutdown sequence")?
|
||||
}
|
||||
|
||||
fn loop_turn(&mut self, event: Event) -> Result<()> {
|
||||
fn handle_event(&mut self, event: Event) -> Result<()> {
|
||||
let loop_start = Instant::now();
|
||||
// NOTE: don't count blocking select! call as a loop-turn time
|
||||
let _p = profile("main_loop_inner/loop-turn");
|
||||
let _p = profile("GlobalState::handle_event");
|
||||
|
||||
log::info!("loop turn = {:?}", event);
|
||||
log::info!("handle_event({:?})", event);
|
||||
let queue_count = self.task_pool.0.len();
|
||||
if queue_count > 0 {
|
||||
log::info!("queued count = {}", queue_count);
|
||||
|
Loading…
x
Reference in New Issue
Block a user