diff options
author | Aleksey Kladov <[email protected]> | 2018-08-13 13:35:53 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2018-08-13 13:35:53 +0100 |
commit | d19f3ac83441420365bff5e4ce21d1d2175bd8c2 (patch) | |
tree | 0523dc698784bb2501998956f8111b31f4e0387b | |
parent | 133d001d8296e51bcb4d0dc0982671f55c2c77d9 (diff) |
workspace symbols
-rw-r--r-- | code/src/extension.ts | 6 | ||||
-rw-r--r-- | crates/libanalysis/src/lib.rs | 29 | ||||
-rw-r--r-- | crates/libanalysis/src/symbol_index.rs | 28 | ||||
-rw-r--r-- | crates/server/src/caps.rs | 2 | ||||
-rw-r--r-- | crates/server/src/dispatch.rs | 15 | ||||
-rw-r--r-- | crates/server/src/main.rs | 4 | ||||
-rw-r--r-- | crates/server/src/main_loop/handlers.rs | 29 | ||||
-rw-r--r-- | crates/server/src/main_loop/mod.rs | 4 | ||||
-rw-r--r-- | 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 dd0c29f14..bb724539d 100644 --- a/code/src/extension.ts +++ b/code/src/extension.ts | |||
@@ -61,9 +61,9 @@ export function deactivate(): Thenable<void> { | |||
61 | 61 | ||
62 | function startServer() { | 62 | function startServer() { |
63 | let run: lc.Executable = { | 63 | let run: lc.Executable = { |
64 | command: "cargo", | 64 | // command: "cargo", |
65 | args: ["run", "--package", "m"], | 65 | // args: ["run", "--package", "m"], |
66 | // command: "m", | 66 | command: "m", |
67 | options: { cwd: "." } | 67 | options: { cwd: "." } |
68 | } | 68 | } |
69 | let serverOptions: lc.ServerOptions = { | 69 | let serverOptions: lc.ServerOptions = { |
diff --git a/crates/libanalysis/src/lib.rs b/crates/libanalysis/src/lib.rs index f0d0cf0a4..acaadb8a2 100644 --- a/crates/libanalysis/src/lib.rs +++ b/crates/libanalysis/src/lib.rs | |||
@@ -89,14 +89,15 @@ impl World { | |||
89 | Ok(index.clone()) | 89 | Ok(index.clone()) |
90 | } | 90 | } |
91 | 91 | ||
92 | pub fn world_symbols(&self, query: &str, f: &mut FnMut(&Path, &FileSymbol) -> Search) { | 92 | pub fn world_symbols<'a>(&'a self, query: &str) -> impl Iterator<Item=(&'a Path, &'a FileSymbol)> + 'a |
93 | { | ||
93 | let q = Query::new(query); | 94 | let q = Query::new(query); |
94 | for (path, data) in self.data.file_map.iter() { | 95 | self.data.file_map.iter() |
95 | let symbols = data.symbols(path.as_path()); | 96 | .flat_map(move |(path, data)| { |
96 | if q.process(symbols, &mut |symbol| f(path, symbol)) == Search::Break { | 97 | let path: &'a Path = path.as_path(); |
97 | break; | 98 | let symbols = data.symbols(path); |
98 | } | 99 | q.process(symbols).map(move |s| (path, s)) |
99 | } | 100 | }) |
100 | } | 101 | } |
101 | 102 | ||
102 | fn file_data(&self, path: &Path) -> Result<Arc<FileData>> { | 103 | fn file_data(&self, path: &Path) -> Result<Arc<FileData>> { |
@@ -107,11 +108,15 @@ impl World { | |||
107 | } | 108 | } |
108 | } | 109 | } |
109 | 110 | ||
110 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 111 | |
111 | pub enum Search { | 112 | pub type SearchResult = ::std::result::Result<Continue, Break>; |
112 | Continue, | 113 | |
113 | Break, | 114 | pub struct Continue; |
114 | } | 115 | |
116 | pub struct Break; | ||
117 | |||
118 | pub const CONTINUE: SearchResult = Ok(Continue); | ||
119 | pub const BREAK: SearchResult = Err(Break); | ||
115 | 120 | ||
116 | 121 | ||
117 | #[derive(Default, Debug)] | 122 | #[derive(Default, Debug)] |
diff --git a/crates/libanalysis/src/symbol_index.rs b/crates/libanalysis/src/symbol_index.rs index 1878fae99..4d90aac0c 100644 --- a/crates/libanalysis/src/symbol_index.rs +++ b/crates/libanalysis/src/symbol_index.rs | |||
@@ -5,8 +5,6 @@ use libsyntax2::{ | |||
5 | }; | 5 | }; |
6 | use fst::{self, IntoStreamer}; | 6 | use fst::{self, IntoStreamer}; |
7 | 7 | ||
8 | use Search; | ||
9 | |||
10 | #[derive(Debug)] | 8 | #[derive(Debug)] |
11 | pub(crate) struct FileSymbols { | 9 | pub(crate) struct FileSymbols { |
12 | symbols: Vec<FileSymbol>, | 10 | symbols: Vec<FileSymbol>, |
@@ -47,11 +45,10 @@ impl Query { | |||
47 | Query { query, all_symbols } | 45 | Query { query, all_symbols } |
48 | } | 46 | } |
49 | 47 | ||
50 | pub(crate) fn process( | 48 | pub(crate) fn process<'a>( |
51 | &self, | 49 | &self, |
52 | file: &FileSymbols, | 50 | file: &'a FileSymbols, |
53 | acc: &mut FnMut(&FileSymbol) -> Search, | 51 | ) -> impl Iterator<Item=&'a FileSymbol> + 'a { |
54 | ) -> Search { | ||
55 | fn is_type(kind: SyntaxKind) -> bool { | 52 | fn is_type(kind: SyntaxKind) -> bool { |
56 | match kind { | 53 | match kind { |
57 | STRUCT | ENUM | TRAIT | TYPE_ITEM => true, | 54 | STRUCT | ENUM | TRAIT | TYPE_ITEM => true, |
@@ -59,16 +56,15 @@ impl Query { | |||
59 | } | 56 | } |
60 | } | 57 | } |
61 | let automaton = fst::automaton::Subsequence::new(&self.query); | 58 | let automaton = fst::automaton::Subsequence::new(&self.query); |
62 | for idx in file.map.search(automaton).into_stream().into_values() { | 59 | let all_symbols = self.all_symbols; |
63 | let idx = idx as usize; | 60 | file.map.search(automaton).into_stream() |
64 | let symbol = &file.symbols[idx]; | 61 | .into_values() |
65 | if self.all_symbols || is_type(symbol.kind) { | 62 | .into_iter() |
66 | if acc(&symbol) == Search::Break { | 63 | .map(move |idx| { |
67 | return Search::Break; | 64 | let idx = idx as usize; |
68 | } | 65 | &file.symbols[idx] |
69 | } | 66 | }) |
70 | } | 67 | .filter(move |s| all_symbols || is_type(s.kind)) |
71 | Search::Continue | ||
72 | } | 68 | } |
73 | } | 69 | } |
74 | 70 | ||
diff --git a/crates/server/src/caps.rs b/crates/server/src/caps.rs index d06a43a82..4fd28b7c8 100644 --- a/crates/server/src/caps.rs +++ b/crates/server/src/caps.rs | |||
@@ -26,7 +26,7 @@ pub fn server_capabilities() -> ServerCapabilities { | |||
26 | references_provider: None, | 26 | references_provider: None, |
27 | document_highlight_provider: None, | 27 | document_highlight_provider: None, |
28 | document_symbol_provider: Some(true), | 28 | document_symbol_provider: Some(true), |
29 | workspace_symbol_provider: None, | 29 | workspace_symbol_provider: Some(true), |
30 | code_action_provider: Some(true), | 30 | code_action_provider: Some(true), |
31 | code_lens_provider: None, | 31 | code_lens_provider: None, |
32 | document_formatting_provider: None, | 32 | document_formatting_provider: None, |
diff --git a/crates/server/src/dispatch.rs b/crates/server/src/dispatch.rs index 3a3ee74bb..d8cca48d0 100644 --- a/crates/server/src/dispatch.rs +++ b/crates/server/src/dispatch.rs | |||
@@ -30,8 +30,12 @@ impl<R: ClientRequest> Responder<R> { | |||
30 | error: serde_json::Value::Null, | 30 | error: serde_json::Value::Null, |
31 | } | 31 | } |
32 | } | 32 | } |
33 | Err(_) => { | 33 | Err(e) => { |
34 | error_response(self.id, ErrorCode::InternalError, "internal error")? | 34 | error_response( |
35 | self.id, | ||
36 | ErrorCode::InternalError, | ||
37 | format!("internal error: {}", e), | ||
38 | )? | ||
35 | } | 39 | } |
36 | }; | 40 | }; |
37 | Ok(res) | 41 | Ok(res) |
@@ -115,21 +119,20 @@ pub fn send_notification<N>(params: N::Params) -> RawNotification | |||
115 | 119 | ||
116 | pub fn unknown_method(id: u64) -> Result<RawResponse> { | 120 | pub fn unknown_method(id: u64) -> Result<RawResponse> { |
117 | error_response(id, ErrorCode::MethodNotFound, "unknown method") | 121 | error_response(id, ErrorCode::MethodNotFound, "unknown method") |
118 | |||
119 | } | 122 | } |
120 | 123 | ||
121 | fn error_response(id: u64, code: ErrorCode, message: &'static str) -> Result<RawResponse> { | 124 | fn error_response(id: u64, code: ErrorCode, message: impl Into<String>) -> Result<RawResponse> { |
122 | #[derive(Serialize)] | 125 | #[derive(Serialize)] |
123 | struct Error { | 126 | struct Error { |
124 | code: i32, | 127 | code: i32, |
125 | message: &'static str, | 128 | message: String, |
126 | } | 129 | } |
127 | let resp = RawResponse { | 130 | let resp = RawResponse { |
128 | id, | 131 | id, |
129 | result: serde_json::Value::Null, | 132 | result: serde_json::Value::Null, |
130 | error: serde_json::to_value(Error { | 133 | error: serde_json::to_value(Error { |
131 | code: code as i32, | 134 | code: code as i32, |
132 | message, | 135 | message: message.into(), |
133 | })?, | 136 | })?, |
134 | }; | 137 | }; |
135 | Ok(resp) | 138 | Ok(resp) |
diff --git a/crates/server/src/main.rs b/crates/server/src/main.rs index 8dca32183..9c044d5a9 100644 --- a/crates/server/src/main.rs +++ b/crates/server/src/main.rs | |||
@@ -27,8 +27,6 @@ mod conv; | |||
27 | mod main_loop; | 27 | mod main_loop; |
28 | mod vfs; | 28 | mod vfs; |
29 | 29 | ||
30 | use std::path::PathBuf; | ||
31 | |||
32 | use threadpool::ThreadPool; | 30 | use threadpool::ThreadPool; |
33 | use crossbeam_channel::bounded; | 31 | use crossbeam_channel::bounded; |
34 | use flexi_logger::{Logger, Duplicate}; | 32 | use flexi_logger::{Logger, Duplicate}; |
@@ -120,7 +118,7 @@ fn initialized(io: &mut Io) -> Result<()> { | |||
120 | let mut pool = ThreadPool::new(4); | 118 | let mut pool = ThreadPool::new(4); |
121 | let (task_sender, task_receiver) = bounded::<Task>(16); | 119 | let (task_sender, task_receiver) = bounded::<Task>(16); |
122 | let (fs_events_receiver, watcher) = vfs::watch(vec![ | 120 | let (fs_events_receiver, watcher) = vfs::watch(vec![ |
123 | PathBuf::from("./") | 121 | ::std::env::current_dir()?, |
124 | ]); | 122 | ]); |
125 | info!("lifecycle: handshake finished, server ready to serve requests"); | 123 | info!("lifecycle: handshake finished, server ready to serve requests"); |
126 | let res = main_loop::main_loop( | 124 | 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 14dcafc38..bd0e6825b 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; | |||
2 | 2 | ||
3 | use languageserver_types::{ | 3 | use languageserver_types::{ |
4 | Diagnostic, DiagnosticSeverity, Url, DocumentSymbol, | 4 | Diagnostic, DiagnosticSeverity, Url, DocumentSymbol, |
5 | Command, TextDocumentIdentifier, WorkspaceEdit | 5 | Command, TextDocumentIdentifier, WorkspaceEdit, |
6 | SymbolInformation, Location, | ||
6 | }; | 7 | }; |
7 | use libanalysis::World; | 8 | use libanalysis::{World}; |
8 | use libeditor; | 9 | use libeditor; |
9 | use libsyntax2::TextUnit; | 10 | use libsyntax2::TextUnit; |
10 | use serde_json::{to_value, from_value}; | 11 | use serde_json::{to_value, from_value}; |
@@ -94,6 +95,30 @@ pub fn handle_code_action( | |||
94 | Ok(ret) | 95 | Ok(ret) |
95 | } | 96 | } |
96 | 97 | ||
98 | pub fn handle_workspace_symbol( | ||
99 | world: World, | ||
100 | params: req::WorkspaceSymbolParams, | ||
101 | ) -> Result<Option<Vec<SymbolInformation>>> { | ||
102 | let mut acc = Vec::new(); | ||
103 | for (path, symbol) in world.world_symbols(¶ms.query).take(128) { | ||
104 | let line_index = world.file_line_index(path)?; | ||
105 | |||
106 | let info = SymbolInformation { | ||
107 | name: symbol.name.to_string(), | ||
108 | kind: symbol.kind.conv(), | ||
109 | location: Location::new( | ||
110 | Url::from_file_path(path) | ||
111 | .map_err(|()| format_err!("invalid url"))?, | ||
112 | symbol.node_range.conv_with(&line_index), | ||
113 | ), | ||
114 | container_name: None, | ||
115 | }; | ||
116 | acc.push(info); | ||
117 | }; | ||
118 | |||
119 | Ok(Some(acc)) | ||
120 | } | ||
121 | |||
97 | pub fn handle_execute_command( | 122 | pub fn handle_execute_command( |
98 | world: World, | 123 | world: World, |
99 | mut params: req::ExecuteCommandParams, | 124 | mut params: req::ExecuteCommandParams, |
diff --git a/crates/server/src/main_loop/mod.rs b/crates/server/src/main_loop/mod.rs index f954e632c..e8b24355c 100644 --- a/crates/server/src/main_loop/mod.rs +++ b/crates/server/src/main_loop/mod.rs | |||
@@ -25,6 +25,7 @@ use { | |||
25 | handle_document_symbol, | 25 | handle_document_symbol, |
26 | handle_code_action, | 26 | handle_code_action, |
27 | handle_execute_command, | 27 | handle_execute_command, |
28 | handle_workspace_symbol, | ||
28 | }, | 29 | }, |
29 | }; | 30 | }; |
30 | 31 | ||
@@ -148,6 +149,9 @@ fn on_request( | |||
148 | handle_request_on_threadpool::<req::CodeActionRequest>( | 149 | handle_request_on_threadpool::<req::CodeActionRequest>( |
149 | &mut req, pool, world, sender, handle_code_action, | 150 | &mut req, pool, world, sender, handle_code_action, |
150 | )?; | 151 | )?; |
152 | handle_request_on_threadpool::<req::WorkspaceSymbol>( | ||
153 | &mut req, pool, world, sender, handle_workspace_symbol, | ||
154 | )?; | ||
151 | dispatch::handle_request::<req::ExecuteCommand, _>(&mut req, |params, resp| { | 155 | dispatch::handle_request::<req::ExecuteCommand, _>(&mut req, |params, resp| { |
152 | io.send(RawMsg::Response(resp.into_response(Ok(None))?)); | 156 | io.send(RawMsg::Response(resp.into_response(Ok(None))?)); |
153 | 157 | ||
diff --git a/crates/server/src/req.rs b/crates/server/src/req.rs index a22ba4bc3..a8cc9b537 100644 --- a/crates/server/src/req.rs +++ b/crates/server/src/req.rs | |||
@@ -8,6 +8,7 @@ pub use languageserver_types::{ | |||
8 | DocumentSymbolParams, DocumentSymbolResponse, | 8 | DocumentSymbolParams, DocumentSymbolResponse, |
9 | CodeActionParams, ApplyWorkspaceEditParams, | 9 | CodeActionParams, ApplyWorkspaceEditParams, |
10 | ExecuteCommandParams, | 10 | ExecuteCommandParams, |
11 | WorkspaceSymbolParams, | ||
11 | }; | 12 | }; |
12 | 13 | ||
13 | 14 | ||