aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2018-08-13 14:35:17 +0100
committerAleksey Kladov <[email protected]>2018-08-13 14:35:17 +0100
commit8ae56fa6d0e8a03d6ad75919d6be953f5fc27083 (patch)
treed93a4f3e1d279a27cc851546796bb488edfe2c65
parent7fc91f41d8bd948cef3085d7c0d0ec92d1b2bc53 (diff)
Stupid goto definition
-rw-r--r--crates/libanalysis/src/lib.rs36
-rw-r--r--crates/libsyntax2/src/ast/generated.rs18
-rw-r--r--crates/libsyntax2/src/ast/mod.rs8
-rw-r--r--crates/libsyntax2/src/grammar.ron1
-rw-r--r--crates/server/src/caps.rs2
-rw-r--r--crates/server/src/conv.rs26
-rw-r--r--crates/server/src/main_loop/handlers.rs27
-rw-r--r--crates/server/src/main_loop/mod.rs4
-rw-r--r--crates/server/src/req.rs1
9 files changed, 109 insertions, 14 deletions
diff --git a/crates/libanalysis/src/lib.rs b/crates/libanalysis/src/lib.rs
index b2f4bdbb3..97b6dfca6 100644
--- a/crates/libanalysis/src/lib.rs
+++ b/crates/libanalysis/src/lib.rs
@@ -18,10 +18,14 @@ use std::{
18 path::{PathBuf, Path}, 18 path::{PathBuf, Path},
19}; 19};
20 20
21use libsyntax2::ast; 21use libsyntax2::{
22 TextUnit,
23 ast::{self, AstNode},
24 algo::{find_leaf_at_offset, ancestors},
25};
22use libeditor::{LineIndex, FileSymbol}; 26use libeditor::{LineIndex, FileSymbol};
23 27
24use self::symbol_index::{FileSymbols}; 28use self::symbol_index::FileSymbols;
25pub use self::symbol_index::Query; 29pub use self::symbol_index::Query;
26 30
27pub type Result<T> = ::std::result::Result<T, ::failure::Error>; 31pub type Result<T> = ::std::result::Result<T, ::failure::Error>;
@@ -90,8 +94,7 @@ impl World {
90 Ok(index.clone()) 94 Ok(index.clone())
91 } 95 }
92 96
93 pub fn world_symbols<'a>(&'a self, query: Query) -> impl Iterator<Item=(&'a Path, &'a FileSymbol)> + 'a 97 pub fn world_symbols<'a>(&'a self, query: Query) -> impl Iterator<Item=(&'a Path, &'a FileSymbol)> + 'a {
94 {
95 self.data.file_map.iter() 98 self.data.file_map.iter()
96 .flat_map(move |(path, data)| { 99 .flat_map(move |(path, data)| {
97 let path: &'a Path = path.as_path(); 100 let path: &'a Path = path.as_path();
@@ -100,6 +103,31 @@ impl World {
100 }) 103 })
101 } 104 }
102 105
106 pub fn approximately_resolve_symbol<'a>(
107 &'a self,
108 path: &Path,
109 offset: TextUnit,
110 ) -> Result<Vec<(&'a Path, &'a FileSymbol)>> {
111 let file = self.file_syntax(path)?;
112 let syntax = file.syntax();
113 let syntax = syntax.as_ref();
114 let name_ref =
115 find_leaf_at_offset(syntax, offset)
116 .left_biased()
117 .into_iter()
118 .flat_map(|node| ancestors(node))
119 .flat_map(ast::NameRef::cast)
120 .next();
121 let name = match name_ref {
122 None => return Ok(vec![]),
123 Some(name_ref) => name_ref.text(),
124 };
125
126 let mut query = Query::new(name.to_string());
127 query.exact();
128 Ok(self.world_symbols(query).take(4).collect())
129 }
130
103 fn file_data(&self, path: &Path) -> Result<Arc<FileData>> { 131 fn file_data(&self, path: &Path) -> Result<Arc<FileData>> {
104 match self.data.file_map.get(path) { 132 match self.data.file_map.get(path) {
105 Some(data) => Ok(data.clone()), 133 Some(data) => Ok(data.clone()),
diff --git a/crates/libsyntax2/src/ast/generated.rs b/crates/libsyntax2/src/ast/generated.rs
index 31f5ecc44..b1fd0a8ad 100644
--- a/crates/libsyntax2/src/ast/generated.rs
+++ b/crates/libsyntax2/src/ast/generated.rs
@@ -123,6 +123,24 @@ impl<R: TreeRoot> AstNode<R> for Name<R> {
123 123
124impl<R: TreeRoot> Name<R> {} 124impl<R: TreeRoot> Name<R> {}
125 125
126// NameRef
127#[derive(Debug, Clone, Copy)]
128pub struct NameRef<R: TreeRoot = Arc<SyntaxRoot>> {
129 syntax: SyntaxNode<R>,
130}
131
132impl<R: TreeRoot> AstNode<R> for NameRef<R> {
133 fn cast(syntax: SyntaxNode<R>) -> Option<Self> {
134 match syntax.kind() {
135 NAME_REF => Some(NameRef { syntax }),
136 _ => None,
137 }
138 }
139 fn syntax(&self) -> &SyntaxNode<R> { &self.syntax }
140}
141
142impl<R: TreeRoot> NameRef<R> {}
143
126// StaticItem 144// StaticItem
127#[derive(Debug, Clone, Copy)] 145#[derive(Debug, Clone, Copy)]
128pub struct StaticItem<R: TreeRoot = Arc<SyntaxRoot>> { 146pub struct StaticItem<R: TreeRoot = Arc<SyntaxRoot>> {
diff --git a/crates/libsyntax2/src/ast/mod.rs b/crates/libsyntax2/src/ast/mod.rs
index e9362d048..2e1fb2d1c 100644
--- a/crates/libsyntax2/src/ast/mod.rs
+++ b/crates/libsyntax2/src/ast/mod.rs
@@ -73,3 +73,11 @@ impl<R: TreeRoot> Name<R> {
73 ident.leaf_text().unwrap() 73 ident.leaf_text().unwrap()
74 } 74 }
75} 75}
76
77impl<R: TreeRoot> NameRef<R> {
78 pub fn text(&self) -> SmolStr {
79 let ident = self.syntax().first_child()
80 .unwrap();
81 ident.leaf_text().unwrap()
82 }
83}
diff --git a/crates/libsyntax2/src/grammar.ron b/crates/libsyntax2/src/grammar.ron
index d4e8c53d3..ee231931e 100644
--- a/crates/libsyntax2/src/grammar.ron
+++ b/crates/libsyntax2/src/grammar.ron
@@ -228,5 +228,6 @@ Grammar(
228 "StaticItem": ( traits: ["NameOwner"] ), 228 "StaticItem": ( traits: ["NameOwner"] ),
229 "TypeItem": ( traits: ["NameOwner"] ), 229 "TypeItem": ( traits: ["NameOwner"] ),
230 "Name": (), 230 "Name": (),
231 "NameRef": (),
231 }, 232 },
232) 233)
diff --git a/crates/server/src/caps.rs b/crates/server/src/caps.rs
index 4fd28b7c8..ffebd9b47 100644
--- a/crates/server/src/caps.rs
+++ b/crates/server/src/caps.rs
@@ -20,7 +20,7 @@ pub fn server_capabilities() -> ServerCapabilities {
20 hover_provider: None, 20 hover_provider: None,
21 completion_provider: None, 21 completion_provider: None,
22 signature_help_provider: None, 22 signature_help_provider: None,
23 definition_provider: None, 23 definition_provider: Some(true),
24 type_definition_provider: None, 24 type_definition_provider: None,
25 implementation_provider: None, 25 implementation_provider: None,
26 references_provider: None, 26 references_provider: None,
diff --git a/crates/server/src/conv.rs b/crates/server/src/conv.rs
index 0ed989b32..1c31d32fe 100644
--- a/crates/server/src/conv.rs
+++ b/crates/server/src/conv.rs
@@ -1,7 +1,11 @@
1use languageserver_types::{Range, SymbolKind, Position, TextEdit}; 1use std::path::Path;
2
3use languageserver_types::{Range, SymbolKind, Position, TextEdit, Location, Url};
2use libeditor::{LineIndex, LineCol, Edit, AtomEdit}; 4use libeditor::{LineIndex, LineCol, Edit, AtomEdit};
3use libsyntax2::{SyntaxKind, TextUnit, TextRange}; 5use libsyntax2::{SyntaxKind, TextUnit, TextRange};
4 6
7use Result;
8
5pub trait Conv { 9pub trait Conv {
6 type Output; 10 type Output;
7 fn conv(self) -> Self::Output; 11 fn conv(self) -> Self::Output;
@@ -13,6 +17,12 @@ pub trait ConvWith {
13 fn conv_with(self, ctx: &Self::Ctx) -> Self::Output; 17 fn conv_with(self, ctx: &Self::Ctx) -> Self::Output;
14} 18}
15 19
20pub trait TryConvWith {
21 type Ctx;
22 type Output;
23 fn try_conv_with(self, ctx: &Self::Ctx) -> Result<Self::Output>;
24}
25
16impl Conv for SyntaxKind { 26impl Conv for SyntaxKind {
17 type Output = SymbolKind; 27 type Output = SymbolKind;
18 28
@@ -104,6 +114,20 @@ impl ConvWith for AtomEdit {
104 } 114 }
105} 115}
106 116
117impl<'a> TryConvWith for (&'a Path, TextRange) {
118 type Ctx = LineIndex;
119 type Output = Location;
120
121 fn try_conv_with(self, line_index: &LineIndex) -> Result<Location> {
122 let loc = Location::new(
123 Url::from_file_path(self.0)
124 .map_err(|()| format_err!("can't convert path to url: {}", self.0.display()))?,
125 self.1.conv_with(line_index),
126 );
127 Ok(loc)
128 }
129}
130
107 131
108pub trait MapConvWith<'a>: Sized { 132pub trait MapConvWith<'a>: Sized {
109 type Ctx; 133 type Ctx;
diff --git a/crates/server/src/main_loop/handlers.rs b/crates/server/src/main_loop/handlers.rs
index f51909280..e9dc78420 100644
--- a/crates/server/src/main_loop/handlers.rs
+++ b/crates/server/src/main_loop/handlers.rs
@@ -3,7 +3,7 @@ use std::collections::HashMap;
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 SymbolInformation,
7}; 7};
8use libanalysis::{World, Query}; 8use libanalysis::{World, Query};
9use libeditor; 9use libeditor;
@@ -13,7 +13,7 @@ use serde_json::{to_value, from_value};
13use ::{ 13use ::{
14 req::{self, Decoration}, Result, 14 req::{self, Decoration}, Result,
15 util::FilePath, 15 util::FilePath,
16 conv::{Conv, ConvWith, MapConvWith}, 16 conv::{Conv, ConvWith, TryConvWith, MapConvWith},
17}; 17};
18 18
19pub fn handle_syntax_tree( 19pub fn handle_syntax_tree(
@@ -115,15 +115,10 @@ pub fn handle_workspace_symbol(
115 115
116 for (path, symbol) in world.world_symbols(query).take(128) { 116 for (path, symbol) in world.world_symbols(query).take(128) {
117 let line_index = world.file_line_index(path)?; 117 let line_index = world.file_line_index(path)?;
118
119 let info = SymbolInformation { 118 let info = SymbolInformation {
120 name: symbol.name.to_string(), 119 name: symbol.name.to_string(),
121 kind: symbol.kind.conv(), 120 kind: symbol.kind.conv(),
122 location: Location::new( 121 location: (path, symbol.node_range).try_conv_with(&line_index)?,
123 Url::from_file_path(path)
124 .map_err(|()| format_err!("invalid url"))?,
125 symbol.node_range.conv_with(&line_index),
126 ),
127 container_name: None, 122 container_name: None,
128 }; 123 };
129 acc.push(info); 124 acc.push(info);
@@ -132,6 +127,22 @@ pub fn handle_workspace_symbol(
132 Ok(Some(acc)) 127 Ok(Some(acc))
133} 128}
134 129
130pub fn handle_goto_definition(
131 world: World,
132 params: req::TextDocumentPositionParams,
133) -> Result<Option<req::GotoDefinitionResponse>> {
134 let path = params.text_document.file_path()?;
135 let line_index = world.file_line_index(&path)?;
136 let offset = params.position.conv_with(&line_index);
137 let mut res = Vec::new();
138 for (path, symbol) in world.approximately_resolve_symbol(&path, offset)? {
139 let line_index = world.file_line_index(path)?;
140 let location = (path, symbol.node_range).try_conv_with(&line_index)?;
141 res.push(location)
142 }
143 Ok(Some(req::GotoDefinitionResponse::Array(res)))
144}
145
135pub fn handle_execute_command( 146pub fn handle_execute_command(
136 world: World, 147 world: World,
137 mut params: req::ExecuteCommandParams, 148 mut params: req::ExecuteCommandParams,
diff --git a/crates/server/src/main_loop/mod.rs b/crates/server/src/main_loop/mod.rs
index e8b24355c..bc898c17b 100644
--- a/crates/server/src/main_loop/mod.rs
+++ b/crates/server/src/main_loop/mod.rs
@@ -26,6 +26,7 @@ use {
26 handle_code_action, 26 handle_code_action,
27 handle_execute_command, 27 handle_execute_command,
28 handle_workspace_symbol, 28 handle_workspace_symbol,
29 handle_goto_definition,
29 }, 30 },
30}; 31};
31 32
@@ -152,6 +153,9 @@ fn on_request(
152 handle_request_on_threadpool::<req::WorkspaceSymbol>( 153 handle_request_on_threadpool::<req::WorkspaceSymbol>(
153 &mut req, pool, world, sender, handle_workspace_symbol, 154 &mut req, pool, world, sender, handle_workspace_symbol,
154 )?; 155 )?;
156 handle_request_on_threadpool::<req::GotoDefinition>(
157 &mut req, pool, world, sender, handle_goto_definition,
158 )?;
155 dispatch::handle_request::<req::ExecuteCommand, _>(&mut req, |params, resp| { 159 dispatch::handle_request::<req::ExecuteCommand, _>(&mut req, |params, resp| {
156 io.send(RawMsg::Response(resp.into_response(Ok(None))?)); 160 io.send(RawMsg::Response(resp.into_response(Ok(None))?));
157 161
diff --git a/crates/server/src/req.rs b/crates/server/src/req.rs
index a8cc9b537..17ef10e43 100644
--- a/crates/server/src/req.rs
+++ b/crates/server/src/req.rs
@@ -9,6 +9,7 @@ pub use languageserver_types::{
9 CodeActionParams, ApplyWorkspaceEditParams, 9 CodeActionParams, ApplyWorkspaceEditParams,
10 ExecuteCommandParams, 10 ExecuteCommandParams,
11 WorkspaceSymbolParams, 11 WorkspaceSymbolParams,
12 TextDocumentPositionParams,
12}; 13};
13 14
14 15