mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 13:03:31 +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},
|
path::{PathBuf, Path},
|
||||||
};
|
};
|
||||||
|
|
||||||
use libsyntax2::ast;
|
use libsyntax2::{
|
||||||
|
TextUnit,
|
||||||
|
ast::{self, AstNode},
|
||||||
|
algo::{find_leaf_at_offset, ancestors},
|
||||||
|
};
|
||||||
use libeditor::{LineIndex, FileSymbol};
|
use libeditor::{LineIndex, FileSymbol};
|
||||||
|
|
||||||
use self::symbol_index::{FileSymbols};
|
use self::symbol_index::FileSymbols;
|
||||||
pub use self::symbol_index::Query;
|
pub use self::symbol_index::Query;
|
||||||
|
|
||||||
pub type Result<T> = ::std::result::Result<T, ::failure::Error>;
|
pub type Result<T> = ::std::result::Result<T, ::failure::Error>;
|
||||||
|
@ -90,8 +94,7 @@ impl World {
|
||||||
Ok(index.clone())
|
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()
|
self.data.file_map.iter()
|
||||||
.flat_map(move |(path, data)| {
|
.flat_map(move |(path, data)| {
|
||||||
let path: &'a Path = path.as_path();
|
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>> {
|
fn file_data(&self, path: &Path) -> Result<Arc<FileData>> {
|
||||||
match self.data.file_map.get(path) {
|
match self.data.file_map.get(path) {
|
||||||
Some(data) => Ok(data.clone()),
|
Some(data) => Ok(data.clone()),
|
||||||
|
|
|
@ -123,6 +123,24 @@ impl<R: TreeRoot> AstNode<R> for Name<R> {
|
||||||
|
|
||||||
impl<R: TreeRoot> 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
|
// StaticItem
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct StaticItem<R: TreeRoot = Arc<SyntaxRoot>> {
|
pub struct StaticItem<R: TreeRoot = Arc<SyntaxRoot>> {
|
||||||
|
|
|
@ -73,3 +73,11 @@ impl<R: TreeRoot> Name<R> {
|
||||||
ident.leaf_text().unwrap()
|
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"] ),
|
"StaticItem": ( traits: ["NameOwner"] ),
|
||||||
"TypeItem": ( traits: ["NameOwner"] ),
|
"TypeItem": ( traits: ["NameOwner"] ),
|
||||||
"Name": (),
|
"Name": (),
|
||||||
|
"NameRef": (),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
|
@ -20,7 +20,7 @@ pub fn server_capabilities() -> ServerCapabilities {
|
||||||
hover_provider: None,
|
hover_provider: None,
|
||||||
completion_provider: None,
|
completion_provider: None,
|
||||||
signature_help_provider: None,
|
signature_help_provider: None,
|
||||||
definition_provider: None,
|
definition_provider: Some(true),
|
||||||
type_definition_provider: None,
|
type_definition_provider: None,
|
||||||
implementation_provider: None,
|
implementation_provider: None,
|
||||||
references_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 libeditor::{LineIndex, LineCol, Edit, AtomEdit};
|
||||||
use libsyntax2::{SyntaxKind, TextUnit, TextRange};
|
use libsyntax2::{SyntaxKind, TextUnit, TextRange};
|
||||||
|
|
||||||
|
use Result;
|
||||||
|
|
||||||
pub trait Conv {
|
pub trait Conv {
|
||||||
type Output;
|
type Output;
|
||||||
fn conv(self) -> Self::Output;
|
fn conv(self) -> Self::Output;
|
||||||
|
@ -13,6 +17,12 @@ pub trait ConvWith {
|
||||||
fn conv_with(self, ctx: &Self::Ctx) -> Self::Output;
|
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 {
|
impl Conv for SyntaxKind {
|
||||||
type Output = SymbolKind;
|
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 {
|
pub trait MapConvWith<'a>: Sized {
|
||||||
type Ctx;
|
type Ctx;
|
||||||
|
|
|
@ -3,7 +3,7 @@ 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,
|
SymbolInformation,
|
||||||
};
|
};
|
||||||
use libanalysis::{World, Query};
|
use libanalysis::{World, Query};
|
||||||
use libeditor;
|
use libeditor;
|
||||||
|
@ -13,7 +13,7 @@ use serde_json::{to_value, from_value};
|
||||||
use ::{
|
use ::{
|
||||||
req::{self, Decoration}, Result,
|
req::{self, Decoration}, Result,
|
||||||
util::FilePath,
|
util::FilePath,
|
||||||
conv::{Conv, ConvWith, MapConvWith},
|
conv::{Conv, ConvWith, TryConvWith, MapConvWith},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn handle_syntax_tree(
|
pub fn handle_syntax_tree(
|
||||||
|
@ -115,15 +115,10 @@ pub fn handle_workspace_symbol(
|
||||||
|
|
||||||
for (path, symbol) in world.world_symbols(query).take(128) {
|
for (path, symbol) in world.world_symbols(query).take(128) {
|
||||||
let line_index = world.file_line_index(path)?;
|
let line_index = world.file_line_index(path)?;
|
||||||
|
|
||||||
let info = SymbolInformation {
|
let info = SymbolInformation {
|
||||||
name: symbol.name.to_string(),
|
name: symbol.name.to_string(),
|
||||||
kind: symbol.kind.conv(),
|
kind: symbol.kind.conv(),
|
||||||
location: Location::new(
|
location: (path, symbol.node_range).try_conv_with(&line_index)?,
|
||||||
Url::from_file_path(path)
|
|
||||||
.map_err(|()| format_err!("invalid url"))?,
|
|
||||||
symbol.node_range.conv_with(&line_index),
|
|
||||||
),
|
|
||||||
container_name: None,
|
container_name: None,
|
||||||
};
|
};
|
||||||
acc.push(info);
|
acc.push(info);
|
||||||
|
@ -132,6 +127,22 @@ pub fn handle_workspace_symbol(
|
||||||
Ok(Some(acc))
|
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(
|
pub fn handle_execute_command(
|
||||||
world: World,
|
world: World,
|
||||||
mut params: req::ExecuteCommandParams,
|
mut params: req::ExecuteCommandParams,
|
||||||
|
|
|
@ -26,6 +26,7 @@ use {
|
||||||
handle_code_action,
|
handle_code_action,
|
||||||
handle_execute_command,
|
handle_execute_command,
|
||||||
handle_workspace_symbol,
|
handle_workspace_symbol,
|
||||||
|
handle_goto_definition,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -152,6 +153,9 @@ fn on_request(
|
||||||
handle_request_on_threadpool::<req::WorkspaceSymbol>(
|
handle_request_on_threadpool::<req::WorkspaceSymbol>(
|
||||||
&mut req, pool, world, sender, handle_workspace_symbol,
|
&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| {
|
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))?));
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ pub use languageserver_types::{
|
||||||
CodeActionParams, ApplyWorkspaceEditParams,
|
CodeActionParams, ApplyWorkspaceEditParams,
|
||||||
ExecuteCommandParams,
|
ExecuteCommandParams,
|
||||||
WorkspaceSymbolParams,
|
WorkspaceSymbolParams,
|
||||||
|
TextDocumentPositionParams,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue