aboutsummaryrefslogtreecommitdiff
path: root/crates/libanalysis/src
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2018-08-13 13:10:20 +0100
committerAleksey Kladov <[email protected]>2018-08-13 13:10:20 +0100
commit133d001d8296e51bcb4d0dc0982671f55c2c77d9 (patch)
treeb0c17dddc00a9d05f5f7a0b2e14fcf2564459533 /crates/libanalysis/src
parented2ac1713326df6b926062efcc6109a20cdf7c37 (diff)
world symbols
Diffstat (limited to 'crates/libanalysis/src')
-rw-r--r--crates/libanalysis/src/lib.rs47
-rw-r--r--crates/libanalysis/src/symbol_index.rs74
2 files changed, 114 insertions, 7 deletions
diff --git a/crates/libanalysis/src/lib.rs b/crates/libanalysis/src/lib.rs
index e4df3de2e..f0d0cf0a4 100644
--- a/crates/libanalysis/src/lib.rs
+++ b/crates/libanalysis/src/lib.rs
@@ -6,6 +6,9 @@ extern crate log;
6extern crate once_cell; 6extern crate once_cell;
7extern crate libsyntax2; 7extern crate libsyntax2;
8extern crate libeditor; 8extern crate libeditor;
9extern crate fst;
10
11mod symbol_index;
9 12
10use once_cell::sync::OnceCell; 13use once_cell::sync::OnceCell;
11 14
@@ -14,8 +17,11 @@ use std::{
14 collections::hash_map::HashMap, 17 collections::hash_map::HashMap,
15 path::{PathBuf, Path}, 18 path::{PathBuf, Path},
16}; 19};
20
17use libsyntax2::ast; 21use libsyntax2::ast;
18use libeditor::LineIndex; 22use libeditor::{LineIndex, FileSymbol};
23
24use self::symbol_index::{FileSymbols, Query};
19 25
20pub type Result<T> = ::std::result::Result<T, ::failure::Error>; 26pub type Result<T> = ::std::result::Result<T, ::failure::Error>;
21 27
@@ -70,12 +76,7 @@ impl WorldState {
70impl World { 76impl World {
71 pub fn file_syntax(&self, path: &Path) -> Result<ast::File> { 77 pub fn file_syntax(&self, path: &Path) -> Result<ast::File> {
72 let data = self.file_data(path)?; 78 let data = self.file_data(path)?;
73 let syntax = data.syntax 79 Ok(data.syntax(path).clone())
74 .get_or_init(|| {
75 trace!("parsing: {}", path.display());
76 ast::File::parse(&data.text)
77 }).clone();
78 Ok(syntax)
79 } 80 }
80 81
81 pub fn file_line_index(&self, path: &Path) -> Result<LineIndex> { 82 pub fn file_line_index(&self, path: &Path) -> Result<LineIndex> {
@@ -88,6 +89,16 @@ impl World {
88 Ok(index.clone()) 89 Ok(index.clone())
89 } 90 }
90 91
92 pub fn world_symbols(&self, query: &str, f: &mut FnMut(&Path, &FileSymbol) -> Search) {
93 let q = Query::new(query);
94 for (path, data) in self.data.file_map.iter() {
95 let symbols = data.symbols(path.as_path());
96 if q.process(symbols, &mut |symbol| f(path, symbol)) == Search::Break {
97 break;
98 }
99 }
100 }
101
91 fn file_data(&self, path: &Path) -> Result<Arc<FileData>> { 102 fn file_data(&self, path: &Path) -> Result<Arc<FileData>> {
92 match self.data.file_map.get(path) { 103 match self.data.file_map.get(path) {
93 Some(data) => Ok(data.clone()), 104 Some(data) => Ok(data.clone()),
@@ -96,6 +107,12 @@ impl World {
96 } 107 }
97} 108}
98 109
110#[derive(Debug, Clone, Copy, PartialEq, Eq)]
111pub enum Search {
112 Continue,
113 Break,
114}
115
99 116
100#[derive(Default, Debug)] 117#[derive(Default, Debug)]
101struct WorldData { 118struct WorldData {
@@ -105,6 +122,7 @@ struct WorldData {
105#[derive(Debug)] 122#[derive(Debug)]
106struct FileData { 123struct FileData {
107 text: String, 124 text: String,
125 symbols: OnceCell<FileSymbols>,
108 syntax: OnceCell<ast::File>, 126 syntax: OnceCell<ast::File>,
109 lines: OnceCell<LineIndex>, 127 lines: OnceCell<LineIndex>,
110} 128}
@@ -113,8 +131,23 @@ impl FileData {
113 fn new(text: String) -> FileData { 131 fn new(text: String) -> FileData {
114 FileData { 132 FileData {
115 text, 133 text,
134 symbols: OnceCell::new(),
116 syntax: OnceCell::new(), 135 syntax: OnceCell::new(),
117 lines: OnceCell::new(), 136 lines: OnceCell::new(),
118 } 137 }
119 } 138 }
139
140 fn syntax(&self, path: &Path) -> &ast::File {
141 self.syntax
142 .get_or_init(|| {
143 trace!("parsing: {}", path.display());
144 ast::File::parse(&self.text)
145 })
146 }
147
148 fn symbols(&self, path: &Path) -> &FileSymbols {
149 let syntax = self.syntax(path);
150 self.symbols
151 .get_or_init(|| FileSymbols::new(syntax))
152 }
120} 153}
diff --git a/crates/libanalysis/src/symbol_index.rs b/crates/libanalysis/src/symbol_index.rs
new file mode 100644
index 000000000..1878fae99
--- /dev/null
+++ b/crates/libanalysis/src/symbol_index.rs
@@ -0,0 +1,74 @@
1use libeditor::{FileSymbol, file_symbols};
2use libsyntax2::{
3 ast,
4 SyntaxKind::{self, *},
5};
6use fst::{self, IntoStreamer};
7
8use Search;
9
10#[derive(Debug)]
11pub(crate) struct FileSymbols {
12 symbols: Vec<FileSymbol>,
13 map: fst::Map,
14}
15
16impl FileSymbols {
17 pub(crate) fn new(file: &ast::File) -> FileSymbols {
18 let mut symbols = file_symbols(file)
19 .into_iter()
20 .map(|s| (s.name.as_str().to_lowercase(), s))
21 .collect::<Vec<_>>();
22
23 symbols.sort_by(|s1, s2| s1.0.cmp(&s2.0));
24 symbols.dedup_by(|s1, s2| s1.0 == s2.0);
25 let (names, symbols): (Vec<String>, Vec<FileSymbol>) =
26 symbols.into_iter().unzip();
27
28 let map = fst::Map::from_iter(
29 names.into_iter().zip(0u64..)
30 ).unwrap();
31 FileSymbols { symbols, map }
32 }
33}
34
35pub(crate) struct Query {
36 query: String,
37 all_symbols: bool,
38}
39
40impl Query {
41 pub(crate) fn new(query: &str) -> Query {
42 let all_symbols = query.contains("#");
43 let query: String = query.chars()
44 .filter(|&c| c != '#')
45 .flat_map(char::to_lowercase)
46 .collect();
47 Query { query, all_symbols }
48 }
49
50 pub(crate) fn process(
51 &self,
52 file: &FileSymbols,
53 acc: &mut FnMut(&FileSymbol) -> Search,
54 ) -> Search {
55 fn is_type(kind: SyntaxKind) -> bool {
56 match kind {
57 STRUCT | ENUM | TRAIT | TYPE_ITEM => true,
58 _ => false,
59 }
60 }
61 let automaton = fst::automaton::Subsequence::new(&self.query);
62 for idx in file.map.search(automaton).into_stream().into_values() {
63 let idx = idx as usize;
64 let symbol = &file.symbols[idx];
65 if self.all_symbols || is_type(symbol.kind) {
66 if acc(&symbol) == Search::Break {
67 return Search::Break;
68 }
69 }
70 }
71 Search::Continue
72 }
73}
74