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/src/server_world.rs | 203 ++++++++++++------------------- 1 file changed, 81 insertions(+), 122 deletions(-) (limited to 'crates/ra_lsp_server/src/server_world.rs') 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) } } -- cgit v1.2.3