From d19f3ac83441420365bff5e4ce21d1d2175bd8c2 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 13 Aug 2018 15:35:53 +0300 Subject: [PATCH] workspace symbols --- code/src/extension.ts | 6 ++--- crates/libanalysis/src/lib.rs | 29 +++++++++++++++---------- crates/libanalysis/src/symbol_index.rs | 28 ++++++++++-------------- crates/server/src/caps.rs | 2 +- crates/server/src/dispatch.rs | 15 ++++++++----- crates/server/src/main.rs | 4 +--- crates/server/src/main_loop/handlers.rs | 29 +++++++++++++++++++++++-- crates/server/src/main_loop/mod.rs | 4 ++++ crates/server/src/req.rs | 1 + 9 files changed, 75 insertions(+), 43 deletions(-) diff --git a/code/src/extension.ts b/code/src/extension.ts index dd0c29f146..bb724539d2 100644 --- a/code/src/extension.ts +++ b/code/src/extension.ts @@ -61,9 +61,9 @@ export function deactivate(): Thenable { function startServer() { let run: lc.Executable = { - command: "cargo", - args: ["run", "--package", "m"], - // command: "m", + // command: "cargo", + // args: ["run", "--package", "m"], + command: "m", options: { cwd: "." } } let serverOptions: lc.ServerOptions = { diff --git a/crates/libanalysis/src/lib.rs b/crates/libanalysis/src/lib.rs index f0d0cf0a4f..acaadb8a2e 100644 --- a/crates/libanalysis/src/lib.rs +++ b/crates/libanalysis/src/lib.rs @@ -89,14 +89,15 @@ impl World { Ok(index.clone()) } - pub fn world_symbols(&self, query: &str, f: &mut FnMut(&Path, &FileSymbol) -> Search) { + pub fn world_symbols<'a>(&'a self, query: &str) -> impl Iterator + 'a + { let q = Query::new(query); - for (path, data) in self.data.file_map.iter() { - let symbols = data.symbols(path.as_path()); - if q.process(symbols, &mut |symbol| f(path, symbol)) == Search::Break { - break; - } - } + self.data.file_map.iter() + .flat_map(move |(path, data)| { + let path: &'a Path = path.as_path(); + let symbols = data.symbols(path); + q.process(symbols).map(move |s| (path, s)) + }) } fn file_data(&self, path: &Path) -> Result> { @@ -107,11 +108,15 @@ impl World { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum Search { - Continue, - Break, -} + +pub type SearchResult = ::std::result::Result; + +pub struct Continue; + +pub struct Break; + +pub const CONTINUE: SearchResult = Ok(Continue); +pub const BREAK: SearchResult = Err(Break); #[derive(Default, Debug)] diff --git a/crates/libanalysis/src/symbol_index.rs b/crates/libanalysis/src/symbol_index.rs index 1878fae997..4d90aac0c6 100644 --- a/crates/libanalysis/src/symbol_index.rs +++ b/crates/libanalysis/src/symbol_index.rs @@ -5,8 +5,6 @@ use libsyntax2::{ }; use fst::{self, IntoStreamer}; -use Search; - #[derive(Debug)] pub(crate) struct FileSymbols { symbols: Vec, @@ -47,11 +45,10 @@ impl Query { Query { query, all_symbols } } - pub(crate) fn process( + pub(crate) fn process<'a>( &self, - file: &FileSymbols, - acc: &mut FnMut(&FileSymbol) -> Search, - ) -> Search { + file: &'a FileSymbols, + ) -> impl Iterator + 'a { fn is_type(kind: SyntaxKind) -> bool { match kind { STRUCT | ENUM | TRAIT | TYPE_ITEM => true, @@ -59,16 +56,15 @@ impl Query { } } let automaton = fst::automaton::Subsequence::new(&self.query); - for idx in file.map.search(automaton).into_stream().into_values() { - let idx = idx as usize; - let symbol = &file.symbols[idx]; - if self.all_symbols || is_type(symbol.kind) { - if acc(&symbol) == Search::Break { - return Search::Break; - } - } - } - Search::Continue + let all_symbols = self.all_symbols; + file.map.search(automaton).into_stream() + .into_values() + .into_iter() + .map(move |idx| { + let idx = idx as usize; + &file.symbols[idx] + }) + .filter(move |s| all_symbols || is_type(s.kind)) } } diff --git a/crates/server/src/caps.rs b/crates/server/src/caps.rs index d06a43a82a..4fd28b7c88 100644 --- a/crates/server/src/caps.rs +++ b/crates/server/src/caps.rs @@ -26,7 +26,7 @@ pub fn server_capabilities() -> ServerCapabilities { references_provider: None, document_highlight_provider: None, document_symbol_provider: Some(true), - workspace_symbol_provider: None, + workspace_symbol_provider: Some(true), code_action_provider: Some(true), code_lens_provider: None, document_formatting_provider: None, diff --git a/crates/server/src/dispatch.rs b/crates/server/src/dispatch.rs index 3a3ee74bb6..d8cca48d06 100644 --- a/crates/server/src/dispatch.rs +++ b/crates/server/src/dispatch.rs @@ -30,8 +30,12 @@ impl Responder { error: serde_json::Value::Null, } } - Err(_) => { - error_response(self.id, ErrorCode::InternalError, "internal error")? + Err(e) => { + error_response( + self.id, + ErrorCode::InternalError, + format!("internal error: {}", e), + )? } }; Ok(res) @@ -115,21 +119,20 @@ pub fn send_notification(params: N::Params) -> RawNotification pub fn unknown_method(id: u64) -> Result { error_response(id, ErrorCode::MethodNotFound, "unknown method") - } -fn error_response(id: u64, code: ErrorCode, message: &'static str) -> Result { +fn error_response(id: u64, code: ErrorCode, message: impl Into) -> Result { #[derive(Serialize)] struct Error { code: i32, - message: &'static str, + message: String, } let resp = RawResponse { id, result: serde_json::Value::Null, error: serde_json::to_value(Error { code: code as i32, - message, + message: message.into(), })?, }; Ok(resp) diff --git a/crates/server/src/main.rs b/crates/server/src/main.rs index 8dca321839..9c044d5a9f 100644 --- a/crates/server/src/main.rs +++ b/crates/server/src/main.rs @@ -27,8 +27,6 @@ mod conv; mod main_loop; mod vfs; -use std::path::PathBuf; - use threadpool::ThreadPool; use crossbeam_channel::bounded; use flexi_logger::{Logger, Duplicate}; @@ -120,7 +118,7 @@ fn initialized(io: &mut Io) -> Result<()> { let mut pool = ThreadPool::new(4); let (task_sender, task_receiver) = bounded::(16); let (fs_events_receiver, watcher) = vfs::watch(vec![ - PathBuf::from("./") + ::std::env::current_dir()?, ]); info!("lifecycle: handshake finished, server ready to serve requests"); let res = main_loop::main_loop( diff --git a/crates/server/src/main_loop/handlers.rs b/crates/server/src/main_loop/handlers.rs index 14dcafc387..bd0e6825bc 100644 --- a/crates/server/src/main_loop/handlers.rs +++ b/crates/server/src/main_loop/handlers.rs @@ -2,9 +2,10 @@ use std::collections::HashMap; use languageserver_types::{ Diagnostic, DiagnosticSeverity, Url, DocumentSymbol, - Command, TextDocumentIdentifier, WorkspaceEdit + Command, TextDocumentIdentifier, WorkspaceEdit, + SymbolInformation, Location, }; -use libanalysis::World; +use libanalysis::{World}; use libeditor; use libsyntax2::TextUnit; use serde_json::{to_value, from_value}; @@ -94,6 +95,30 @@ pub fn handle_code_action( Ok(ret) } +pub fn handle_workspace_symbol( + world: World, + params: req::WorkspaceSymbolParams, +) -> Result>> { + let mut acc = Vec::new(); + for (path, symbol) in world.world_symbols(¶ms.query).take(128) { + let line_index = world.file_line_index(path)?; + + let info = SymbolInformation { + name: symbol.name.to_string(), + kind: symbol.kind.conv(), + location: Location::new( + Url::from_file_path(path) + .map_err(|()| format_err!("invalid url"))?, + symbol.node_range.conv_with(&line_index), + ), + container_name: None, + }; + acc.push(info); + }; + + Ok(Some(acc)) +} + pub fn handle_execute_command( world: World, mut params: req::ExecuteCommandParams, diff --git a/crates/server/src/main_loop/mod.rs b/crates/server/src/main_loop/mod.rs index f954e632ca..e8b24355c5 100644 --- a/crates/server/src/main_loop/mod.rs +++ b/crates/server/src/main_loop/mod.rs @@ -25,6 +25,7 @@ use { handle_document_symbol, handle_code_action, handle_execute_command, + handle_workspace_symbol, }, }; @@ -148,6 +149,9 @@ fn on_request( handle_request_on_threadpool::( &mut req, pool, world, sender, handle_code_action, )?; + handle_request_on_threadpool::( + &mut req, pool, world, sender, handle_workspace_symbol, + )?; dispatch::handle_request::(&mut req, |params, resp| { io.send(RawMsg::Response(resp.into_response(Ok(None))?)); diff --git a/crates/server/src/req.rs b/crates/server/src/req.rs index a22ba4bc31..a8cc9b537b 100644 --- a/crates/server/src/req.rs +++ b/crates/server/src/req.rs @@ -8,6 +8,7 @@ pub use languageserver_types::{ DocumentSymbolParams, DocumentSymbolResponse, CodeActionParams, ApplyWorkspaceEditParams, ExecuteCommandParams, + WorkspaceSymbolParams, };