mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-25 12:33:33 +00:00
Stupid goto definition
This commit is contained in:
parent
7fc91f41d8
commit
8ae56fa6d0
9 changed files with 109 additions and 14 deletions
|
@ -18,10 +18,14 @@ use std::{
|
|||
path::{PathBuf, Path},
|
||||
};
|
||||
|
||||
use libsyntax2::ast;
|
||||
use libsyntax2::{
|
||||
TextUnit,
|
||||
ast::{self, AstNode},
|
||||
algo::{find_leaf_at_offset, ancestors},
|
||||
};
|
||||
use libeditor::{LineIndex, FileSymbol};
|
||||
|
||||
use self::symbol_index::{FileSymbols};
|
||||
use self::symbol_index::FileSymbols;
|
||||
pub use self::symbol_index::Query;
|
||||
|
||||
pub type Result<T> = ::std::result::Result<T, ::failure::Error>;
|
||||
|
@ -90,8 +94,7 @@ impl World {
|
|||
Ok(index.clone())
|
||||
}
|
||||
|
||||
pub fn world_symbols<'a>(&'a self, query: Query) -> impl Iterator<Item=(&'a Path, &'a FileSymbol)> + 'a
|
||||
{
|
||||
pub fn world_symbols<'a>(&'a self, query: Query) -> impl Iterator<Item=(&'a Path, &'a FileSymbol)> + 'a {
|
||||
self.data.file_map.iter()
|
||||
.flat_map(move |(path, data)| {
|
||||
let path: &'a Path = path.as_path();
|
||||
|
@ -100,6 +103,31 @@ impl World {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn approximately_resolve_symbol<'a>(
|
||||
&'a self,
|
||||
path: &Path,
|
||||
offset: TextUnit,
|
||||
) -> Result<Vec<(&'a Path, &'a FileSymbol)>> {
|
||||
let file = self.file_syntax(path)?;
|
||||
let syntax = file.syntax();
|
||||
let syntax = syntax.as_ref();
|
||||
let name_ref =
|
||||
find_leaf_at_offset(syntax, offset)
|
||||
.left_biased()
|
||||
.into_iter()
|
||||
.flat_map(|node| ancestors(node))
|
||||
.flat_map(ast::NameRef::cast)
|
||||
.next();
|
||||
let name = match name_ref {
|
||||
None => return Ok(vec![]),
|
||||
Some(name_ref) => name_ref.text(),
|
||||
};
|
||||
|
||||
let mut query = Query::new(name.to_string());
|
||||
query.exact();
|
||||
Ok(self.world_symbols(query).take(4).collect())
|
||||
}
|
||||
|
||||
fn file_data(&self, path: &Path) -> Result<Arc<FileData>> {
|
||||
match self.data.file_map.get(path) {
|
||||
Some(data) => Ok(data.clone()),
|
||||
|
|
|
@ -123,6 +123,24 @@ impl<R: TreeRoot> AstNode<R> for Name<R> {
|
|||
|
||||
impl<R: TreeRoot> Name<R> {}
|
||||
|
||||
// NameRef
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct NameRef<R: TreeRoot = Arc<SyntaxRoot>> {
|
||||
syntax: SyntaxNode<R>,
|
||||
}
|
||||
|
||||
impl<R: TreeRoot> AstNode<R> for NameRef<R> {
|
||||
fn cast(syntax: SyntaxNode<R>) -> Option<Self> {
|
||||
match syntax.kind() {
|
||||
NAME_REF => Some(NameRef { syntax }),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
fn syntax(&self) -> &SyntaxNode<R> { &self.syntax }
|
||||
}
|
||||
|
||||
impl<R: TreeRoot> NameRef<R> {}
|
||||
|
||||
// StaticItem
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct StaticItem<R: TreeRoot = Arc<SyntaxRoot>> {
|
||||
|
|
|
@ -73,3 +73,11 @@ impl<R: TreeRoot> Name<R> {
|
|||
ident.leaf_text().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: TreeRoot> NameRef<R> {
|
||||
pub fn text(&self) -> SmolStr {
|
||||
let ident = self.syntax().first_child()
|
||||
.unwrap();
|
||||
ident.leaf_text().unwrap()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -228,5 +228,6 @@ Grammar(
|
|||
"StaticItem": ( traits: ["NameOwner"] ),
|
||||
"TypeItem": ( traits: ["NameOwner"] ),
|
||||
"Name": (),
|
||||
"NameRef": (),
|
||||
},
|
||||
)
|
||||
|
|
|
@ -20,7 +20,7 @@ pub fn server_capabilities() -> ServerCapabilities {
|
|||
hover_provider: None,
|
||||
completion_provider: None,
|
||||
signature_help_provider: None,
|
||||
definition_provider: None,
|
||||
definition_provider: Some(true),
|
||||
type_definition_provider: None,
|
||||
implementation_provider: None,
|
||||
references_provider: None,
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
use languageserver_types::{Range, SymbolKind, Position, TextEdit};
|
||||
use std::path::Path;
|
||||
|
||||
use languageserver_types::{Range, SymbolKind, Position, TextEdit, Location, Url};
|
||||
use libeditor::{LineIndex, LineCol, Edit, AtomEdit};
|
||||
use libsyntax2::{SyntaxKind, TextUnit, TextRange};
|
||||
|
||||
use Result;
|
||||
|
||||
pub trait Conv {
|
||||
type Output;
|
||||
fn conv(self) -> Self::Output;
|
||||
|
@ -13,6 +17,12 @@ pub trait ConvWith {
|
|||
fn conv_with(self, ctx: &Self::Ctx) -> Self::Output;
|
||||
}
|
||||
|
||||
pub trait TryConvWith {
|
||||
type Ctx;
|
||||
type Output;
|
||||
fn try_conv_with(self, ctx: &Self::Ctx) -> Result<Self::Output>;
|
||||
}
|
||||
|
||||
impl Conv for SyntaxKind {
|
||||
type Output = SymbolKind;
|
||||
|
||||
|
@ -104,6 +114,20 @@ impl ConvWith for AtomEdit {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> TryConvWith for (&'a Path, TextRange) {
|
||||
type Ctx = LineIndex;
|
||||
type Output = Location;
|
||||
|
||||
fn try_conv_with(self, line_index: &LineIndex) -> Result<Location> {
|
||||
let loc = Location::new(
|
||||
Url::from_file_path(self.0)
|
||||
.map_err(|()| format_err!("can't convert path to url: {}", self.0.display()))?,
|
||||
self.1.conv_with(line_index),
|
||||
);
|
||||
Ok(loc)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub trait MapConvWith<'a>: Sized {
|
||||
type Ctx;
|
||||
|
|
|
@ -3,7 +3,7 @@ use std::collections::HashMap;
|
|||
use languageserver_types::{
|
||||
Diagnostic, DiagnosticSeverity, Url, DocumentSymbol,
|
||||
Command, TextDocumentIdentifier, WorkspaceEdit,
|
||||
SymbolInformation, Location,
|
||||
SymbolInformation,
|
||||
};
|
||||
use libanalysis::{World, Query};
|
||||
use libeditor;
|
||||
|
@ -13,7 +13,7 @@ use serde_json::{to_value, from_value};
|
|||
use ::{
|
||||
req::{self, Decoration}, Result,
|
||||
util::FilePath,
|
||||
conv::{Conv, ConvWith, MapConvWith},
|
||||
conv::{Conv, ConvWith, TryConvWith, MapConvWith},
|
||||
};
|
||||
|
||||
pub fn handle_syntax_tree(
|
||||
|
@ -115,15 +115,10 @@ pub fn handle_workspace_symbol(
|
|||
|
||||
for (path, symbol) in world.world_symbols(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),
|
||||
),
|
||||
location: (path, symbol.node_range).try_conv_with(&line_index)?,
|
||||
container_name: None,
|
||||
};
|
||||
acc.push(info);
|
||||
|
@ -132,6 +127,22 @@ pub fn handle_workspace_symbol(
|
|||
Ok(Some(acc))
|
||||
}
|
||||
|
||||
pub fn handle_goto_definition(
|
||||
world: World,
|
||||
params: req::TextDocumentPositionParams,
|
||||
) -> Result<Option<req::GotoDefinitionResponse>> {
|
||||
let path = params.text_document.file_path()?;
|
||||
let line_index = world.file_line_index(&path)?;
|
||||
let offset = params.position.conv_with(&line_index);
|
||||
let mut res = Vec::new();
|
||||
for (path, symbol) in world.approximately_resolve_symbol(&path, offset)? {
|
||||
let line_index = world.file_line_index(path)?;
|
||||
let location = (path, symbol.node_range).try_conv_with(&line_index)?;
|
||||
res.push(location)
|
||||
}
|
||||
Ok(Some(req::GotoDefinitionResponse::Array(res)))
|
||||
}
|
||||
|
||||
pub fn handle_execute_command(
|
||||
world: World,
|
||||
mut params: req::ExecuteCommandParams,
|
||||
|
|
|
@ -26,6 +26,7 @@ use {
|
|||
handle_code_action,
|
||||
handle_execute_command,
|
||||
handle_workspace_symbol,
|
||||
handle_goto_definition,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -152,6 +153,9 @@ fn on_request(
|
|||
handle_request_on_threadpool::<req::WorkspaceSymbol>(
|
||||
&mut req, pool, world, sender, handle_workspace_symbol,
|
||||
)?;
|
||||
handle_request_on_threadpool::<req::GotoDefinition>(
|
||||
&mut req, pool, world, sender, handle_goto_definition,
|
||||
)?;
|
||||
dispatch::handle_request::<req::ExecuteCommand, _>(&mut req, |params, resp| {
|
||||
io.send(RawMsg::Response(resp.into_response(Ok(None))?));
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ pub use languageserver_types::{
|
|||
CodeActionParams, ApplyWorkspaceEditParams,
|
||||
ExecuteCommandParams,
|
||||
WorkspaceSymbolParams,
|
||||
TextDocumentPositionParams,
|
||||
};
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue