From 47cbaeba6f21e59ee8735bfe8bcbf06300767b57 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 3 Sep 2018 21:03:37 +0300 Subject: [PATCH] Index deps --- crates/libanalysis/src/imp.rs | 10 +-- crates/libanalysis/src/lib.rs | 4 +- crates/server/src/main_loop/handlers.rs | 6 +- crates/server/src/main_loop/mod.rs | 62 ++++++++++------- crates/server/src/project_model.rs | 29 ++++---- crates/server/src/server_world.rs | 13 +++- crates/server/src/vfs.rs | 88 ++++++++++++++----------- 7 files changed, 128 insertions(+), 84 deletions(-) diff --git a/crates/libanalysis/src/imp.rs b/crates/libanalysis/src/imp.rs index c1e144025b..3ea27947e0 100644 --- a/crates/libanalysis/src/imp.rs +++ b/crates/libanalysis/src/imp.rs @@ -57,9 +57,9 @@ impl AnalysisHostImpl { } self.data_mut().crate_graph = graph; } - pub fn set_libraries(&mut self, libs: impl Iterator>) { - let libs = libs.map(ReadonlySourceRoot::new).collect::>(); - self.data_mut().libs = Arc::new(libs); + pub fn add_library(&mut self, files: impl Iterator) { + let libs = ReadonlySourceRoot::new(files); + self.data_mut().libs.push(Arc::new(libs)); } fn data_mut(&mut self) -> &mut WorldData { Arc::make_mut(&mut self.data) @@ -93,7 +93,7 @@ impl AnalysisImpl { if self.data.root.contains(file_id) { return &self.data.root; } - self.data.libs.iter().find(|it| it.contains(file_id)).unwrap() + &**self.data.libs.iter().find(|it| it.contains(file_id)).unwrap() } pub fn file_syntax(&self, file_id: FileId) -> &File { self.root(file_id).syntax(file_id) @@ -308,7 +308,7 @@ impl AnalysisImpl { struct WorldData { crate_graph: CrateGraph, root: WritableSourceRoot, - libs: Arc>, + libs: Vec>, } impl SourceChange { diff --git a/crates/libanalysis/src/lib.rs b/crates/libanalysis/src/lib.rs index 9ae87d46cf..e9e0c51d54 100644 --- a/crates/libanalysis/src/lib.rs +++ b/crates/libanalysis/src/lib.rs @@ -68,8 +68,8 @@ impl AnalysisHost { pub fn set_crate_graph(&mut self, graph: CrateGraph) { self.imp.set_crate_graph(graph) } - pub fn set_libraries(&mut self, libs: impl Iterator>) { - self.imp.set_libraries(libs) + pub fn add_library(&mut self, files: impl Iterator) { + self.imp.add_library(files) } } diff --git a/crates/server/src/main_loop/handlers.rs b/crates/server/src/main_loop/handlers.rs index 898195f6d7..323d4e95ea 100644 --- a/crates/server/src/main_loop/handlers.rs +++ b/crates/server/src/main_loop/handlers.rs @@ -141,14 +141,18 @@ pub fn handle_workspace_symbol( token: JobToken, ) -> Result>> { let all_symbols = params.query.contains("#"); + let libs = params.query.contains("*"); let query = { let query: String = params.query.chars() - .filter(|&c| c != '#') + .filter(|&c| c != '#' && c != '*') .collect(); let mut q = Query::new(query); if !all_symbols { q.only_types(); } + if libs { + q.libs(); + } q.limit(128); q }; diff --git a/crates/server/src/main_loop/mod.rs b/crates/server/src/main_loop/mod.rs index bb1d638e0f..ce61265a29 100644 --- a/crates/server/src/main_loop/mod.rs +++ b/crates/server/src/main_loop/mod.rs @@ -38,9 +38,8 @@ pub fn main_loop( ) -> Result<()> { let pool = ThreadPool::new(4); let (task_sender, task_receiver) = bounded::(16); - let (fs_events_receiver, watcher) = vfs::watch(vec![root.clone()]); - let (ws_root_sender, ws_receiver, ws_watcher) = workspace_loader(); - ws_root_sender.send(root); + let (fs_sender, fs_receiver, fs_watcher) = vfs::roots_loader(); + let (ws_sender, ws_receiver, ws_watcher) = workspace_loader(); info!("server initialized, serving requests"); let mut state = ServerWorldState::new(); @@ -48,13 +47,15 @@ pub fn main_loop( let mut pending_requests = HashMap::new(); let mut subs = Subscriptions::new(); let main_res = main_loop_inner( + root, &pool, - msg_receriver, msg_sender, - task_receiver.clone(), + msg_receriver, task_sender, - fs_events_receiver, - ws_root_sender, + task_receiver.clone(), + fs_sender, + fs_receiver, + ws_sender, ws_receiver, &mut state, &mut pending_requests, @@ -68,38 +69,40 @@ pub fn main_loop( pool.join(); info!("...threadpool has finished"); - let vfs_res = watcher.stop(); + let fs_res = fs_watcher.stop(); let ws_res = ws_watcher.stop(); main_res?; - vfs_res?; + fs_res?; ws_res?; Ok(()) } fn main_loop_inner( + ws_root: PathBuf, pool: &ThreadPool, - msg_receiver: &mut Receiver, msg_sender: &mut Sender, - task_receiver: Receiver, + msg_receiver: &mut Receiver, task_sender: Sender, - fs_receiver: Receiver>, - _ws_roots_sender: Sender, + task_receiver: Receiver, + fs_sender: Sender, + fs_receiver: Receiver<(PathBuf, Vec)>, + ws_sender: Sender, ws_receiver: Receiver>, state: &mut ServerWorldState, pending_requests: &mut HashMap, subs: &mut Subscriptions, ) -> Result<()> { - let mut fs_receiver = Some(fs_receiver); + ws_sender.send(ws_root.clone()); + fs_sender.send(ws_root.clone()); loop { #[derive(Debug)] enum Event { Msg(RawMessage), Task(Task), - Fs(Vec), + Fs(PathBuf, Vec), Ws(Result), - FsWatcherDead, } trace!("selecting"); let event = select! { @@ -109,8 +112,8 @@ fn main_loop_inner( }, recv(task_receiver, task) => Event::Task(task.unwrap()), recv(fs_receiver, events) => match events { - Some(events) => Event::Fs(events), - None => Event::FsWatcherDead, + None => bail!("roots watcher died"), + Some((pb, events)) => Event::Fs(pb, events), } recv(ws_receiver, ws) => match ws { None => bail!("workspace watcher died"), @@ -120,19 +123,30 @@ fn main_loop_inner( trace!("selected {:?}", event); let mut state_changed = false; match event { - Event::FsWatcherDead => fs_receiver = None, Event::Task(task) => on_task(task, msg_sender, pending_requests), - Event::Fs(events) => { - trace!("fs change, {} events", events.len()); - state.apply_fs_changes(events); + Event::Fs(root, events) => { + info!("fs change, {}, {} events", root.display(), events.len()); + if root == ws_root { + state.apply_fs_changes(events); + } else { + state.add_library(events); + } state_changed = true; } Event::Ws(ws) => { match ws { Ok(ws) => { - let not = RawNotification::new::(&vec![ws.clone()]); + let workspaces = vec![ws]; + let not = RawNotification::new::(&workspaces); msg_sender.send(RawMessage::Notification(not)); - state.set_workspaces(vec![ws]); + for ws in workspaces.iter() { + for pkg in ws.packages().filter(|pkg| !pkg.is_member(ws)) { + debug!("sending root, {}", pkg.root(ws).to_path_buf().display()); + // deadlocky :-( + fs_sender.send(pkg.root(ws).to_path_buf()); + } + } + state.set_workspaces(workspaces); state_changed = true; } Err(e) => warn!("loading workspace failed: {}", e), diff --git a/crates/server/src/project_model.rs b/crates/server/src/project_model.rs index 12233f2580..517836e624 100644 --- a/crates/server/src/project_model.rs +++ b/crates/server/src/project_model.rs @@ -1,5 +1,5 @@ use std::{ - collections::HashMap, + collections::{HashMap, HashSet}, path::{Path, PathBuf}, }; use cargo_metadata::{metadata_run, CargoOpt}; @@ -13,7 +13,6 @@ use { #[derive(Debug, Serialize, Clone)] pub struct CargoWorkspace { - ws_members: Vec, packages: Vec, targets: Vec, } @@ -27,7 +26,8 @@ pub struct Target(usize); struct PackageData { name: SmolStr, manifest: PathBuf, - targets: Vec + targets: Vec, + is_member: bool, } #[derive(Debug, Serialize, Clone)] @@ -50,9 +50,15 @@ impl Package { pub fn manifest(self, ws: &CargoWorkspace) -> &Path { ws.pkg(self).manifest.as_path() } + pub fn root(self, ws: &CargoWorkspace) -> &Path { + ws.pkg(self).manifest.parent().unwrap() + } pub fn targets<'a>(self, ws: &'a CargoWorkspace) -> impl Iterator + 'a { ws.pkg(self).targets.iter().cloned() } + pub fn is_member(self, ws: &CargoWorkspace) -> bool { + ws.pkg(self).is_member + } } impl Target { @@ -81,13 +87,21 @@ impl CargoWorkspace { let mut pkg_by_id = HashMap::new(); let mut packages = Vec::new(); let mut targets = Vec::new(); + + let ws_members: HashSet = meta.workspace_members + .into_iter() + .map(|it| it.raw) + .collect(); + for meta_pkg in meta.packages { let pkg = Package(packages.len()); + let is_member = ws_members.contains(&meta_pkg.id); pkg_by_id.insert(meta_pkg.id.clone(), pkg); let mut pkg_data = PackageData { name: meta_pkg.name.into(), manifest: PathBuf::from(meta_pkg.manifest_path), targets: Vec::new(), + is_member, }; for meta_tgt in meta_pkg.targets { let tgt = Target(targets.len()); @@ -101,19 +115,12 @@ impl CargoWorkspace { } packages.push(pkg_data) } - let ws_members = meta.workspace_members - .iter() - .map(|it| pkg_by_id[&it.raw]) - .collect(); - Ok(CargoWorkspace { packages, targets, ws_members }) + Ok(CargoWorkspace { packages, targets }) } pub fn packages<'a>(&'a self) -> impl Iterator + 'a { (0..self.packages.len()).map(Package) } - pub fn ws_members<'a>(&'a self) -> impl Iterator + 'a { - self.ws_members.iter().cloned() - } pub fn target_by_root(&self, root: &Path) -> Option { self.packages() .filter_map(|pkg| pkg.targets(self).find(|it| it.root(self) == root)) diff --git a/crates/server/src/server_world.rs b/crates/server/src/server_world.rs index f78b56cf8d..95c109e102 100644 --- a/crates/server/src/server_world.rs +++ b/crates/server/src/server_world.rs @@ -47,7 +47,6 @@ impl ServerWorldState { .map(|event| { let text = match event.kind { FileEventKind::Add(text) => Some(text), - FileEventKind::Remove => None, }; (event.path, text) }) @@ -65,6 +64,18 @@ impl ServerWorldState { self.analysis_host.change_files(changes); } + pub fn add_library(&mut self, events: Vec) { + let pm = &mut self.path_map; + let files = events.into_iter() + .map(|event| { + let text = match event.kind { + FileEventKind::Add(text) => text, + }; + (event.path, text) + }) + .map(|(path, text)| (pm.get_or_insert(path), text)); + self.analysis_host.add_library(files); + } pub fn add_mem_file(&mut self, path: PathBuf, text: String) -> FileId { let file_id = self.path_map.get_or_insert(path); diff --git a/crates/server/src/vfs.rs b/crates/server/src/vfs.rs index 2acc3f55f3..69a7654af2 100644 --- a/crates/server/src/vfs.rs +++ b/crates/server/src/vfs.rs @@ -1,5 +1,5 @@ use std::{ - path::PathBuf, + path::{PathBuf, Path}, fs, }; @@ -20,46 +20,54 @@ pub struct FileEvent { #[derive(Debug)] pub enum FileEventKind { Add(String), - #[allow(unused)] - Remove, } -pub fn watch(roots: Vec) -> (Receiver>, ThreadWatcher) { - let (sender, receiver) = bounded(16); - let watcher = ThreadWatcher::spawn("vfs", move || run(roots, sender)); - (receiver, watcher) -} - -fn run(roots: Vec, sender: Sender>) { - for root in roots { - let mut events = Vec::new(); - for entry in WalkDir::new(root.as_path()) { - let entry = match entry { - Ok(entry) => entry, - Err(e) => { - warn!("watcher error: {}", e); - continue; - } - }; - if !entry.file_type().is_file() { - continue; - } - let path = entry.path(); - if path.extension().and_then(|os| os.to_str()) != Some("rs") { - continue; - } - let text = match fs::read_to_string(path) { - Ok(text) => text, - Err(e) => { - warn!("watcher error: {}", e); - continue; - } - }; - events.push(FileEvent { - path: path.to_owned(), - kind: FileEventKind::Add(text), +pub fn roots_loader() -> (Sender, Receiver<(PathBuf, Vec)>, ThreadWatcher) { + let (path_sender, path_receiver) = bounded::(2048); + let (event_sender, event_receiver) = bounded::<(PathBuf, Vec)>(1); + let thread = ThreadWatcher::spawn("roots loader", move || { + path_receiver + .into_iter() + .map(|path| { + debug!("loading {} ...", path.as_path().display()); + let events = load_root(path.as_path()); + debug!("... loaded {}", path.as_path().display()); + (path, events) }) - } - sender.send(events) - } + .for_each(|it| event_sender.send(it)) + }); + + (path_sender, event_receiver, thread) +} + +fn load_root(path: &Path) -> Vec { + let mut res = Vec::new(); + for entry in WalkDir::new(path) { + let entry = match entry { + Ok(entry) => entry, + Err(e) => { + warn!("watcher error: {}", e); + continue; + } + }; + if !entry.file_type().is_file() { + continue; + } + let path = entry.path(); + if path.extension().and_then(|os| os.to_str()) != Some("rs") { + continue; + } + let text = match fs::read_to_string(path) { + Ok(text) => text, + Err(e) => { + warn!("watcher error: {}", e); + continue; + } + }; + res.push(FileEvent { + path: path.to_owned(), + kind: FileEventKind::Add(text), + }) + } + res }