From bf801953a3d41e781c136b74815244d07c6cad03 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 1 Jun 2019 10:31:40 +0300 Subject: rename --- crates/ra_lsp_server/src/cargo_target_spec.rs | 6 +- crates/ra_lsp_server/src/conv.rs | 50 +++--- crates/ra_lsp_server/src/lib.rs | 2 +- crates/ra_lsp_server/src/main_loop.rs | 20 +-- crates/ra_lsp_server/src/main_loop/handlers.rs | 66 ++++---- crates/ra_lsp_server/src/server_world.rs | 212 ------------------------ crates/ra_lsp_server/src/world.rs | 218 +++++++++++++++++++++++++ 7 files changed, 290 insertions(+), 284 deletions(-) delete mode 100644 crates/ra_lsp_server/src/server_world.rs create mode 100644 crates/ra_lsp_server/src/world.rs diff --git a/crates/ra_lsp_server/src/cargo_target_spec.rs b/crates/ra_lsp_server/src/cargo_target_spec.rs index cdf2ec10b..742361155 100644 --- a/crates/ra_lsp_server/src/cargo_target_spec.rs +++ b/crates/ra_lsp_server/src/cargo_target_spec.rs @@ -1,13 +1,13 @@ use crate::{ project_model::{self, TargetKind}, - server_world::ServerWorld, + world::WorldSnapshot, Result }; use ra_ide_api::{FileId, RunnableKind}; pub(crate) fn runnable_args( - world: &ServerWorld, + world: &WorldSnapshot, file_id: FileId, kind: &RunnableKind, ) -> Result> { @@ -58,7 +58,7 @@ pub struct CargoTargetSpec { } impl CargoTargetSpec { - pub fn for_file(world: &ServerWorld, file_id: FileId) -> Result> { + pub fn for_file(world: &WorldSnapshot, file_id: FileId) -> Result> { let &crate_id = match world.analysis().crate_for(file_id)?.first() { Some(crate_id) => crate_id, None => return Ok(None), diff --git a/crates/ra_lsp_server/src/conv.rs b/crates/ra_lsp_server/src/conv.rs index 1b349d02a..88d29b256 100644 --- a/crates/ra_lsp_server/src/conv.rs +++ b/crates/ra_lsp_server/src/conv.rs @@ -12,7 +12,7 @@ use ra_ide_api::{ use ra_syntax::{SyntaxKind, TextRange, TextUnit}; use ra_text_edit::{AtomTextEdit, TextEdit}; -use crate::{req, server_world::ServerWorld, Result}; +use crate::{req, world::WorldSnapshot, Result}; pub trait Conv { type Output; @@ -228,49 +228,49 @@ impl ConvWith for Option { } impl<'a> TryConvWith for &'a Url { - type Ctx = ServerWorld; + type Ctx = WorldSnapshot; type Output = FileId; - fn try_conv_with(self, world: &ServerWorld) -> Result { + fn try_conv_with(self, world: &WorldSnapshot) -> Result { world.uri_to_file_id(self) } } impl TryConvWith for FileId { - type Ctx = ServerWorld; + type Ctx = WorldSnapshot; type Output = Url; - fn try_conv_with(self, world: &ServerWorld) -> Result { + fn try_conv_with(self, world: &WorldSnapshot) -> Result { world.file_id_to_uri(self) } } impl<'a> TryConvWith for &'a TextDocumentItem { - type Ctx = ServerWorld; + type Ctx = WorldSnapshot; type Output = FileId; - fn try_conv_with(self, world: &ServerWorld) -> Result { + fn try_conv_with(self, world: &WorldSnapshot) -> Result { self.uri.try_conv_with(world) } } impl<'a> TryConvWith for &'a VersionedTextDocumentIdentifier { - type Ctx = ServerWorld; + type Ctx = WorldSnapshot; type Output = FileId; - fn try_conv_with(self, world: &ServerWorld) -> Result { + fn try_conv_with(self, world: &WorldSnapshot) -> Result { self.uri.try_conv_with(world) } } impl<'a> TryConvWith for &'a TextDocumentIdentifier { - type Ctx = ServerWorld; + type Ctx = WorldSnapshot; type Output = FileId; - fn try_conv_with(self, world: &ServerWorld) -> Result { + fn try_conv_with(self, world: &WorldSnapshot) -> Result { world.uri_to_file_id(&self.uri) } } impl<'a> TryConvWith for &'a TextDocumentPositionParams { - type Ctx = ServerWorld; + type Ctx = WorldSnapshot; type Output = FilePosition; - fn try_conv_with(self, world: &ServerWorld) -> Result { + fn try_conv_with(self, world: &WorldSnapshot) -> Result { let file_id = self.text_document.try_conv_with(world)?; let line_index = world.analysis().file_line_index(file_id); let offset = self.position.conv_with(&line_index); @@ -279,9 +279,9 @@ impl<'a> TryConvWith for &'a TextDocumentPositionParams { } impl<'a> TryConvWith for (&'a TextDocumentIdentifier, Range) { - type Ctx = ServerWorld; + type Ctx = WorldSnapshot; type Output = FileRange; - fn try_conv_with(self, world: &ServerWorld) -> Result { + fn try_conv_with(self, world: &WorldSnapshot) -> Result { let file_id = self.0.try_conv_with(world)?; let line_index = world.analysis().file_line_index(file_id); let range = self.1.conv_with(&line_index); @@ -302,9 +302,9 @@ impl TryConvWith for Vec { } impl TryConvWith for SourceChange { - type Ctx = ServerWorld; + type Ctx = WorldSnapshot; type Output = req::SourceChange; - fn try_conv_with(self, world: &ServerWorld) -> Result { + fn try_conv_with(self, world: &WorldSnapshot) -> Result { let cursor_position = match self.cursor_position { None => None, Some(pos) => { @@ -342,9 +342,9 @@ impl TryConvWith for SourceChange { } impl TryConvWith for SourceFileEdit { - type Ctx = ServerWorld; + type Ctx = WorldSnapshot; type Output = TextDocumentEdit; - fn try_conv_with(self, world: &ServerWorld) -> Result { + fn try_conv_with(self, world: &WorldSnapshot) -> Result { let text_document = VersionedTextDocumentIdentifier { uri: self.file_id.try_conv_with(world)?, version: None, @@ -356,9 +356,9 @@ impl TryConvWith for SourceFileEdit { } impl TryConvWith for FileSystemEdit { - type Ctx = ServerWorld; + type Ctx = WorldSnapshot; type Output = ResourceOp; - fn try_conv_with(self, world: &ServerWorld) -> Result { + fn try_conv_with(self, world: &WorldSnapshot) -> Result { let res = match self { FileSystemEdit::CreateFile { source_root, path } => { let uri = world.path_to_uri(source_root, &path)?; @@ -375,9 +375,9 @@ impl TryConvWith for FileSystemEdit { } impl TryConvWith for &NavigationTarget { - type Ctx = ServerWorld; + type Ctx = WorldSnapshot; type Output = Location; - fn try_conv_with(self, world: &ServerWorld) -> Result { + fn try_conv_with(self, world: &WorldSnapshot) -> Result { let line_index = world.analysis().file_line_index(self.file_id()); let range = self.range(); to_location(self.file_id(), range, &world, &line_index) @@ -386,7 +386,7 @@ impl TryConvWith for &NavigationTarget { pub fn to_location_link( target: &RangeInfo, - world: &ServerWorld, + world: &WorldSnapshot, // line index for original range file line_index: &LineIndex, ) -> Result { @@ -410,7 +410,7 @@ pub fn to_location_link( pub fn to_location( file_id: FileId, range: TextRange, - world: &ServerWorld, + world: &WorldSnapshot, line_index: &LineIndex, ) -> Result { let url = file_id.try_conv_with(world)?; diff --git a/crates/ra_lsp_server/src/lib.rs b/crates/ra_lsp_server/src/lib.rs index 113883bdd..aabde420b 100644 --- a/crates/ra_lsp_server/src/lib.rs +++ b/crates/ra_lsp_server/src/lib.rs @@ -7,7 +7,7 @@ mod project_model; mod vfs_filter; pub mod req; pub mod init; -mod server_world; +mod world; pub type Result = ::std::result::Result; pub use crate::{caps::server_capabilities, main_loop::main_loop, main_loop::LspError, init::InitializationOptions}; diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs index e6a7dc641..6080a3a4e 100644 --- a/crates/ra_lsp_server/src/main_loop.rs +++ b/crates/ra_lsp_server/src/main_loop.rs @@ -24,7 +24,7 @@ use crate::{ }, project_model::workspace_loader, req, - server_world::{ServerWorld, ServerWorldState}, + world::{WorldSnapshot, WorldState}, Result, InitializationOptions, }; @@ -73,7 +73,7 @@ pub fn main_loop( loaded_workspaces }; - let mut state = ServerWorldState::new(ws_roots, workspaces); + let mut state = WorldState::new(ws_roots, workspaces); let pool = ThreadPool::new(THREADPOOL_SIZE); let (task_sender, task_receiver) = unbounded::(); @@ -161,7 +161,7 @@ fn main_loop_inner( msg_receiver: &Receiver, task_sender: Sender, task_receiver: Receiver, - state: &mut ServerWorldState, + state: &mut WorldState, pending_requests: &mut PendingRequests, ) -> Result<()> { let mut subs = Subscriptions::default(); @@ -278,7 +278,7 @@ fn on_task( task: Task, msg_sender: &Sender, pending_requests: &mut PendingRequests, - state: &mut ServerWorldState, + state: &mut WorldState, ) { match task { Task::Respond(response) => { @@ -295,7 +295,7 @@ fn on_task( } fn on_request( - world: &mut ServerWorldState, + world: &mut WorldState, pending_requests: &mut PendingRequests, pool: &ThreadPool, sender: &Sender, @@ -352,7 +352,7 @@ fn on_request( fn on_notification( msg_sender: &Sender, - state: &mut ServerWorldState, + state: &mut WorldState, pending_requests: &mut PendingRequests, subs: &mut Subscriptions, not: RawNotification, @@ -422,7 +422,7 @@ fn on_notification( struct PoolDispatcher<'a> { req: Option, pool: &'a ThreadPool, - world: &'a mut ServerWorldState, + world: &'a mut WorldState, pending_requests: &'a mut PendingRequests, msg_sender: &'a Sender, sender: &'a Sender, @@ -433,7 +433,7 @@ impl<'a> PoolDispatcher<'a> { /// Dispatches the request onto the current thread fn on_sync( &mut self, - f: fn(&mut ServerWorldState, R::Params) -> Result, + f: fn(&mut WorldState, R::Params) -> Result, ) -> Result<&mut Self> where R: req::Request + 'static, @@ -453,7 +453,7 @@ impl<'a> PoolDispatcher<'a> { } /// Dispatches the request onto thread pool - fn on(&mut self, f: fn(ServerWorld, R::Params) -> Result) -> Result<&mut Self> + fn on(&mut self, f: fn(WorldSnapshot, R::Params) -> Result) -> Result<&mut Self> where R: req::Request + 'static, R::Params: DeserializeOwned + Send + 'static, @@ -557,7 +557,7 @@ where fn update_file_notifications_on_threadpool( pool: &ThreadPool, - world: ServerWorld, + world: WorldSnapshot, publish_decorations: bool, sender: Sender, subscriptions: Vec, diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs index 8cfb6a192..6373240d5 100644 --- a/crates/ra_lsp_server/src/main_loop/handlers.rs +++ b/crates/ra_lsp_server/src/main_loop/handlers.rs @@ -24,11 +24,11 @@ use crate::{ cargo_target_spec::{runnable_args, CargoTargetSpec}, conv::{to_location, to_location_link, Conv, ConvWith, MapConvWith, TryConvWith}, req::{self, Decoration}, - server_world::ServerWorld, + world::WorldSnapshot, LspError, Result, }; -pub fn handle_analyzer_status(world: ServerWorld, _: ()) -> Result { +pub fn handle_analyzer_status(world: WorldSnapshot, _: ()) -> Result { let mut buf = world.status(); writeln!(buf, "\n\nrequests:").unwrap(); let requests = world.latest_requests.read(); @@ -39,7 +39,7 @@ pub fn handle_analyzer_status(world: ServerWorld, _: ()) -> Result { Ok(buf) } -pub fn handle_syntax_tree(world: ServerWorld, params: req::SyntaxTreeParams) -> Result { +pub fn handle_syntax_tree(world: WorldSnapshot, params: req::SyntaxTreeParams) -> Result { let id = params.text_document.try_conv_with(&world)?; let line_index = world.analysis().file_line_index(id); let text_range = params.range.map(|p| p.conv_with(&line_index)); @@ -49,7 +49,7 @@ pub fn handle_syntax_tree(world: ServerWorld, params: req::SyntaxTreeParams) -> // FIXME: drop this API pub fn handle_extend_selection( - world: ServerWorld, + world: WorldSnapshot, params: req::ExtendSelectionParams, ) -> Result { log::error!( @@ -69,7 +69,7 @@ pub fn handle_extend_selection( } pub fn handle_selection_range( - world: ServerWorld, + world: WorldSnapshot, params: req::SelectionRangeParams, ) -> Result> { let _p = profile("handle_selection_range"); @@ -110,7 +110,7 @@ pub fn handle_selection_range( } pub fn handle_find_matching_brace( - world: ServerWorld, + world: WorldSnapshot, params: req::FindMatchingBraceParams, ) -> Result> { let _p = profile("handle_find_matching_brace"); @@ -129,7 +129,7 @@ pub fn handle_find_matching_brace( } pub fn handle_join_lines( - world: ServerWorld, + world: WorldSnapshot, params: req::JoinLinesParams, ) -> Result { let _p = profile("handle_join_lines"); @@ -138,7 +138,7 @@ pub fn handle_join_lines( } pub fn handle_on_enter( - world: ServerWorld, + world: WorldSnapshot, params: req::TextDocumentPositionParams, ) -> Result> { let _p = profile("handle_on_enter"); @@ -150,7 +150,7 @@ pub fn handle_on_enter( } pub fn handle_on_type_formatting( - world: ServerWorld, + world: WorldSnapshot, params: req::DocumentOnTypeFormattingParams, ) -> Result>> { let _p = profile("handle_on_type_formatting"); @@ -181,7 +181,7 @@ pub fn handle_on_type_formatting( } pub fn handle_document_symbol( - world: ServerWorld, + world: WorldSnapshot, params: req::DocumentSymbolParams, ) -> Result> { let file_id = params.text_document.try_conv_with(&world)?; @@ -219,7 +219,7 @@ pub fn handle_document_symbol( } pub fn handle_workspace_symbol( - world: ServerWorld, + world: WorldSnapshot, params: req::WorkspaceSymbolParams, ) -> Result>> { let all_symbols = params.query.contains('#'); @@ -245,7 +245,7 @@ pub fn handle_workspace_symbol( return Ok(Some(res)); - fn exec_query(world: &ServerWorld, query: Query) -> Result> { + fn exec_query(world: &WorldSnapshot, query: Query) -> Result> { let mut res = Vec::new(); for nav in world.analysis().symbol_search(query)? { let info = SymbolInformation { @@ -262,7 +262,7 @@ pub fn handle_workspace_symbol( } pub fn handle_goto_definition( - world: ServerWorld, + world: WorldSnapshot, params: req::TextDocumentPositionParams, ) -> Result> { let position = params.try_conv_with(&world)?; @@ -282,7 +282,7 @@ pub fn handle_goto_definition( } pub fn handle_goto_implementation( - world: ServerWorld, + world: WorldSnapshot, params: req::TextDocumentPositionParams, ) -> Result> { let position = params.try_conv_with(&world)?; @@ -302,7 +302,7 @@ pub fn handle_goto_implementation( } pub fn handle_goto_type_definition( - world: ServerWorld, + world: WorldSnapshot, params: req::TextDocumentPositionParams, ) -> Result> { let position = params.try_conv_with(&world)?; @@ -322,7 +322,7 @@ pub fn handle_goto_type_definition( } pub fn handle_parent_module( - world: ServerWorld, + world: WorldSnapshot, params: req::TextDocumentPositionParams, ) -> Result> { let position = params.try_conv_with(&world)?; @@ -335,7 +335,7 @@ pub fn handle_parent_module( } pub fn handle_runnables( - world: ServerWorld, + world: WorldSnapshot, params: req::RunnablesParams, ) -> Result> { let file_id = params.text_document.try_conv_with(&world)?; @@ -396,7 +396,7 @@ pub fn handle_runnables( } pub fn handle_decorations( - world: ServerWorld, + world: WorldSnapshot, params: TextDocumentIdentifier, ) -> Result> { let file_id = params.try_conv_with(&world)?; @@ -404,7 +404,7 @@ pub fn handle_decorations( } pub fn handle_completion( - world: ServerWorld, + world: WorldSnapshot, params: req::CompletionParams, ) -> Result> { let _p = profile("handle_completion"); @@ -447,7 +447,7 @@ pub fn handle_completion( } pub fn handle_folding_range( - world: ServerWorld, + world: WorldSnapshot, params: FoldingRangeParams, ) -> Result>> { let file_id = params.text_document.try_conv_with(&world)?; @@ -481,7 +481,7 @@ pub fn handle_folding_range( } pub fn handle_signature_help( - world: ServerWorld, + world: WorldSnapshot, params: req::TextDocumentPositionParams, ) -> Result> { let position = params.try_conv_with(&world)?; @@ -500,7 +500,7 @@ pub fn handle_signature_help( } pub fn handle_hover( - world: ServerWorld, + world: WorldSnapshot, params: req::TextDocumentPositionParams, ) -> Result> { let position = params.try_conv_with(&world)?; @@ -522,7 +522,7 @@ pub fn handle_hover( /// Test doc comment pub fn handle_prepare_rename( - world: ServerWorld, + world: WorldSnapshot, params: req::TextDocumentPositionParams, ) -> Result> { let position = params.try_conv_with(&world)?; @@ -543,7 +543,7 @@ pub fn handle_prepare_rename( Ok(Some(PrepareRenameResponse::Range(loc.range))) } -pub fn handle_rename(world: ServerWorld, params: RenameParams) -> Result> { +pub fn handle_rename(world: WorldSnapshot, params: RenameParams) -> Result> { let file_id = params.text_document.try_conv_with(&world)?; let line_index = world.analysis().file_line_index(file_id); let offset = params.position.conv_with(&line_index); @@ -569,7 +569,7 @@ pub fn handle_rename(world: ServerWorld, params: RenameParams) -> Result Result>> { let file_id = params.text_document.try_conv_with(&world)?; @@ -597,7 +597,7 @@ pub fn handle_references( } pub fn handle_formatting( - world: ServerWorld, + world: WorldSnapshot, params: DocumentFormattingParams, ) -> Result>> { let file_id = params.text_document.try_conv_with(&world)?; @@ -641,7 +641,7 @@ pub fn handle_formatting( } pub fn handle_code_action( - world: ServerWorld, + world: WorldSnapshot, params: req::CodeActionParams, ) -> Result> { let _p = profile("handle_code_action"); @@ -704,7 +704,7 @@ pub fn handle_code_action( } pub fn handle_code_lens( - world: ServerWorld, + world: WorldSnapshot, params: req::CodeLensParams, ) -> Result>> { let file_id = params.text_document.try_conv_with(&world)?; @@ -781,7 +781,7 @@ enum CodeLensResolveData { Impls(req::TextDocumentPositionParams), } -pub fn handle_code_lens_resolve(world: ServerWorld, code_lens: CodeLens) -> Result { +pub fn handle_code_lens_resolve(world: WorldSnapshot, code_lens: CodeLens) -> Result { let data = code_lens.data.unwrap(); let resolve = serde_json::from_value(data)?; match resolve { @@ -826,7 +826,7 @@ pub fn handle_code_lens_resolve(world: ServerWorld, code_lens: CodeLens) -> Resu } pub fn handle_document_highlight( - world: ServerWorld, + world: WorldSnapshot, params: req::TextDocumentPositionParams, ) -> Result>> { let file_id = params.text_document.try_conv_with(&world)?; @@ -845,7 +845,7 @@ pub fn handle_document_highlight( } pub fn publish_diagnostics( - world: &ServerWorld, + world: &WorldSnapshot, file_id: FileId, ) -> Result { let uri = world.file_id_to_uri(file_id)?; @@ -867,14 +867,14 @@ pub fn publish_diagnostics( } pub fn publish_decorations( - world: &ServerWorld, + world: &WorldSnapshot, file_id: FileId, ) -> Result { let uri = world.file_id_to_uri(file_id)?; Ok(req::PublishDecorationsParams { uri, decorations: highlight(&world, file_id)? }) } -fn highlight(world: &ServerWorld, file_id: FileId) -> Result> { +fn highlight(world: &WorldSnapshot, file_id: FileId) -> Result> { let line_index = world.analysis().file_line_index(file_id); let res = world .analysis() diff --git a/crates/ra_lsp_server/src/server_world.rs b/crates/ra_lsp_server/src/server_world.rs deleted file mode 100644 index 6076a6cd6..000000000 --- a/crates/ra_lsp_server/src/server_world.rs +++ /dev/null @@ -1,212 +0,0 @@ -use std::{ - path::{Path, PathBuf}, - sync::Arc, -}; - -use lsp_types::Url; -use ra_ide_api::{ - Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId, LibraryData, - SourceRootId -}; -use ra_vfs::{Vfs, VfsChange, VfsFile, VfsRoot}; -use relative_path::RelativePathBuf; -use parking_lot::RwLock; -use failure::{Error, format_err}; -use gen_lsp_server::ErrorCode; - -use crate::{ - main_loop::pending_requests::{CompletedRequest, LatestRequests}, - project_model::ProjectWorkspace, - vfs_filter::IncludeRustFiles, - Result, - LspError, -}; - -#[derive(Debug)] -pub struct ServerWorldState { - pub roots_to_scan: usize, - pub roots: Vec, - pub workspaces: Arc>, - pub analysis_host: AnalysisHost, - pub vfs: Arc>, - pub latest_requests: Arc>, -} - -pub struct ServerWorld { - pub workspaces: Arc>, - pub analysis: Analysis, - pub vfs: Arc>, - pub latest_requests: Arc>, -} - -impl ServerWorldState { - pub fn new(folder_roots: Vec, workspaces: Vec) -> ServerWorldState { - let mut change = AnalysisChange::new(); - - let mut roots = Vec::new(); - roots.extend(folder_roots.iter().cloned().map(IncludeRustFiles::member)); - for ws in workspaces.iter() { - roots.extend(IncludeRustFiles::from_roots(ws.to_roots())); - } - - let (mut vfs, vfs_roots) = Vfs::new(roots); - let roots_to_scan = vfs_roots.len(); - for r in vfs_roots { - let vfs_root_path = vfs.root2path(r); - let is_local = folder_roots.iter().any(|it| vfs_root_path.starts_with(it)); - change.add_root(SourceRootId(r.0.into()), is_local); - } - - // Create crate graph from all the workspaces - let mut crate_graph = CrateGraph::default(); - let mut load = |path: &std::path::Path| { - let vfs_file = vfs.load(path); - vfs_file.map(|f| FileId(f.0.into())) - }; - for ws in workspaces.iter() { - crate_graph.extend(ws.to_crate_graph(&mut load)); - } - change.set_crate_graph(crate_graph); - - let mut analysis_host = AnalysisHost::default(); - analysis_host.apply_change(change); - ServerWorldState { - roots_to_scan, - roots: folder_roots, - workspaces: Arc::new(workspaces), - analysis_host, - vfs: Arc::new(RwLock::new(vfs)), - latest_requests: Default::default(), - } - } - - /// Returns a vec of libraries - /// FIXME: better API here - 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 changes { - match c { - VfsChange::AddRoot { root, files } => { - let root_path = self.vfs.read().root2path(root); - let is_local = self.roots.iter().any(|r| root_path.starts_with(r)); - if is_local { - self.roots_to_scan -= 1; - for (file, path, text) in files { - change.add_file( - SourceRootId(root.0.into()), - FileId(file.0.into()), - path, - text, - ); - } - } else { - let files = files - .into_iter() - .map(|(vfsfile, path, text)| (FileId(vfsfile.0.into()), path, text)) - .collect(); - libs.push((SourceRootId(root.0.into()), files)); - } - } - VfsChange::AddFile { root, file, path, text } => { - change.add_file(SourceRootId(root.0.into()), FileId(file.0.into()), path, text); - } - VfsChange::RemoveFile { root, file, path } => { - change.remove_file(SourceRootId(root.0.into()), FileId(file.0.into()), path) - } - VfsChange::ChangeFile { file, text } => { - change.change_file(FileId(file.0.into()), text); - } - } - } - self.analysis_host.apply_change(change); - libs - } - - 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); - } - - pub fn snapshot(&self) -> ServerWorld { - ServerWorld { - workspaces: Arc::clone(&self.workspaces), - analysis: self.analysis_host.analysis(), - vfs: Arc::clone(&self.vfs), - latest_requests: Arc::clone(&self.latest_requests), - } - } - - pub fn maybe_collect_garbage(&mut self) { - self.analysis_host.maybe_collect_garbage() - } - - pub fn collect_garbage(&mut self) { - self.analysis_host.collect_garbage() - } - - pub fn complete_request(&mut self, request: CompletedRequest) { - self.latest_requests.write().record(request) - } -} - -impl ServerWorld { - pub fn analysis(&self) -> &Analysis { - &self.analysis - } - - pub fn uri_to_file_id(&self, uri: &Url) -> Result { - let path = uri.to_file_path().map_err(|()| format_err!("invalid uri: {}", uri))?; - let file = self.vfs.read().path2file(&path).ok_or_else(|| { - // Show warning as this file is outside current workspace - Error::from(LspError { - code: ErrorCode::InvalidRequest as i32, - message: "Rust file outside current workspace is not supported yet.".to_string(), - }) - })?; - Ok(FileId(file.0.into())) - } - - pub fn file_id_to_uri(&self, id: FileId) -> Result { - let path = self.vfs.read().file2path(VfsFile(id.0.into())); - let url = Url::from_file_path(&path) - .map_err(|_| format_err!("can't convert path to url: {}", path.display()))?; - Ok(url) - } - - pub fn path_to_uri(&self, root: SourceRootId, path: &RelativePathBuf) -> Result { - let base = self.vfs.read().root2path(VfsRoot(root.0.into())); - let path = path.to_path(base); - let url = Url::from_file_path(&path) - .map_err(|_| format_err!("can't convert path to url: {}", path.display()))?; - Ok(url) - } - - pub fn status(&self) -> String { - let mut res = String::new(); - if self.workspaces.is_empty() { - res.push_str("no workspaces\n") - } else { - res.push_str("workspaces:\n"); - for w in self.workspaces.iter() { - res += &format!("{} packages loaded\n", w.count()); - } - } - res.push_str("\nanalysis:\n"); - res.push_str(&self.analysis.status()); - res - } - - pub fn workspace_root_for(&self, file_id: FileId) -> Option<&Path> { - let path = self.vfs.read().file2path(VfsFile(file_id.0.into())); - self.workspaces.iter().find_map(|ws| ws.workspace_root_for(&path)) - } -} diff --git a/crates/ra_lsp_server/src/world.rs b/crates/ra_lsp_server/src/world.rs new file mode 100644 index 000000000..e0d2f6306 --- /dev/null +++ b/crates/ra_lsp_server/src/world.rs @@ -0,0 +1,218 @@ +use std::{ + path::{Path, PathBuf}, + sync::Arc, +}; + +use lsp_types::Url; +use ra_ide_api::{ + Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId, LibraryData, + SourceRootId +}; +use ra_vfs::{Vfs, VfsChange, VfsFile, VfsRoot}; +use relative_path::RelativePathBuf; +use parking_lot::RwLock; +use failure::{Error, format_err}; +use gen_lsp_server::ErrorCode; + +use crate::{ + main_loop::pending_requests::{CompletedRequest, LatestRequests}, + project_model::ProjectWorkspace, + vfs_filter::IncludeRustFiles, + Result, + LspError, +}; + +/// `WorldState` is the primary mutable state of the language server +/// +/// The most interesting components are `vfs`, which stores a consistent +/// snapshot of the file systems, and `analysis_host`, which stores our +/// incremental salsa database. +#[derive(Debug)] +pub struct WorldState { + pub roots_to_scan: usize, + pub roots: Vec, + pub workspaces: Arc>, + pub analysis_host: AnalysisHost, + pub vfs: Arc>, + pub latest_requests: Arc>, +} + +/// An immutable snapshot of the world's state at a point in time. +pub struct WorldSnapshot { + pub workspaces: Arc>, + pub analysis: Analysis, + pub vfs: Arc>, + pub latest_requests: Arc>, +} + +impl WorldState { + pub fn new(folder_roots: Vec, workspaces: Vec) -> WorldState { + let mut change = AnalysisChange::new(); + + let mut roots = Vec::new(); + roots.extend(folder_roots.iter().cloned().map(IncludeRustFiles::member)); + for ws in workspaces.iter() { + roots.extend(IncludeRustFiles::from_roots(ws.to_roots())); + } + + let (mut vfs, vfs_roots) = Vfs::new(roots); + let roots_to_scan = vfs_roots.len(); + for r in vfs_roots { + let vfs_root_path = vfs.root2path(r); + let is_local = folder_roots.iter().any(|it| vfs_root_path.starts_with(it)); + change.add_root(SourceRootId(r.0.into()), is_local); + } + + // Create crate graph from all the workspaces + let mut crate_graph = CrateGraph::default(); + let mut load = |path: &std::path::Path| { + let vfs_file = vfs.load(path); + vfs_file.map(|f| FileId(f.0.into())) + }; + for ws in workspaces.iter() { + crate_graph.extend(ws.to_crate_graph(&mut load)); + } + change.set_crate_graph(crate_graph); + + let mut analysis_host = AnalysisHost::default(); + analysis_host.apply_change(change); + WorldState { + roots_to_scan, + roots: folder_roots, + workspaces: Arc::new(workspaces), + analysis_host, + vfs: Arc::new(RwLock::new(vfs)), + latest_requests: Default::default(), + } + } + + /// Returns a vec of libraries + /// FIXME: better API here + 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 changes { + match c { + VfsChange::AddRoot { root, files } => { + let root_path = self.vfs.read().root2path(root); + let is_local = self.roots.iter().any(|r| root_path.starts_with(r)); + if is_local { + self.roots_to_scan -= 1; + for (file, path, text) in files { + change.add_file( + SourceRootId(root.0.into()), + FileId(file.0.into()), + path, + text, + ); + } + } else { + let files = files + .into_iter() + .map(|(vfsfile, path, text)| (FileId(vfsfile.0.into()), path, text)) + .collect(); + libs.push((SourceRootId(root.0.into()), files)); + } + } + VfsChange::AddFile { root, file, path, text } => { + change.add_file(SourceRootId(root.0.into()), FileId(file.0.into()), path, text); + } + VfsChange::RemoveFile { root, file, path } => { + change.remove_file(SourceRootId(root.0.into()), FileId(file.0.into()), path) + } + VfsChange::ChangeFile { file, text } => { + change.change_file(FileId(file.0.into()), text); + } + } + } + self.analysis_host.apply_change(change); + libs + } + + 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); + } + + pub fn snapshot(&self) -> WorldSnapshot { + WorldSnapshot { + workspaces: Arc::clone(&self.workspaces), + analysis: self.analysis_host.analysis(), + vfs: Arc::clone(&self.vfs), + latest_requests: Arc::clone(&self.latest_requests), + } + } + + pub fn maybe_collect_garbage(&mut self) { + self.analysis_host.maybe_collect_garbage() + } + + pub fn collect_garbage(&mut self) { + self.analysis_host.collect_garbage() + } + + pub fn complete_request(&mut self, request: CompletedRequest) { + self.latest_requests.write().record(request) + } +} + +impl WorldSnapshot { + pub fn analysis(&self) -> &Analysis { + &self.analysis + } + + pub fn uri_to_file_id(&self, uri: &Url) -> Result { + let path = uri.to_file_path().map_err(|()| format_err!("invalid uri: {}", uri))?; + let file = self.vfs.read().path2file(&path).ok_or_else(|| { + // Show warning as this file is outside current workspace + Error::from(LspError { + code: ErrorCode::InvalidRequest as i32, + message: "Rust file outside current workspace is not supported yet.".to_string(), + }) + })?; + Ok(FileId(file.0.into())) + } + + pub fn file_id_to_uri(&self, id: FileId) -> Result { + let path = self.vfs.read().file2path(VfsFile(id.0.into())); + let url = Url::from_file_path(&path) + .map_err(|_| format_err!("can't convert path to url: {}", path.display()))?; + Ok(url) + } + + pub fn path_to_uri(&self, root: SourceRootId, path: &RelativePathBuf) -> Result { + let base = self.vfs.read().root2path(VfsRoot(root.0.into())); + let path = path.to_path(base); + let url = Url::from_file_path(&path) + .map_err(|_| format_err!("can't convert path to url: {}", path.display()))?; + Ok(url) + } + + pub fn status(&self) -> String { + let mut res = String::new(); + if self.workspaces.is_empty() { + res.push_str("no workspaces\n") + } else { + res.push_str("workspaces:\n"); + for w in self.workspaces.iter() { + res += &format!("{} packages loaded\n", w.count()); + } + } + res.push_str("\nanalysis:\n"); + res.push_str(&self.analysis.status()); + res + } + + pub fn workspace_root_for(&self, file_id: FileId) -> Option<&Path> { + let path = self.vfs.read().file2path(VfsFile(file_id.0.into())); + self.workspaces.iter().find_map(|ws| ws.workspace_root_for(&path)) + } +} -- cgit v1.2.3