workspace symbols

This commit is contained in:
Aleksey Kladov 2018-08-13 15:35:53 +03:00
parent 133d001d82
commit d19f3ac834
9 changed files with 75 additions and 43 deletions

View File

@ -61,9 +61,9 @@ export function deactivate(): Thenable<void> {
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 = {

View File

@ -89,14 +89,15 @@ pub fn file_line_index(&self, path: &Path) -> Result<LineIndex> {
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<Item=(&'a Path, &'a FileSymbol)> + '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<Arc<FileData>> {
@ -107,11 +108,15 @@ fn file_data(&self, path: &Path) -> Result<Arc<FileData>> {
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Search {
Continue,
Break,
}
pub type SearchResult = ::std::result::Result<Continue, Break>;
pub struct Continue;
pub struct Break;
pub const CONTINUE: SearchResult = Ok(Continue);
pub const BREAK: SearchResult = Err(Break);
#[derive(Default, Debug)]

View File

@ -5,8 +5,6 @@
};
use fst::{self, IntoStreamer};
use Search;
#[derive(Debug)]
pub(crate) struct FileSymbols {
symbols: Vec<FileSymbol>,
@ -47,11 +45,10 @@ pub(crate) fn new(query: &str) -> 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<Item=&'a FileSymbol> + 'a {
fn is_type(kind: SyntaxKind) -> bool {
match kind {
STRUCT | ENUM | TRAIT | TYPE_ITEM => true,
@ -59,16 +56,15 @@ fn is_type(kind: SyntaxKind) -> bool {
}
}
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))
}
}

View File

@ -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,

View File

@ -30,8 +30,12 @@ pub fn into_response(mut self, result: Result<R::Result>) -> Result<RawResponse>
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<N>(params: N::Params) -> RawNotification
pub fn unknown_method(id: u64) -> Result<RawResponse> {
error_response(id, ErrorCode::MethodNotFound, "unknown method")
}
fn error_response(id: u64, code: ErrorCode, message: &'static str) -> Result<RawResponse> {
fn error_response(id: u64, code: ErrorCode, message: impl Into<String>) -> Result<RawResponse> {
#[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)

View File

@ -27,8 +27,6 @@
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::<Task>(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(

View File

@ -2,9 +2,10 @@
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<Option<Vec<SymbolInformation>>> {
let mut acc = Vec::new();
for (path, symbol) in world.world_symbols(&params.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,

View File

@ -25,6 +25,7 @@
handle_document_symbol,
handle_code_action,
handle_execute_command,
handle_workspace_symbol,
},
};
@ -148,6 +149,9 @@ fn on_request(
handle_request_on_threadpool::<req::CodeActionRequest>(
&mut req, pool, world, sender, handle_code_action,
)?;
handle_request_on_threadpool::<req::WorkspaceSymbol>(
&mut req, pool, world, sender, handle_workspace_symbol,
)?;
dispatch::handle_request::<req::ExecuteCommand, _>(&mut req, |params, resp| {
io.send(RawMsg::Response(resp.into_response(Ok(None))?));

View File

@ -8,6 +8,7 @@
DocumentSymbolParams, DocumentSymbolResponse,
CodeActionParams, ApplyWorkspaceEditParams,
ExecuteCommandParams,
WorkspaceSymbolParams,
};