diff options
-rw-r--r-- | crates/libanalysis/src/lib.rs | 56 | ||||
-rw-r--r-- | crates/libanalysis/src/symbol_index.rs | 8 | ||||
-rw-r--r-- | crates/libeditor/src/symbols.rs | 4 | ||||
-rw-r--r-- | crates/libsyntax2/src/ast/mod.rs | 9 | ||||
-rw-r--r-- | crates/libsyntax2/src/yellow/syntax.rs | 10 | ||||
-rw-r--r-- | crates/server/src/path_map.rs | 47 |
6 files changed, 111 insertions, 23 deletions
diff --git a/crates/libanalysis/src/lib.rs b/crates/libanalysis/src/lib.rs index 9429f8f55..19b64fece 100644 --- a/crates/libanalysis/src/lib.rs +++ b/crates/libanalysis/src/lib.rs | |||
@@ -16,7 +16,7 @@ use rayon::prelude::*; | |||
16 | 16 | ||
17 | use std::{ | 17 | use std::{ |
18 | fmt, | 18 | fmt, |
19 | path::Path, | 19 | path::{Path, PathBuf}, |
20 | sync::{ | 20 | sync::{ |
21 | Arc, | 21 | Arc, |
22 | atomic::{AtomicUsize, Ordering::SeqCst}, | 22 | atomic::{AtomicUsize, Ordering::SeqCst}, |
@@ -26,8 +26,9 @@ use std::{ | |||
26 | }; | 26 | }; |
27 | 27 | ||
28 | use libsyntax2::{ | 28 | use libsyntax2::{ |
29 | TextUnit, | 29 | TextUnit, TextRange, SyntaxRoot, |
30 | ast::{self, AstNode}, | 30 | ast::{self, AstNode, NameOwner}, |
31 | SyntaxKind::*, | ||
31 | }; | 32 | }; |
32 | use libeditor::{LineIndex, FileSymbol, find_node}; | 33 | use libeditor::{LineIndex, FileSymbol, find_node}; |
33 | 34 | ||
@@ -119,33 +120,58 @@ impl World { | |||
119 | Ok(index.clone()) | 120 | Ok(index.clone()) |
120 | } | 121 | } |
121 | 122 | ||
122 | pub fn world_symbols<'a>(&'a self, mut query: Query) -> impl Iterator<Item=(FileId, &'a FileSymbol)> + 'a { | 123 | pub fn world_symbols(&self, mut query: Query) -> Vec<(FileId, FileSymbol)> { |
123 | self.reindex(); | 124 | self.reindex(); |
124 | self.data.file_map.iter() | 125 | self.data.file_map.iter() |
125 | .flat_map(move |(id, data)| { | 126 | .flat_map(move |(id, data)| { |
126 | let symbols = data.symbols(); | 127 | let symbols = data.symbols(); |
127 | query.process(symbols).into_iter().map(move |s| (*id, s)) | 128 | query.process(symbols).into_iter().map(move |s| (*id, s)) |
128 | }) | 129 | }) |
130 | .collect() | ||
129 | } | 131 | } |
130 | 132 | ||
131 | pub fn approximately_resolve_symbol<'a>( | 133 | pub fn approximately_resolve_symbol( |
132 | &'a self, | 134 | &self, |
133 | id: FileId, | 135 | id: FileId, |
134 | offset: TextUnit, | 136 | offset: TextUnit, |
135 | ) -> Result<Vec<(FileId, &'a FileSymbol)>> { | 137 | ) -> Result<Vec<(FileId, FileSymbol)>> { |
136 | let file = self.file_syntax(id)?; | 138 | let file = self.file_syntax(id)?; |
137 | let syntax = file.syntax(); | 139 | let syntax = file.syntax_ref(); |
138 | let syntax = syntax.as_ref(); | 140 | if let Some(name_ref) = find_node::<ast::NameRef<_>>(syntax, offset) { |
139 | let name_ref = find_node::<ast::NameRef<_>>(syntax, offset); | 141 | return Ok(self.index_resolve(name_ref)); |
140 | let name = match name_ref { | 142 | } |
141 | None => return Ok(vec![]), | 143 | if let Some(name) = find_node::<ast::Name<_>>(syntax, offset) { |
142 | Some(name_ref) => name_ref.text(), | 144 | if let Some(module) = name.syntax().parent().and_then(ast::Module::cast) { |
143 | }; | 145 | if module.has_semi() { |
146 | return Ok(self.resolve_module(id, module)); | ||
147 | } | ||
148 | } | ||
149 | } | ||
150 | Ok(vec![]) | ||
151 | } | ||
144 | 152 | ||
153 | fn index_resolve(&self, name_ref: ast::NameRef<&SyntaxRoot>) -> Vec<(FileId, FileSymbol)> { | ||
154 | let name = name_ref.text(); | ||
145 | let mut query = Query::new(name.to_string()); | 155 | let mut query = Query::new(name.to_string()); |
146 | query.exact(); | 156 | query.exact(); |
147 | query.limit(4); | 157 | query.limit(4); |
148 | Ok(self.world_symbols(query).collect()) | 158 | self.world_symbols(query) |
159 | } | ||
160 | |||
161 | fn resolve_module(&self, id: FileId, module: ast::Module<&SyntaxRoot>) -> Vec<(FileId, FileSymbol)> { | ||
162 | let name = match module.name() { | ||
163 | Some(name) => name.text(), | ||
164 | None => return Vec::new(), | ||
165 | }; | ||
166 | let id = match self.resolve_relative_path(id, &PathBuf::from(format!("../{}.rs", name))) { | ||
167 | Some(id) => id, | ||
168 | None => return Vec::new(), | ||
169 | }; | ||
170 | vec![(id, FileSymbol { | ||
171 | name: name.clone(), | ||
172 | node_range: TextRange::offset_len(0.into(), 0.into()), | ||
173 | kind: MODULE, | ||
174 | })] | ||
149 | } | 175 | } |
150 | 176 | ||
151 | fn resolve_relative_path(&self, id: FileId, path: &Path) -> Option<FileId> { | 177 | fn resolve_relative_path(&self, id: FileId, path: &Path) -> Option<FileId> { |
diff --git a/crates/libanalysis/src/symbol_index.rs b/crates/libanalysis/src/symbol_index.rs index 35141cfdc..3c3252956 100644 --- a/crates/libanalysis/src/symbol_index.rs +++ b/crates/libanalysis/src/symbol_index.rs | |||
@@ -62,10 +62,10 @@ impl Query { | |||
62 | self.limit = limit | 62 | self.limit = limit |
63 | } | 63 | } |
64 | 64 | ||
65 | pub(crate) fn process<'a>( | 65 | pub(crate) fn process( |
66 | &mut self, | 66 | &mut self, |
67 | file: &'a FileSymbols, | 67 | file: &FileSymbols, |
68 | ) -> Vec<&'a FileSymbol> { | 68 | ) -> Vec<FileSymbol> { |
69 | fn is_type(kind: SyntaxKind) -> bool { | 69 | fn is_type(kind: SyntaxKind) -> bool { |
70 | match kind { | 70 | match kind { |
71 | STRUCT_DEF | ENUM_DEF | TRAIT_DEF | TYPE_DEF => true, | 71 | STRUCT_DEF | ENUM_DEF | TRAIT_DEF | TYPE_DEF => true, |
@@ -87,7 +87,7 @@ impl Query { | |||
87 | if self.exact && symbol.name != self.query { | 87 | if self.exact && symbol.name != self.query { |
88 | continue; | 88 | continue; |
89 | } | 89 | } |
90 | res.push(symbol); | 90 | res.push(symbol.clone()); |
91 | self.limit -= 1; | 91 | self.limit -= 1; |
92 | } | 92 | } |
93 | res | 93 | res |
diff --git a/crates/libeditor/src/symbols.rs b/crates/libeditor/src/symbols.rs index 2585d9579..ce870430e 100644 --- a/crates/libeditor/src/symbols.rs +++ b/crates/libeditor/src/symbols.rs | |||
@@ -9,7 +9,7 @@ use libsyntax2::{ | |||
9 | }; | 9 | }; |
10 | use TextRange; | 10 | use TextRange; |
11 | 11 | ||
12 | #[derive(Debug)] | 12 | #[derive(Debug, Clone)] |
13 | pub struct StructureNode { | 13 | pub struct StructureNode { |
14 | pub parent: Option<usize>, | 14 | pub parent: Option<usize>, |
15 | pub label: String, | 15 | pub label: String, |
@@ -18,7 +18,7 @@ pub struct StructureNode { | |||
18 | pub kind: SyntaxKind, | 18 | pub kind: SyntaxKind, |
19 | } | 19 | } |
20 | 20 | ||
21 | #[derive(Debug)] | 21 | #[derive(Debug, Clone)] |
22 | pub struct FileSymbol { | 22 | pub struct FileSymbol { |
23 | pub name: SmolStr, | 23 | pub name: SmolStr, |
24 | pub node_range: TextRange, | 24 | pub node_range: TextRange, |
diff --git a/crates/libsyntax2/src/ast/mod.rs b/crates/libsyntax2/src/ast/mod.rs index d53b12ab8..9b9200f99 100644 --- a/crates/libsyntax2/src/ast/mod.rs +++ b/crates/libsyntax2/src/ast/mod.rs | |||
@@ -118,3 +118,12 @@ impl <R: TreeRoot> ImplItem<R> { | |||
118 | (first, second) | 118 | (first, second) |
119 | } | 119 | } |
120 | } | 120 | } |
121 | |||
122 | impl <R: TreeRoot> Module<R> { | ||
123 | pub fn has_semi(&self) -> bool { | ||
124 | match self.syntax_ref().last_child() { | ||
125 | None => false, | ||
126 | Some(node) => node.kind() == SEMI, | ||
127 | } | ||
128 | } | ||
129 | } | ||
diff --git a/crates/libsyntax2/src/yellow/syntax.rs b/crates/libsyntax2/src/yellow/syntax.rs index b264e008a..bb390751a 100644 --- a/crates/libsyntax2/src/yellow/syntax.rs +++ b/crates/libsyntax2/src/yellow/syntax.rs | |||
@@ -89,7 +89,15 @@ impl<R: TreeRoot> SyntaxNode<R> { | |||
89 | } | 89 | } |
90 | 90 | ||
91 | pub fn first_child(&self) -> Option<SyntaxNode<R>> { | 91 | pub fn first_child(&self) -> Option<SyntaxNode<R>> { |
92 | self.children().next() | 92 | let red = self.red().get_child(0)?; |
93 | Some(SyntaxNode { root: self.root.clone(), red }) | ||
94 | } | ||
95 | |||
96 | pub fn last_child(&self) -> Option<SyntaxNode<R>> { | ||
97 | let n = self.red().n_children(); | ||
98 | let n = n.checked_sub(1)?; | ||
99 | let red = self.red().get_child(n)?; | ||
100 | Some(SyntaxNode { root: self.root.clone(), red }) | ||
93 | } | 101 | } |
94 | 102 | ||
95 | pub fn next_sibling(&self) -> Option<SyntaxNode<R>> { | 103 | pub fn next_sibling(&self) -> Option<SyntaxNode<R>> { |
diff --git a/crates/server/src/path_map.rs b/crates/server/src/path_map.rs index e198e165d..d2b811a3b 100644 --- a/crates/server/src/path_map.rs +++ b/crates/server/src/path_map.rs | |||
@@ -1,4 +1,4 @@ | |||
1 | use std::path::{PathBuf, Path}; | 1 | use std::path::{PathBuf, Path, Component}; |
2 | use im; | 2 | use im; |
3 | use libanalysis::{FileId}; | 3 | use libanalysis::{FileId}; |
4 | 4 | ||
@@ -36,6 +36,7 @@ impl PathMap { | |||
36 | 36 | ||
37 | pub fn resolve(&self, id: FileId, relpath: &Path) -> Option<FileId> { | 37 | pub fn resolve(&self, id: FileId, relpath: &Path) -> Option<FileId> { |
38 | let path = self.get_path(id).join(relpath); | 38 | let path = self.get_path(id).join(relpath); |
39 | let path = normalize(&path); | ||
39 | self.get_id(&path) | 40 | self.get_id(&path) |
40 | } | 41 | } |
41 | 42 | ||
@@ -50,3 +51,47 @@ impl PathMap { | |||
50 | id | 51 | id |
51 | } | 52 | } |
52 | } | 53 | } |
54 | |||
55 | fn normalize(path: &Path) -> PathBuf { | ||
56 | let mut components = path.components().peekable(); | ||
57 | let mut ret = if let Some(c @ Component::Prefix(..)) = components.peek().cloned() { | ||
58 | components.next(); | ||
59 | PathBuf::from(c.as_os_str()) | ||
60 | } else { | ||
61 | PathBuf::new() | ||
62 | }; | ||
63 | |||
64 | for component in components { | ||
65 | match component { | ||
66 | Component::Prefix(..) => unreachable!(), | ||
67 | Component::RootDir => { | ||
68 | ret.push(component.as_os_str()); | ||
69 | } | ||
70 | Component::CurDir => {} | ||
71 | Component::ParentDir => { | ||
72 | ret.pop(); | ||
73 | } | ||
74 | Component::Normal(c) => { | ||
75 | ret.push(c); | ||
76 | } | ||
77 | } | ||
78 | } | ||
79 | ret | ||
80 | } | ||
81 | |||
82 | #[cfg(test)] | ||
83 | mod test { | ||
84 | use super::*; | ||
85 | |||
86 | #[test] | ||
87 | fn test_resolve() { | ||
88 | let mut m = PathMap::new(); | ||
89 | let id1 = m.get_or_insert(PathBuf::from("/foo")); | ||
90 | let id2 = m.get_or_insert(PathBuf::from("/foo/bar.rs")); | ||
91 | assert_eq!( | ||
92 | m.resolve(id1, &PathBuf::from("bar.rs")), | ||
93 | Some(id2), | ||
94 | ) | ||
95 | } | ||
96 | } | ||
97 | |||