From 7509901fa0985f8fc4893a83e0275a063f072dda Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 18 Dec 2018 12:29:14 +0300 Subject: wip --- crates/ra_lsp_server/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'crates/ra_lsp_server') diff --git a/crates/ra_lsp_server/Cargo.toml b/crates/ra_lsp_server/Cargo.toml index ce4f79d46..4e8e09584 100644 --- a/crates/ra_lsp_server/Cargo.toml +++ b/crates/ra_lsp_server/Cargo.toml @@ -19,7 +19,7 @@ flexi_logger = "0.10.0" log = "0.4.3" url_serde = "0.2.0" languageserver-types = "0.53.0" -walkdir = "2.2.0" +walkdir = "2.2.7" im = "12.0.0" cargo_metadata = "0.6.0" text_unit = { version = "0.1.2", features = ["serde"] } -- cgit v1.2.3 From 2ae05a6163d8b15f3d8a18a2ab713d1fbd83c505 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 18 Dec 2018 13:18:55 +0300 Subject: vfs crate scaffold --- crates/ra_lsp_server/src/main_loop.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'crates/ra_lsp_server') diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs index eab82ee85..9d3f83b4c 100644 --- a/crates/ra_lsp_server/src/main_loop.rs +++ b/crates/ra_lsp_server/src/main_loop.rs @@ -88,8 +88,8 @@ pub fn main_loop( drop(pool); log::info!("...threadpool has finished"); - let fs_res = fs_watcher.stop(); - let ws_res = ws_watcher.stop(); + let fs_res = fs_watcher.shutdown(); + let ws_res = ws_watcher.shutdown(); main_res?; fs_res.map_err(|_| format_err!("fs watcher died"))?; -- cgit v1.2.3 From a422d480a188a28c6b5e7862fbf07817eb2c7447 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 18 Dec 2018 16:38:05 +0300 Subject: implement vfs events handling --- crates/ra_lsp_server/tests/heavy_tests/support.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'crates/ra_lsp_server') diff --git a/crates/ra_lsp_server/tests/heavy_tests/support.rs b/crates/ra_lsp_server/tests/heavy_tests/support.rs index 07a878a26..c14d287ca 100644 --- a/crates/ra_lsp_server/tests/heavy_tests/support.rs +++ b/crates/ra_lsp_server/tests/heavy_tests/support.rs @@ -174,11 +174,11 @@ impl Server { impl Drop for Server { fn drop(&mut self) { self.send_request::(666, ()); - let receiver = self.worker.take().unwrap().stop(); + let receiver = self.worker.take().unwrap().shutdown(); while let Some(msg) = recv_timeout(&receiver) { drop(msg); } - self.watcher.take().unwrap().stop().unwrap(); + self.watcher.take().unwrap().shutdown().unwrap(); } } -- cgit v1.2.3 From 6a755ed83a583d1f70a5fbcff2d4933b52628cfe Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 19 Dec 2018 12:48:34 +0300 Subject: remove more imports --- crates/ra_lsp_server/src/path_map.rs | 23 +---------------------- crates/ra_lsp_server/src/server_world.rs | 2 +- 2 files changed, 2 insertions(+), 23 deletions(-) (limited to 'crates/ra_lsp_server') diff --git a/crates/ra_lsp_server/src/path_map.rs b/crates/ra_lsp_server/src/path_map.rs index 02e54629c..86cf29540 100644 --- a/crates/ra_lsp_server/src/path_map.rs +++ b/crates/ra_lsp_server/src/path_map.rs @@ -4,7 +4,7 @@ use std::{ }; use im; -use ra_analysis::{FileId, FileResolver}; +use ra_analysis::{FileId}; use relative_path::RelativePath; #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -64,27 +64,6 @@ impl PathMap { } } -impl FileResolver for PathMap { - fn file_stem(&self, file_id: FileId) -> String { - self.get_path(file_id) - .file_stem() - .unwrap() - .to_str() - .unwrap() - .to_string() - } - - fn resolve(&self, file_id: FileId, path: &RelativePath) -> Option { - let path = path.to_path(&self.get_path(file_id)); - let path = normalize(&path); - self.get_id(&path) - } - - fn debug_path(&self, file_id: FileId) -> Option { - Some(self.get_path(file_id).to_owned()) - } -} - fn normalize(path: &Path) -> PathBuf { let mut components = path.components().peekable(); let mut ret = if let Some(c @ Component::Prefix(..)) = components.peek().cloned() { diff --git a/crates/ra_lsp_server/src/server_world.rs b/crates/ra_lsp_server/src/server_world.rs index ab4c2c8aa..c0d1338a2 100644 --- a/crates/ra_lsp_server/src/server_world.rs +++ b/crates/ra_lsp_server/src/server_world.rs @@ -6,7 +6,7 @@ use std::{ use languageserver_types::Url; use ra_analysis::{ - Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId, FileResolver, LibraryData, + Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId, LibraryData, }; use rustc_hash::FxHashMap; use failure::{bail, format_err}; -- cgit v1.2.3 From a5ef8ad05b7c1f7148c59814b55d641fd75aff75 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 19 Dec 2018 15:04:15 +0300 Subject: swtich lsp server to vfs --- crates/ra_lsp_server/Cargo.toml | 2 + crates/ra_lsp_server/src/lib.rs | 2 - crates/ra_lsp_server/src/main_loop.rs | 143 +++++++---------- crates/ra_lsp_server/src/main_loop/handlers.rs | 4 +- crates/ra_lsp_server/src/path_map.rs | 105 ------------- crates/ra_lsp_server/src/project_model.rs | 1 + crates/ra_lsp_server/src/server_world.rs | 203 ++++++++++--------------- crates/ra_lsp_server/src/vfs.rs | 67 -------- 8 files changed, 140 insertions(+), 387 deletions(-) delete mode 100644 crates/ra_lsp_server/src/path_map.rs delete mode 100644 crates/ra_lsp_server/src/vfs.rs (limited to 'crates/ra_lsp_server') diff --git a/crates/ra_lsp_server/Cargo.toml b/crates/ra_lsp_server/Cargo.toml index 4e8e09584..fc10096e5 100644 --- a/crates/ra_lsp_server/Cargo.toml +++ b/crates/ra_lsp_server/Cargo.toml @@ -25,6 +25,7 @@ cargo_metadata = "0.6.0" text_unit = { version = "0.1.2", features = ["serde"] } smol_str = { version = "0.1.5", features = ["serde"] } rustc-hash = "1.0" +parking_lot = "0.7.0" thread_worker = { path = "../thread_worker" } ra_syntax = { path = "../ra_syntax" } @@ -32,6 +33,7 @@ ra_editor = { path = "../ra_editor" } ra_text_edit = { path = "../ra_text_edit" } ra_analysis = { path = "../ra_analysis" } gen_lsp_server = { path = "../gen_lsp_server" } +ra_vfs = { path = "../ra_vfs" } [dev-dependencies] tempdir = "0.3.7" diff --git a/crates/ra_lsp_server/src/lib.rs b/crates/ra_lsp_server/src/lib.rs index 1d7258c35..725b1258a 100644 --- a/crates/ra_lsp_server/src/lib.rs +++ b/crates/ra_lsp_server/src/lib.rs @@ -1,11 +1,9 @@ mod caps; mod conv; mod main_loop; -mod path_map; mod project_model; pub mod req; mod server_world; -mod vfs; pub type Result = ::std::result::Result; pub use crate::{caps::server_capabilities, main_loop::main_loop, main_loop::LspError}; diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs index 9d3f83b4c..7904545d3 100644 --- a/crates/ra_lsp_server/src/main_loop.rs +++ b/crates/ra_lsp_server/src/main_loop.rs @@ -1,7 +1,10 @@ mod handlers; mod subscriptions; -use std::path::PathBuf; +use std::{ + path::PathBuf, + sync::Arc, +}; use crossbeam_channel::{unbounded, select, Receiver, Sender}; use gen_lsp_server::{ @@ -9,8 +12,8 @@ use gen_lsp_server::{ }; use languageserver_types::NumberOrString; use ra_analysis::{Canceled, FileId, LibraryData}; +use ra_vfs::{VfsTask}; use rayon; -use thread_worker::Worker; use threadpool::ThreadPool; use rustc_hash::FxHashSet; use serde::{de::DeserializeOwned, Serialize}; @@ -19,10 +22,9 @@ use failure_derive::Fail; use crate::{ main_loop::subscriptions::Subscriptions, - project_model::{workspace_loader, CargoWorkspace}, + project_model::{workspace_loader}, req, server_world::{ServerWorld, ServerWorldState}, - vfs::{self, FileEvent}, Result, }; @@ -50,32 +52,42 @@ enum Task { pub fn main_loop( internal_mode: bool, - root: PathBuf, + ws_root: PathBuf, publish_decorations: bool, msg_receiver: &Receiver, msg_sender: &Sender, ) -> Result<()> { let pool = ThreadPool::new(8); let (task_sender, task_receiver) = unbounded::(); - let (fs_worker, fs_watcher) = vfs::roots_loader(); let (ws_worker, ws_watcher) = workspace_loader(); + ws_worker.send(ws_root.clone()); + // FIXME: support dynamic workspace loading. + let workspaces = match ws_worker.recv().unwrap() { + Ok(ws) => vec![ws], + Err(e) => { + log::warn!("loading workspace failed: {}", e); + Vec::new() + } + }; + ws_worker.shutdown(); + ws_watcher + .shutdown() + .map_err(|_| format_err!("ws watcher died"))?; + let mut state = ServerWorldState::new(ws_root.clone(), workspaces); + log::info!("server initialized, serving requests"); - let mut state = ServerWorldState::default(); let mut pending_requests = FxHashSet::default(); let mut subs = Subscriptions::new(); let main_res = main_loop_inner( internal_mode, publish_decorations, - root, &pool, msg_sender, msg_receiver, task_sender, task_receiver.clone(), - fs_worker, - ws_worker, &mut state, &mut pending_requests, &mut subs, @@ -88,12 +100,11 @@ pub fn main_loop( drop(pool); log::info!("...threadpool has finished"); - let fs_res = fs_watcher.shutdown(); - let ws_res = ws_watcher.shutdown(); + let vfs = Arc::try_unwrap(state.vfs).expect("all snapshots should be dead"); + let vfs_res = vfs.into_inner().shutdown(); main_res?; - fs_res.map_err(|_| format_err!("fs watcher died"))?; - ws_res.map_err(|_| format_err!("ws watcher died"))?; + vfs_res.map_err(|_| format_err!("fs watcher died"))?; Ok(()) } @@ -101,28 +112,22 @@ pub fn main_loop( fn main_loop_inner( internal_mode: bool, publish_decorations: bool, - ws_root: PathBuf, pool: &ThreadPool, msg_sender: &Sender, msg_receiver: &Receiver, task_sender: Sender, task_receiver: Receiver, - fs_worker: Worker)>, - ws_worker: Worker>, state: &mut ServerWorldState, pending_requests: &mut FxHashSet, subs: &mut Subscriptions, ) -> Result<()> { let (libdata_sender, libdata_receiver) = unbounded(); - ws_worker.send(ws_root.clone()); - fs_worker.send(ws_root.clone()); loop { #[derive(Debug)] enum Event { Msg(RawMessage), Task(Task), - Fs(PathBuf, Vec), - Ws(Result), + Vfs(VfsTask), Lib(LibraryData), } log::trace!("selecting"); @@ -132,77 +137,19 @@ fn main_loop_inner( None => bail!("client exited without shutdown"), }, recv(task_receiver, task) => Event::Task(task.unwrap()), - recv(fs_worker.out, events) => match events { - None => bail!("roots watcher died"), - Some((pb, events)) => Event::Fs(pb, events), - } - recv(ws_worker.out, ws) => match ws { - None => bail!("workspace watcher died"), - Some(ws) => Event::Ws(ws), + recv(state.vfs.read().task_receiver(), task) => match task { + None => bail!("vfs died"), + Some(task) => Event::Vfs(task), } recv(libdata_receiver, data) => Event::Lib(data.unwrap()) }; let mut state_changed = false; match event { Event::Task(task) => on_task(task, msg_sender, pending_requests), - Event::Fs(root, events) => { - log::info!("fs change, {}, {} events", root.display(), events.len()); - if root == ws_root { - state.apply_fs_changes(events); - } else { - let (files, resolver) = state.events_to_files(events); - let sender = libdata_sender.clone(); - pool.execute(move || { - let start = ::std::time::Instant::now(); - log::info!("indexing {} ... ", root.display()); - let data = LibraryData::prepare(files, resolver); - log::info!("indexed {:?} {}", start.elapsed(), root.display()); - sender.send(data); - }); - } + Event::Vfs(task) => { + state.vfs.write().handle_task(task); state_changed = true; } - Event::Ws(ws) => match ws { - Ok(ws) => { - let workspaces = vec![ws]; - feedback(internal_mode, "workspace loaded", msg_sender); - for ws in workspaces.iter() { - // Add each library as constant input. If library is - // within the workspace, don't treat it as a library. - // - // HACK: If source roots are nested, pick the outer one. - - let mut roots = ws - .packages() - .filter(|pkg| !pkg.is_member(ws)) - .filter_map(|pkg| { - let root = pkg.root(ws).to_path_buf(); - if root.starts_with(&ws_root) { - None - } else { - Some(root) - } - }) - .collect::>(); - roots.sort_by_key(|it| it.as_os_str().len()); - let unique = roots - .iter() - .enumerate() - .filter(|&(idx, long)| { - !roots[..idx].iter().any(|short| long.starts_with(short)) - }) - .map(|(_idx, root)| root); - - for root in unique { - log::debug!("sending root, {}", root.display()); - fs_worker.send(root.to_owned()); - } - } - state.set_workspaces(workspaces); - state_changed = true; - } - Err(e) => log::warn!("loading workspace failed: {}", e), - }, Event::Lib(lib) => { feedback(internal_mode, "library loaded", msg_sender); state.add_lib(lib); @@ -234,6 +181,18 @@ fn main_loop_inner( }, }; + for lib in state.process_changes() { + let (root, files) = lib; + let sender = libdata_sender.clone(); + pool.execute(move || { + let start = ::std::time::Instant::now(); + log::info!("indexing {:?} ... ", root); + let data = LibraryData::prepare(root, files); + log::info!("indexed {:?} {:?}", start.elapsed(), root); + sender.send(data); + }); + } + if state_changed { update_file_notifications_on_threadpool( pool, @@ -336,8 +295,13 @@ fn on_notification( let path = uri .to_file_path() .map_err(|()| format_err!("invalid uri: {}", uri))?; - let file_id = state.add_mem_file(path, params.text_document.text); - subs.add_sub(file_id); + if let Some(file_id) = state + .vfs + .write() + .add_file_overlay(&path, params.text_document.text) + { + subs.add_sub(FileId(file_id.0)); + } return Ok(()); } Err(not) => not, @@ -353,7 +317,7 @@ fn on_notification( .pop() .ok_or_else(|| format_err!("empty changes"))? .text; - state.change_mem_file(path.as_path(), text)?; + state.vfs.write().change_file_overlay(path.as_path(), text); return Ok(()); } Err(not) => not, @@ -364,8 +328,9 @@ fn on_notification( let path = uri .to_file_path() .map_err(|()| format_err!("invalid uri: {}", uri))?; - let file_id = state.remove_mem_file(path.as_path())?; - subs.remove_sub(file_id); + if let Some(file_id) = state.vfs.write().remove_file_overlay(path.as_path()) { + subs.remove_sub(FileId(file_id.0)); + } let params = req::PublishDiagnosticsParams { uri, diagnostics: Vec::new(), diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs index acca480c7..572ae7fb5 100644 --- a/crates/ra_lsp_server/src/main_loop/handlers.rs +++ b/crates/ra_lsp_server/src/main_loop/handlers.rs @@ -326,9 +326,9 @@ pub fn handle_runnables( None => return Ok(None), }; let file_id = world.analysis().crate_root(crate_id)?; - let path = world.path_map.get_path(file_id); + let path = world.vfs.read().file2path(ra_vfs::VfsFile(file_id.0)); let res = world.workspaces.iter().find_map(|ws| { - let tgt = ws.target_by_root(path)?; + let tgt = ws.target_by_root(&path)?; let res = CargoTargetSpec { package: tgt.package(ws).name(ws).to_string(), target: tgt.name(ws).to_string(), diff --git a/crates/ra_lsp_server/src/path_map.rs b/crates/ra_lsp_server/src/path_map.rs deleted file mode 100644 index 86cf29540..000000000 --- a/crates/ra_lsp_server/src/path_map.rs +++ /dev/null @@ -1,105 +0,0 @@ -use std::{ - fmt, - path::{Component, Path, PathBuf}, -}; - -use im; -use ra_analysis::{FileId}; -use relative_path::RelativePath; - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum Root { - Workspace, - Lib, -} - -#[derive(Default, Clone)] -pub struct PathMap { - next_id: u32, - path2id: im::HashMap, - id2path: im::HashMap, - id2root: im::HashMap, -} - -impl fmt::Debug for PathMap { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str("PathMap { ... }") - } -} - -impl PathMap { - pub fn get_or_insert(&mut self, path: PathBuf, root: Root) -> (bool, FileId) { - let mut inserted = false; - let file_id = self - .path2id - .get(path.as_path()) - .map(|&id| id) - .unwrap_or_else(|| { - inserted = true; - let id = self.new_file_id(); - self.insert(path, id, root); - id - }); - (inserted, file_id) - } - pub fn get_id(&self, path: &Path) -> Option { - self.path2id.get(path).cloned() - } - pub fn get_path(&self, file_id: FileId) -> &Path { - self.id2path.get(&file_id).unwrap().as_path() - } - pub fn get_root(&self, file_id: FileId) -> Root { - self.id2root[&file_id] - } - fn insert(&mut self, path: PathBuf, file_id: FileId, root: Root) { - self.path2id.insert(path.clone(), file_id); - self.id2path.insert(file_id, path.clone()); - self.id2root.insert(file_id, root); - } - - fn new_file_id(&mut self) -> FileId { - let id = FileId(self.next_id); - self.next_id += 1; - id - } -} - -fn normalize(path: &Path) -> PathBuf { - let mut components = path.components().peekable(); - let mut ret = if let Some(c @ Component::Prefix(..)) = components.peek().cloned() { - components.next(); - PathBuf::from(c.as_os_str()) - } else { - PathBuf::new() - }; - - for component in components { - match component { - Component::Prefix(..) => unreachable!(), - Component::RootDir => { - ret.push(component.as_os_str()); - } - Component::CurDir => {} - Component::ParentDir => { - ret.pop(); - } - Component::Normal(c) => { - ret.push(c); - } - } - } - ret -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn test_resolve() { - let mut m = PathMap::default(); - let (_, id1) = m.get_or_insert(PathBuf::from("/foo"), Root::Workspace); - let (_, id2) = m.get_or_insert(PathBuf::from("/foo/bar.rs"), Root::Workspace); - assert_eq!(m.resolve(id1, &RelativePath::new("bar.rs")), Some(id2),) - } -} diff --git a/crates/ra_lsp_server/src/project_model.rs b/crates/ra_lsp_server/src/project_model.rs index b881f8b6f..5852a157d 100644 --- a/crates/ra_lsp_server/src/project_model.rs +++ b/crates/ra_lsp_server/src/project_model.rs @@ -69,6 +69,7 @@ impl Package { pub fn targets<'a>(self, ws: &'a CargoWorkspace) -> impl Iterator + 'a { ws.pkg(self).targets.iter().cloned() } + #[allow(unused)] pub fn is_member(self, ws: &CargoWorkspace) -> bool { ws.pkg(self).is_member } diff --git a/crates/ra_lsp_server/src/server_world.rs b/crates/ra_lsp_server/src/server_world.rs index c0d1338a2..f2fd09e85 100644 --- a/crates/ra_lsp_server/src/server_world.rs +++ b/crates/ra_lsp_server/src/server_world.rs @@ -1,154 +1,62 @@ use std::{ - fs, - path::{Path, PathBuf}, + path::{PathBuf}, sync::Arc, }; use languageserver_types::Url; use ra_analysis::{ Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId, LibraryData, + SourceRootId }; +use ra_vfs::{Vfs, VfsChange, VfsFile}; use rustc_hash::FxHashMap; -use failure::{bail, format_err}; +use relative_path::RelativePathBuf; +use parking_lot::RwLock; +use failure::{format_err}; use crate::{ - path_map::{PathMap, Root}, project_model::{CargoWorkspace, TargetKind}, - vfs::{FileEvent, FileEventKind}, Result, }; -#[derive(Debug, Default)] +#[derive(Debug)] pub struct ServerWorldState { pub workspaces: Arc>, pub analysis_host: AnalysisHost, - pub path_map: PathMap, - pub mem_map: FxHashMap>, + pub vfs: Arc>, } pub struct ServerWorld { pub workspaces: Arc>, pub analysis: Analysis, - pub path_map: PathMap, + pub vfs: Arc>, } impl ServerWorldState { - pub fn apply_fs_changes(&mut self, events: Vec) { + pub fn new(root: PathBuf, workspaces: Vec) -> ServerWorldState { let mut change = AnalysisChange::new(); - let mut inserted = false; - { - let pm = &mut self.path_map; - let mm = &mut self.mem_map; - events - .into_iter() - .map(|event| { - let text = match event.kind { - FileEventKind::Add(text) => text, - }; - (event.path, text) - }) - .map(|(path, text)| { - let (ins, file_id) = pm.get_or_insert(path, Root::Workspace); - inserted |= ins; - (file_id, text) - }) - .filter_map(|(file_id, text)| { - if mm.contains_key(&file_id) { - mm.insert(file_id, Some(text)); - None - } else { - Some((file_id, text)) - } - }) - .for_each(|(file_id, text)| change.add_file(file_id, text)); - } - if inserted { - change.set_file_resolver(Arc::new(self.path_map.clone())) - } - self.analysis_host.apply_change(change); - } - pub fn events_to_files( - &mut self, - events: Vec, - ) -> (Vec<(FileId, String)>, Arc) { - let files = { - let pm = &mut self.path_map; - events - .into_iter() - .map(|event| { - let FileEventKind::Add(text) = event.kind; - (event.path, text) - }) - .map(|(path, text)| (pm.get_or_insert(path, Root::Lib).1, text)) - .collect() - }; - let resolver = Arc::new(self.path_map.clone()); - (files, resolver) - } - pub fn add_lib(&mut self, data: LibraryData) { - let mut change = AnalysisChange::new(); - change.add_library(data); - self.analysis_host.apply_change(change); - } - pub fn add_mem_file(&mut self, path: PathBuf, text: String) -> FileId { - let (inserted, file_id) = self.path_map.get_or_insert(path, Root::Workspace); - if self.path_map.get_root(file_id) != Root::Lib { - let mut change = AnalysisChange::new(); - if inserted { - change.add_file(file_id, text); - change.set_file_resolver(Arc::new(self.path_map.clone())); - } else { - change.change_file(file_id, text); + let mut roots = Vec::new(); + roots.push(root); + for ws in workspaces.iter() { + for pkg in ws.packages() { + roots.push(pkg.root(&ws).to_path_buf()); } - self.analysis_host.apply_change(change); } - self.mem_map.insert(file_id, None); - file_id - } - - pub fn change_mem_file(&mut self, path: &Path, text: String) -> Result<()> { - let file_id = self - .path_map - .get_id(path) - .ok_or_else(|| format_err!("change to unknown file: {}", path.display()))?; - if self.path_map.get_root(file_id) != Root::Lib { - let mut change = AnalysisChange::new(); - change.change_file(file_id, text); - self.analysis_host.apply_change(change); + let (mut vfs, roots) = Vfs::new(roots); + for r in roots { + change.add_root(SourceRootId(r.0)); } - Ok(()) - } - pub fn remove_mem_file(&mut self, path: &Path) -> Result { - let file_id = self - .path_map - .get_id(path) - .ok_or_else(|| format_err!("change to unknown file: {}", path.display()))?; - match self.mem_map.remove(&file_id) { - Some(_) => (), - None => bail!("unmatched close notification"), - }; - // Do this via file watcher ideally. - let text = fs::read_to_string(path).ok(); - if self.path_map.get_root(file_id) != Root::Lib { - let mut change = AnalysisChange::new(); - if let Some(text) = text { - change.change_file(file_id, text); - } - self.analysis_host.apply_change(change); - } - Ok(file_id) - } - pub fn set_workspaces(&mut self, ws: Vec) { let mut crate_graph = CrateGraph::default(); let mut pkg_to_lib_crate = FxHashMap::default(); let mut pkg_crates = FxHashMap::default(); - for ws in ws.iter() { + for ws in workspaces.iter() { for pkg in ws.packages() { for tgt in pkg.targets(ws) { let root = tgt.root(ws); - if let Some(file_id) = self.path_map.get_id(root) { + if let Some(file_id) = vfs.load(root) { + let file_id = FileId(file_id.0); let crate_id = crate_graph.add_crate_root(file_id); if tgt.kind(ws) == TargetKind::Lib { pkg_to_lib_crate.insert(pkg, crate_id); @@ -170,16 +78,64 @@ impl ServerWorldState { } } } - self.workspaces = Arc::new(ws); - let mut change = AnalysisChange::new(); change.set_crate_graph(crate_graph); + + let mut analysis_host = AnalysisHost::default(); + analysis_host.apply_change(change); + ServerWorldState { + workspaces: Arc::new(workspaces), + analysis_host, + vfs: Arc::new(RwLock::new(vfs)), + } + } + + /// Returns a vec of libraries + /// FIXME: better API here + pub fn process_changes( + &mut self, + ) -> Vec<(SourceRootId, Vec<(FileId, RelativePathBuf, Arc)>)> { + let mut libs = Vec::new(); + let mut change = AnalysisChange::new(); + for c in self.vfs.write().commit_changes() { + match c { + VfsChange::AddRoot { root, files } => { + let files = files + .into_iter() + .map(|(vfsfile, path, text)| (FileId(vfsfile.0), path, text)) + .collect(); + libs.push((SourceRootId(root.0), files)); + } + VfsChange::AddFile { + root, + file, + path, + text, + } => { + change.add_file(SourceRootId(root.0), FileId(file.0), path, text); + } + VfsChange::RemoveFile { root, file, path } => { + change.remove_file(SourceRootId(root.0), FileId(file.0), path) + } + VfsChange::ChangeFile { file, text } => { + change.change_file(FileId(file.0), text); + } + } + } self.analysis_host.apply_change(change); + libs } + + pub fn add_lib(&mut self, data: LibraryData) { + let mut change = AnalysisChange::new(); + change.add_library(data); + self.analysis_host.apply_change(change); + } + pub fn snapshot(&self) -> ServerWorld { ServerWorld { workspaces: Arc::clone(&self.workspaces), analysis: self.analysis_host.analysis(), - path_map: self.path_map.clone(), + vfs: Arc::clone(&self.vfs), } } } @@ -193,15 +149,18 @@ impl ServerWorld { let path = uri .to_file_path() .map_err(|()| format_err!("invalid uri: {}", uri))?; - self.path_map - .get_id(&path) - .ok_or_else(|| format_err!("unknown file: {}", path.display())) + let file = self + .vfs + .read() + .path2file(&path) + .ok_or_else(|| format_err!("unknown file: {}", path.display()))?; + Ok(FileId(file.0)) } pub fn file_id_to_uri(&self, id: FileId) -> Result { - let path = self.path_map.get_path(id); - let url = Url::from_file_path(path) - .map_err(|()| format_err!("can't convert path to url: {}", path.display()))?; + let path = self.vfs.read().file2path(VfsFile(id.0)); + let url = Url::from_file_path(&path) + .map_err(|_| format_err!("can't convert path to url: {}", path.display()))?; Ok(url) } } diff --git a/crates/ra_lsp_server/src/vfs.rs b/crates/ra_lsp_server/src/vfs.rs deleted file mode 100644 index fcf7693d8..000000000 --- a/crates/ra_lsp_server/src/vfs.rs +++ /dev/null @@ -1,67 +0,0 @@ -use std::{ - fs, - path::{Path, PathBuf}, -}; - -use walkdir::WalkDir; -use thread_worker::{WorkerHandle, Worker}; - -#[derive(Debug)] -pub struct FileEvent { - pub path: PathBuf, - pub kind: FileEventKind, -} - -#[derive(Debug)] -pub enum FileEventKind { - Add(String), -} - -pub fn roots_loader() -> (Worker)>, WorkerHandle) { - thread_worker::spawn::), _>( - "roots loader", - 128, - |input_receiver, output_sender| { - input_receiver - .map(|path| { - log::debug!("loading {} ...", path.as_path().display()); - let events = load_root(path.as_path()); - log::debug!("... loaded {}", path.as_path().display()); - (path, events) - }) - .for_each(|it| output_sender.send(it)) - }, - ) -} - -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) => { - log::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) => { - log::warn!("watcher error: {}", e); - continue; - } - }; - res.push(FileEvent { - path: path.to_owned(), - kind: FileEventKind::Add(text), - }) - } - res -} -- cgit v1.2.3 From 7b6bafa631e6272946da568e9da7c3adc01ba625 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 19 Dec 2018 15:40:42 +0300 Subject: fix syc --- crates/ra_lsp_server/src/main_loop.rs | 4 ++++ crates/ra_lsp_server/src/server_world.rs | 33 ++++++++++++++++++++------ crates/ra_lsp_server/tests/heavy_tests/main.rs | 3 +-- 3 files changed, 31 insertions(+), 9 deletions(-) (limited to 'crates/ra_lsp_server') diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs index 7904545d3..d2f16ea97 100644 --- a/crates/ra_lsp_server/src/main_loop.rs +++ b/crates/ra_lsp_server/src/main_loop.rs @@ -143,6 +143,7 @@ fn main_loop_inner( } recv(libdata_receiver, data) => Event::Lib(data.unwrap()) }; + log::info!("{:?}", event); let mut state_changed = false; match event { Event::Task(task) => on_task(task, msg_sender, pending_requests), @@ -192,6 +193,9 @@ fn main_loop_inner( sender.send(data); }); } + if state.roots_to_scan == 0 { + feedback(internal_mode, "workspace loaded", msg_sender); + } if state_changed { update_file_notifications_on_threadpool( diff --git a/crates/ra_lsp_server/src/server_world.rs b/crates/ra_lsp_server/src/server_world.rs index f2fd09e85..bdb4c513f 100644 --- a/crates/ra_lsp_server/src/server_world.rs +++ b/crates/ra_lsp_server/src/server_world.rs @@ -21,6 +21,8 @@ use crate::{ #[derive(Debug)] pub struct ServerWorldState { + pub roots_to_scan: usize, + pub root: PathBuf, pub workspaces: Arc>, pub analysis_host: AnalysisHost, pub vfs: Arc>, @@ -37,12 +39,13 @@ impl ServerWorldState { let mut change = AnalysisChange::new(); let mut roots = Vec::new(); - roots.push(root); + roots.push(root.clone()); for ws in workspaces.iter() { for pkg in ws.packages() { roots.push(pkg.root(&ws).to_path_buf()); } } + let roots_to_scan = roots.len(); let (mut vfs, roots) = Vfs::new(roots); for r in roots { change.add_root(SourceRootId(r.0)); @@ -83,6 +86,8 @@ impl ServerWorldState { let mut analysis_host = AnalysisHost::default(); analysis_host.apply_change(change); ServerWorldState { + roots_to_scan, + root, workspaces: Arc::new(workspaces), analysis_host, vfs: Arc::new(RwLock::new(vfs)), @@ -94,16 +99,29 @@ impl ServerWorldState { pub fn process_changes( &mut self, ) -> Vec<(SourceRootId, Vec<(FileId, RelativePathBuf, Arc)>)> { + let changes = self.vfs.write().commit_changes(); + if changes.is_empty() { + return Vec::new(); + } let mut libs = Vec::new(); let mut change = AnalysisChange::new(); - for c in self.vfs.write().commit_changes() { + for c in changes { + log::info!("vfs change {:?}", c); match c { VfsChange::AddRoot { root, files } => { - let files = files - .into_iter() - .map(|(vfsfile, path, text)| (FileId(vfsfile.0), path, text)) - .collect(); - libs.push((SourceRootId(root.0), files)); + let root_path = self.vfs.read().root2path(root); + if root_path.starts_with(&self.root) { + self.roots_to_scan -= 1; + for (file, path, text) in files { + change.add_file(SourceRootId(root.0), FileId(file.0), path, text); + } + } else { + let files = files + .into_iter() + .map(|(vfsfile, path, text)| (FileId(vfsfile.0), path, text)) + .collect(); + libs.push((SourceRootId(root.0), files)); + } } VfsChange::AddFile { root, @@ -126,6 +144,7 @@ impl ServerWorldState { } pub fn add_lib(&mut self, data: LibraryData) { + self.roots_to_scan -= 1; let mut change = AnalysisChange::new(); change.add_library(data); self.analysis_host.apply_change(change); diff --git a/crates/ra_lsp_server/tests/heavy_tests/main.rs b/crates/ra_lsp_server/tests/heavy_tests/main.rs index 26f5e3f20..029a55d40 100644 --- a/crates/ra_lsp_server/tests/heavy_tests/main.rs +++ b/crates/ra_lsp_server/tests/heavy_tests/main.rs @@ -1,9 +1,7 @@ mod support; use serde_json::json; - use ra_lsp_server::req::{Runnables, RunnablesParams, CodeActionRequest, CodeActionParams}; - use languageserver_types::{Position, Range, CodeActionContext}; use crate::support::project; @@ -20,6 +18,7 @@ fn foo() { } ", ); + server.wait_for_feedback("workspace loaded"); server.request::( RunnablesParams { text_document: server.doc_id("lib.rs"), -- cgit v1.2.3 From 2fe41574a1695a6608d738f40ec51bc61fc7604a Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 19 Dec 2018 16:19:53 +0300 Subject: fix tests --- crates/ra_lsp_server/src/server_world.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'crates/ra_lsp_server') diff --git a/crates/ra_lsp_server/src/server_world.rs b/crates/ra_lsp_server/src/server_world.rs index bdb4c513f..785877c4b 100644 --- a/crates/ra_lsp_server/src/server_world.rs +++ b/crates/ra_lsp_server/src/server_world.rs @@ -48,7 +48,8 @@ impl ServerWorldState { let roots_to_scan = roots.len(); let (mut vfs, roots) = Vfs::new(roots); for r in roots { - change.add_root(SourceRootId(r.0)); + let is_local = vfs.root2path(r).starts_with(&root); + change.add_root(SourceRootId(r.0), is_local); } let mut crate_graph = CrateGraph::default(); -- cgit v1.2.3