aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2018-08-13 13:35:53 +0100
committerAleksey Kladov <[email protected]>2018-08-13 13:35:53 +0100
commitd19f3ac83441420365bff5e4ce21d1d2175bd8c2 (patch)
tree0523dc698784bb2501998956f8111b31f4e0387b
parent133d001d8296e51bcb4d0dc0982671f55c2c77d9 (diff)
workspace symbols
-rw-r--r--code/src/extension.ts6
-rw-r--r--crates/libanalysis/src/lib.rs29
-rw-r--r--crates/libanalysis/src/symbol_index.rs28
-rw-r--r--crates/server/src/caps.rs2
-rw-r--r--crates/server/src/dispatch.rs15
-rw-r--r--crates/server/src/main.rs4
-rw-r--r--crates/server/src/main_loop/handlers.rs29
-rw-r--r--crates/server/src/main_loop/mod.rs4
-rw-r--r--crates/server/src/req.rs1
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
62function startServer() { 62function 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
111pub enum Search { 112pub type SearchResult = ::std::result::Result<Continue, Break>;
112 Continue, 113
113 Break, 114pub struct Continue;
114} 115
116pub struct Break;
117
118pub const CONTINUE: SearchResult = Ok(Continue);
119pub 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};
6use fst::{self, IntoStreamer}; 6use fst::{self, IntoStreamer};
7 7
8use Search;
9
10#[derive(Debug)] 8#[derive(Debug)]
11pub(crate) struct FileSymbols { 9pub(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
116pub fn unknown_method(id: u64) -> Result<RawResponse> { 120pub 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
121fn error_response(id: u64, code: ErrorCode, message: &'static str) -> Result<RawResponse> { 124fn 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;
27mod main_loop; 27mod main_loop;
28mod vfs; 28mod vfs;
29 29
30use std::path::PathBuf;
31
32use threadpool::ThreadPool; 30use threadpool::ThreadPool;
33use crossbeam_channel::bounded; 31use crossbeam_channel::bounded;
34use flexi_logger::{Logger, Duplicate}; 32use 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
3use languageserver_types::{ 3use 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};
7use libanalysis::World; 8use libanalysis::{World};
8use libeditor; 9use libeditor;
9use libsyntax2::TextUnit; 10use libsyntax2::TextUnit;
10use serde_json::{to_value, from_value}; 11use 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
98pub 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(&params.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
97pub fn handle_execute_command( 122pub 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