mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-27 04:15:08 +00:00
workspace symbols
This commit is contained in:
parent
133d001d82
commit
d19f3ac834
9 changed files with 75 additions and 43 deletions
|
@ -61,9 +61,9 @@ export function deactivate(): Thenable<void> {
|
||||||
|
|
||||||
function startServer() {
|
function startServer() {
|
||||||
let run: lc.Executable = {
|
let run: lc.Executable = {
|
||||||
command: "cargo",
|
// command: "cargo",
|
||||||
args: ["run", "--package", "m"],
|
// args: ["run", "--package", "m"],
|
||||||
// command: "m",
|
command: "m",
|
||||||
options: { cwd: "." }
|
options: { cwd: "." }
|
||||||
}
|
}
|
||||||
let serverOptions: lc.ServerOptions = {
|
let serverOptions: lc.ServerOptions = {
|
||||||
|
|
|
@ -89,14 +89,15 @@ impl World {
|
||||||
Ok(index.clone())
|
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);
|
let q = Query::new(query);
|
||||||
for (path, data) in self.data.file_map.iter() {
|
self.data.file_map.iter()
|
||||||
let symbols = data.symbols(path.as_path());
|
.flat_map(move |(path, data)| {
|
||||||
if q.process(symbols, &mut |symbol| f(path, symbol)) == Search::Break {
|
let path: &'a Path = path.as_path();
|
||||||
break;
|
let symbols = data.symbols(path);
|
||||||
}
|
q.process(symbols).map(move |s| (path, s))
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn file_data(&self, path: &Path) -> Result<Arc<FileData>> {
|
fn file_data(&self, path: &Path) -> Result<Arc<FileData>> {
|
||||||
|
@ -107,11 +108,15 @@ impl World {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
||||||
pub enum Search {
|
pub type SearchResult = ::std::result::Result<Continue, Break>;
|
||||||
Continue,
|
|
||||||
Break,
|
pub struct Continue;
|
||||||
}
|
|
||||||
|
pub struct Break;
|
||||||
|
|
||||||
|
pub const CONTINUE: SearchResult = Ok(Continue);
|
||||||
|
pub const BREAK: SearchResult = Err(Break);
|
||||||
|
|
||||||
|
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
|
|
|
@ -5,8 +5,6 @@ use libsyntax2::{
|
||||||
};
|
};
|
||||||
use fst::{self, IntoStreamer};
|
use fst::{self, IntoStreamer};
|
||||||
|
|
||||||
use Search;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct FileSymbols {
|
pub(crate) struct FileSymbols {
|
||||||
symbols: Vec<FileSymbol>,
|
symbols: Vec<FileSymbol>,
|
||||||
|
@ -47,11 +45,10 @@ impl Query {
|
||||||
Query { query, all_symbols }
|
Query { query, all_symbols }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn process(
|
pub(crate) fn process<'a>(
|
||||||
&self,
|
&self,
|
||||||
file: &FileSymbols,
|
file: &'a FileSymbols,
|
||||||
acc: &mut FnMut(&FileSymbol) -> Search,
|
) -> impl Iterator<Item=&'a FileSymbol> + 'a {
|
||||||
) -> Search {
|
|
||||||
fn is_type(kind: SyntaxKind) -> bool {
|
fn is_type(kind: SyntaxKind) -> bool {
|
||||||
match kind {
|
match kind {
|
||||||
STRUCT | ENUM | TRAIT | TYPE_ITEM => true,
|
STRUCT | ENUM | TRAIT | TYPE_ITEM => true,
|
||||||
|
@ -59,16 +56,15 @@ impl Query {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let automaton = fst::automaton::Subsequence::new(&self.query);
|
let automaton = fst::automaton::Subsequence::new(&self.query);
|
||||||
for idx in file.map.search(automaton).into_stream().into_values() {
|
let all_symbols = self.all_symbols;
|
||||||
let idx = idx as usize;
|
file.map.search(automaton).into_stream()
|
||||||
let symbol = &file.symbols[idx];
|
.into_values()
|
||||||
if self.all_symbols || is_type(symbol.kind) {
|
.into_iter()
|
||||||
if acc(&symbol) == Search::Break {
|
.map(move |idx| {
|
||||||
return Search::Break;
|
let idx = idx as usize;
|
||||||
}
|
&file.symbols[idx]
|
||||||
}
|
})
|
||||||
}
|
.filter(move |s| all_symbols || is_type(s.kind))
|
||||||
Search::Continue
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ pub fn server_capabilities() -> ServerCapabilities {
|
||||||
references_provider: None,
|
references_provider: None,
|
||||||
document_highlight_provider: None,
|
document_highlight_provider: None,
|
||||||
document_symbol_provider: Some(true),
|
document_symbol_provider: Some(true),
|
||||||
workspace_symbol_provider: None,
|
workspace_symbol_provider: Some(true),
|
||||||
code_action_provider: Some(true),
|
code_action_provider: Some(true),
|
||||||
code_lens_provider: None,
|
code_lens_provider: None,
|
||||||
document_formatting_provider: None,
|
document_formatting_provider: None,
|
||||||
|
|
|
@ -30,8 +30,12 @@ impl<R: ClientRequest> Responder<R> {
|
||||||
error: serde_json::Value::Null,
|
error: serde_json::Value::Null,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(_) => {
|
Err(e) => {
|
||||||
error_response(self.id, ErrorCode::InternalError, "internal error")?
|
error_response(
|
||||||
|
self.id,
|
||||||
|
ErrorCode::InternalError,
|
||||||
|
format!("internal error: {}", e),
|
||||||
|
)?
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Ok(res)
|
Ok(res)
|
||||||
|
@ -115,21 +119,20 @@ pub fn send_notification<N>(params: N::Params) -> RawNotification
|
||||||
|
|
||||||
pub fn unknown_method(id: u64) -> Result<RawResponse> {
|
pub fn unknown_method(id: u64) -> Result<RawResponse> {
|
||||||
error_response(id, ErrorCode::MethodNotFound, "unknown method")
|
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)]
|
#[derive(Serialize)]
|
||||||
struct Error {
|
struct Error {
|
||||||
code: i32,
|
code: i32,
|
||||||
message: &'static str,
|
message: String,
|
||||||
}
|
}
|
||||||
let resp = RawResponse {
|
let resp = RawResponse {
|
||||||
id,
|
id,
|
||||||
result: serde_json::Value::Null,
|
result: serde_json::Value::Null,
|
||||||
error: serde_json::to_value(Error {
|
error: serde_json::to_value(Error {
|
||||||
code: code as i32,
|
code: code as i32,
|
||||||
message,
|
message: message.into(),
|
||||||
})?,
|
})?,
|
||||||
};
|
};
|
||||||
Ok(resp)
|
Ok(resp)
|
||||||
|
|
|
@ -27,8 +27,6 @@ mod conv;
|
||||||
mod main_loop;
|
mod main_loop;
|
||||||
mod vfs;
|
mod vfs;
|
||||||
|
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
use threadpool::ThreadPool;
|
use threadpool::ThreadPool;
|
||||||
use crossbeam_channel::bounded;
|
use crossbeam_channel::bounded;
|
||||||
use flexi_logger::{Logger, Duplicate};
|
use flexi_logger::{Logger, Duplicate};
|
||||||
|
@ -120,7 +118,7 @@ fn initialized(io: &mut Io) -> Result<()> {
|
||||||
let mut pool = ThreadPool::new(4);
|
let mut pool = ThreadPool::new(4);
|
||||||
let (task_sender, task_receiver) = bounded::<Task>(16);
|
let (task_sender, task_receiver) = bounded::<Task>(16);
|
||||||
let (fs_events_receiver, watcher) = vfs::watch(vec![
|
let (fs_events_receiver, watcher) = vfs::watch(vec![
|
||||||
PathBuf::from("./")
|
::std::env::current_dir()?,
|
||||||
]);
|
]);
|
||||||
info!("lifecycle: handshake finished, server ready to serve requests");
|
info!("lifecycle: handshake finished, server ready to serve requests");
|
||||||
let res = main_loop::main_loop(
|
let res = main_loop::main_loop(
|
||||||
|
|
|
@ -2,9 +2,10 @@ use std::collections::HashMap;
|
||||||
|
|
||||||
use languageserver_types::{
|
use languageserver_types::{
|
||||||
Diagnostic, DiagnosticSeverity, Url, DocumentSymbol,
|
Diagnostic, DiagnosticSeverity, Url, DocumentSymbol,
|
||||||
Command, TextDocumentIdentifier, WorkspaceEdit
|
Command, TextDocumentIdentifier, WorkspaceEdit,
|
||||||
|
SymbolInformation, Location,
|
||||||
};
|
};
|
||||||
use libanalysis::World;
|
use libanalysis::{World};
|
||||||
use libeditor;
|
use libeditor;
|
||||||
use libsyntax2::TextUnit;
|
use libsyntax2::TextUnit;
|
||||||
use serde_json::{to_value, from_value};
|
use serde_json::{to_value, from_value};
|
||||||
|
@ -94,6 +95,30 @@ pub fn handle_code_action(
|
||||||
Ok(ret)
|
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(¶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(
|
pub fn handle_execute_command(
|
||||||
world: World,
|
world: World,
|
||||||
mut params: req::ExecuteCommandParams,
|
mut params: req::ExecuteCommandParams,
|
||||||
|
|
|
@ -25,6 +25,7 @@ use {
|
||||||
handle_document_symbol,
|
handle_document_symbol,
|
||||||
handle_code_action,
|
handle_code_action,
|
||||||
handle_execute_command,
|
handle_execute_command,
|
||||||
|
handle_workspace_symbol,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -148,6 +149,9 @@ fn on_request(
|
||||||
handle_request_on_threadpool::<req::CodeActionRequest>(
|
handle_request_on_threadpool::<req::CodeActionRequest>(
|
||||||
&mut req, pool, world, sender, handle_code_action,
|
&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| {
|
dispatch::handle_request::<req::ExecuteCommand, _>(&mut req, |params, resp| {
|
||||||
io.send(RawMsg::Response(resp.into_response(Ok(None))?));
|
io.send(RawMsg::Response(resp.into_response(Ok(None))?));
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ pub use languageserver_types::{
|
||||||
DocumentSymbolParams, DocumentSymbolResponse,
|
DocumentSymbolParams, DocumentSymbolResponse,
|
||||||
CodeActionParams, ApplyWorkspaceEditParams,
|
CodeActionParams, ApplyWorkspaceEditParams,
|
||||||
ExecuteCommandParams,
|
ExecuteCommandParams,
|
||||||
|
WorkspaceSymbolParams,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue