diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/libanalysis/src/lib.rs | 70 | ||||
-rw-r--r-- | crates/libanalysis/src/module_map.rs | 148 | ||||
-rw-r--r-- | crates/server/src/main_loop/mod.rs | 2 | ||||
-rw-r--r-- | crates/server/src/server_world.rs | 2 |
4 files changed, 149 insertions, 73 deletions
diff --git a/crates/libanalysis/src/lib.rs b/crates/libanalysis/src/lib.rs index d01144627..fee0d10d6 100644 --- a/crates/libanalysis/src/lib.rs +++ b/crates/libanalysis/src/lib.rs | |||
@@ -17,7 +17,6 @@ use rayon::prelude::*; | |||
17 | 17 | ||
18 | use std::{ | 18 | use std::{ |
19 | fmt, | 19 | fmt, |
20 | mem, | ||
21 | path::{Path}, | 20 | path::{Path}, |
22 | sync::{ | 21 | sync::{ |
23 | Arc, | 22 | Arc, |
@@ -36,18 +35,16 @@ use libeditor::{LineIndex, FileSymbol, find_node}; | |||
36 | 35 | ||
37 | use self::{ | 36 | use self::{ |
38 | symbol_index::FileSymbols, | 37 | symbol_index::FileSymbols, |
39 | module_map::ModuleMap, | 38 | module_map::{ModuleMap, ChangeKind}, |
40 | }; | 39 | }; |
41 | pub use self::symbol_index::Query; | 40 | pub use self::symbol_index::Query; |
42 | 41 | ||
43 | pub type Result<T> = ::std::result::Result<T, ::failure::Error>; | 42 | pub type Result<T> = ::std::result::Result<T, ::failure::Error>; |
44 | const INDEXING_THRESHOLD: usize = 128; | ||
45 | 43 | ||
46 | pub type FileResolver = dyn Fn(FileId, &Path) -> Option<FileId> + Send + Sync; | 44 | pub type FileResolver = dyn Fn(FileId, &Path) -> Option<FileId> + Send + Sync; |
47 | 45 | ||
48 | #[derive(Debug)] | 46 | #[derive(Debug)] |
49 | pub struct WorldState { | 47 | pub struct WorldState { |
50 | updates: Vec<FileId>, | ||
51 | data: Arc<WorldData> | 48 | data: Arc<WorldData> |
52 | } | 49 | } |
53 | 50 | ||
@@ -79,32 +76,16 @@ pub struct FileId(pub u32); | |||
79 | impl WorldState { | 76 | impl WorldState { |
80 | pub fn new() -> WorldState { | 77 | pub fn new() -> WorldState { |
81 | WorldState { | 78 | WorldState { |
82 | updates: Vec::new(), | ||
83 | data: Arc::new(WorldData::default()), | 79 | data: Arc::new(WorldData::default()), |
84 | } | 80 | } |
85 | } | 81 | } |
86 | 82 | ||
87 | pub fn snapshot( | 83 | pub fn snapshot( |
88 | &mut self, | 84 | &self, |
89 | file_resolver: impl Fn(FileId, &Path) -> Option<FileId> + 'static + Send + Sync, | 85 | file_resolver: impl Fn(FileId, &Path) -> Option<FileId> + 'static + Send + Sync, |
90 | ) -> World { | 86 | ) -> World { |
91 | let needs_reindex = self.updates.len() >= INDEXING_THRESHOLD; | ||
92 | if !self.updates.is_empty() { | ||
93 | let updates = mem::replace(&mut self.updates, Vec::new()); | ||
94 | let data = self.data_mut(); | ||
95 | for file_id in updates { | ||
96 | let syntax = data.file_map | ||
97 | .get(&file_id) | ||
98 | .map(|it| it.syntax()); | ||
99 | data.module_map.update_file( | ||
100 | file_id, | ||
101 | syntax, | ||
102 | &file_resolver, | ||
103 | ); | ||
104 | } | ||
105 | } | ||
106 | World { | 87 | World { |
107 | needs_reindex: AtomicBool::new(needs_reindex), | 88 | needs_reindex: AtomicBool::new(false), |
108 | file_resolver: Arc::new(file_resolver), | 89 | file_resolver: Arc::new(file_resolver), |
109 | data: self.data.clone() | 90 | data: self.data.clone() |
110 | } | 91 | } |
@@ -115,21 +96,26 @@ impl WorldState { | |||
115 | } | 96 | } |
116 | 97 | ||
117 | pub fn change_files(&mut self, changes: impl Iterator<Item=(FileId, Option<String>)>) { | 98 | pub fn change_files(&mut self, changes: impl Iterator<Item=(FileId, Option<String>)>) { |
118 | let mut updates = Vec::new(); | 99 | let data = self.data_mut(); |
119 | { | 100 | for (file_id, text) in changes { |
120 | let data = self.data_mut(); | 101 | let change_kind = if data.file_map.remove(&file_id).is_some() { |
121 | for (file_id, text) in changes { | 102 | if text.is_some() { |
122 | data.file_map.remove(&file_id); | 103 | ChangeKind::Update |
123 | if let Some(text) = text { | ||
124 | let file_data = FileData::new(text); | ||
125 | data.file_map.insert(file_id, Arc::new(file_data)); | ||
126 | } else { | 104 | } else { |
127 | data.file_map.remove(&file_id); | 105 | ChangeKind::Delete |
128 | } | 106 | } |
129 | updates.push(file_id); | 107 | } else { |
108 | ChangeKind::Insert | ||
109 | }; | ||
110 | data.module_map.update_file(file_id, change_kind); | ||
111 | data.file_map.remove(&file_id); | ||
112 | if let Some(text) = text { | ||
113 | let file_data = FileData::new(text); | ||
114 | data.file_map.insert(file_id, Arc::new(file_data)); | ||
115 | } else { | ||
116 | data.file_map.remove(&file_id); | ||
130 | } | 117 | } |
131 | } | 118 | } |
132 | self.updates.extend(updates) | ||
133 | } | 119 | } |
134 | 120 | ||
135 | fn data_mut(&mut self) -> &mut WorldData { | 121 | fn data_mut(&mut self) -> &mut WorldData { |
@@ -171,13 +157,17 @@ impl World { | |||
171 | let module_map = &self.data.module_map; | 157 | let module_map = &self.data.module_map; |
172 | let id = module_map.file2module(id); | 158 | let id = module_map.file2module(id); |
173 | module_map | 159 | module_map |
174 | .parent_modules(id) | 160 | .parent_modules( |
161 | id, | ||
162 | &*self.file_resolver, | ||
163 | &|file_id| self.file_syntax(file_id).unwrap(), | ||
164 | ) | ||
175 | .into_iter() | 165 | .into_iter() |
176 | .map(|(id, m)| { | 166 | .map(|(id, name, node)| { |
177 | let id = module_map.module2file(id); | 167 | let id = module_map.module2file(id); |
178 | let sym = FileSymbol { | 168 | let sym = FileSymbol { |
179 | name: m.name().unwrap().text(), | 169 | name, |
180 | node_range: m.syntax().range(), | 170 | node_range: node.range(), |
181 | kind: MODULE, | 171 | kind: MODULE, |
182 | }; | 172 | }; |
183 | (id, sym) | 173 | (id, sym) |
@@ -235,7 +225,11 @@ impl World { | |||
235 | let module_map = &self.data.module_map; | 225 | let module_map = &self.data.module_map; |
236 | let id = module_map.file2module(id); | 226 | let id = module_map.file2module(id); |
237 | module_map | 227 | module_map |
238 | .child_module_by_name(id, name.as_str()) | 228 | .child_module_by_name( |
229 | id, name.as_str(), | ||
230 | &*self.file_resolver, | ||
231 | &|file_id| self.file_syntax(file_id).unwrap(), | ||
232 | ) | ||
239 | .into_iter() | 233 | .into_iter() |
240 | .map(|id| module_map.module2file(id)) | 234 | .map(|id| module_map.module2file(id)) |
241 | .collect() | 235 | .collect() |
diff --git a/crates/libanalysis/src/module_map.rs b/crates/libanalysis/src/module_map.rs index 9b4c778b6..83e6e57f7 100644 --- a/crates/libanalysis/src/module_map.rs +++ b/crates/libanalysis/src/module_map.rs | |||
@@ -2,17 +2,38 @@ use std::{ | |||
2 | path::{PathBuf}, | 2 | path::{PathBuf}, |
3 | }; | 3 | }; |
4 | 4 | ||
5 | use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard}; | ||
5 | use libsyntax2::{ | 6 | use libsyntax2::{ |
6 | ast::{self, AstNode, NameOwner}, | 7 | ast::{self, AstNode, NameOwner, ParsedFile}, |
7 | SyntaxNode, ParsedFile, SmolStr, | 8 | SyntaxNode, SmolStr, |
8 | }; | 9 | }; |
9 | use {FileId, FileResolver}; | 10 | use {FileId, FileResolver}; |
10 | 11 | ||
12 | type SyntaxProvider<'a> = dyn Fn(FileId) -> ParsedFile + 'a; | ||
13 | |||
11 | #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] | 14 | #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] |
12 | pub struct ModuleId(FileId); | 15 | pub struct ModuleId(FileId); |
13 | 16 | ||
14 | #[derive(Clone, Debug, Default)] | 17 | #[derive(Debug, Default)] |
15 | pub struct ModuleMap { | 18 | pub struct ModuleMap { |
19 | state: RwLock<State>, | ||
20 | } | ||
21 | |||
22 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
23 | pub enum ChangeKind { | ||
24 | Delete, Insert, Update | ||
25 | } | ||
26 | |||
27 | impl Clone for ModuleMap { | ||
28 | fn clone(&self) -> ModuleMap { | ||
29 | let state = self.state.read().clone(); | ||
30 | ModuleMap { state: RwLock::new(state) } | ||
31 | } | ||
32 | } | ||
33 | |||
34 | #[derive(Clone, Debug, Default)] | ||
35 | struct State { | ||
36 | changes: Vec<(FileId, ChangeKind)>, | ||
16 | links: Vec<Link>, | 37 | links: Vec<Link>, |
17 | } | 38 | } |
18 | 39 | ||
@@ -24,31 +45,8 @@ struct Link { | |||
24 | } | 45 | } |
25 | 46 | ||
26 | impl ModuleMap { | 47 | impl ModuleMap { |
27 | pub fn update_file( | 48 | pub fn update_file(&mut self, file: FileId, change_kind: ChangeKind) { |
28 | &mut self, | 49 | self.state.get_mut().changes.push((file, change_kind)); |
29 | file_id: FileId, | ||
30 | syntax: Option<&ParsedFile>, | ||
31 | file_resolver: &FileResolver, | ||
32 | ) { | ||
33 | let mod_id = ModuleId(file_id); | ||
34 | self.links.retain(|link| link.owner != mod_id); | ||
35 | match syntax { | ||
36 | None => { | ||
37 | for link in self.links.iter_mut() { | ||
38 | link.points_to.retain(|&x| x != mod_id); | ||
39 | } | ||
40 | } | ||
41 | Some(syntax) => { | ||
42 | self.links.extend( | ||
43 | syntax.ast().modules().filter_map(|it| { | ||
44 | Link::new(mod_id, it) | ||
45 | }) | ||
46 | ) | ||
47 | } | ||
48 | } | ||
49 | self.links.iter_mut().for_each(|link| { | ||
50 | link.resolve(file_resolver) | ||
51 | }) | ||
52 | } | 50 | } |
53 | 51 | ||
54 | pub fn module2file(&self, m: ModuleId) -> FileId { | 52 | pub fn module2file(&self, m: ModuleId) -> FileId { |
@@ -59,8 +57,15 @@ impl ModuleMap { | |||
59 | ModuleId(file_id) | 57 | ModuleId(file_id) |
60 | } | 58 | } |
61 | 59 | ||
62 | pub fn child_module_by_name(&self, parent_mod: ModuleId, child_mod: &str) -> Vec<ModuleId> { | 60 | pub fn child_module_by_name<'a>( |
63 | self.links | 61 | &self, |
62 | parent_mod: ModuleId, | ||
63 | child_mod: &str, | ||
64 | file_resolver: &FileResolver, | ||
65 | syntax_provider: &SyntaxProvider, | ||
66 | ) -> Vec<ModuleId> { | ||
67 | self.links(file_resolver, syntax_provider) | ||
68 | .links | ||
64 | .iter() | 69 | .iter() |
65 | .filter(|link| link.owner == parent_mod) | 70 | .filter(|link| link.owner == parent_mod) |
66 | .filter(|link| link.name() == child_mod) | 71 | .filter(|link| link.name() == child_mod) |
@@ -69,13 +74,90 @@ impl ModuleMap { | |||
69 | .collect() | 74 | .collect() |
70 | } | 75 | } |
71 | 76 | ||
72 | pub fn parent_modules<'a>(&'a self, m: ModuleId) -> impl Iterator<Item=(ModuleId, ast::Module<'a>)> + 'a { | 77 | pub fn parent_modules( |
73 | self.links | 78 | &self, |
79 | m: ModuleId, | ||
80 | file_resolver: &FileResolver, | ||
81 | syntax_provider: &SyntaxProvider, | ||
82 | ) -> Vec<(ModuleId, SmolStr, SyntaxNode)> { | ||
83 | let links = self.links(file_resolver, syntax_provider); | ||
84 | let res = links | ||
85 | .links | ||
74 | .iter() | 86 | .iter() |
75 | .filter(move |link| link.points_to.iter().any(|&it| it == m)) | 87 | .filter(move |link| link.points_to.iter().any(|&it| it == m)) |
76 | .map(|link| { | 88 | .map(|link| { |
77 | (link.owner, link.ast()) | 89 | (link.owner, link.name().clone(), link.syntax.clone()) |
78 | }) | 90 | }) |
91 | .collect(); | ||
92 | res | ||
93 | } | ||
94 | |||
95 | fn links( | ||
96 | &self, | ||
97 | file_resolver: &FileResolver, | ||
98 | syntax_provider: &SyntaxProvider, | ||
99 | ) -> RwLockReadGuard<State> { | ||
100 | { | ||
101 | let guard = self.state.read(); | ||
102 | if guard.changes.is_empty() { | ||
103 | return guard; | ||
104 | } | ||
105 | } | ||
106 | let mut guard = self.state.write(); | ||
107 | if !guard.changes.is_empty() { | ||
108 | guard.apply_changes(file_resolver, syntax_provider); | ||
109 | } | ||
110 | assert!(guard.changes.is_empty()); | ||
111 | RwLockWriteGuard::downgrade(guard) | ||
112 | } | ||
113 | } | ||
114 | |||
115 | impl State { | ||
116 | pub fn apply_changes( | ||
117 | &mut self, | ||
118 | file_resolver: &FileResolver, | ||
119 | syntax_provider: &SyntaxProvider, | ||
120 | ) { | ||
121 | let mut reresolve = false; | ||
122 | for (file_id, kind) in self.changes.drain(..) { | ||
123 | let mod_id = ModuleId(file_id); | ||
124 | self.links.retain(|link| link.owner != mod_id); | ||
125 | match kind { | ||
126 | ChangeKind::Delete => { | ||
127 | for link in self.links.iter_mut() { | ||
128 | link.points_to.retain(|&x| x != mod_id); | ||
129 | } | ||
130 | } | ||
131 | ChangeKind::Insert => { | ||
132 | let file = syntax_provider(file_id); | ||
133 | self.links.extend( | ||
134 | file | ||
135 | .ast() | ||
136 | .modules() | ||
137 | .filter_map(|it| Link::new(mod_id, it)) | ||
138 | ); | ||
139 | reresolve = true; | ||
140 | } | ||
141 | ChangeKind::Update => { | ||
142 | let file = syntax_provider(file_id); | ||
143 | self.links.extend( | ||
144 | file | ||
145 | .ast() | ||
146 | .modules() | ||
147 | .filter_map(|it| Link::new(mod_id, it)) | ||
148 | .map(|mut link| { | ||
149 | link.resolve(file_resolver); | ||
150 | link | ||
151 | }) | ||
152 | ); | ||
153 | } | ||
154 | } | ||
155 | } | ||
156 | if reresolve { | ||
157 | for link in self.links.iter_mut() { | ||
158 | link.resolve(file_resolver) | ||
159 | } | ||
160 | } | ||
79 | } | 161 | } |
80 | } | 162 | } |
81 | 163 | ||
diff --git a/crates/server/src/main_loop/mod.rs b/crates/server/src/main_loop/mod.rs index 12a903dac..752d6ddb2 100644 --- a/crates/server/src/main_loop/mod.rs +++ b/crates/server/src/main_loop/mod.rs | |||
@@ -252,7 +252,7 @@ fn on_notification( | |||
252 | fn handle_request_on_threadpool<R: req::ClientRequest>( | 252 | fn handle_request_on_threadpool<R: req::ClientRequest>( |
253 | req: &mut Option<RawRequest>, | 253 | req: &mut Option<RawRequest>, |
254 | pool: &ThreadPool, | 254 | pool: &ThreadPool, |
255 | world: &mut ServerWorldState, | 255 | world: &ServerWorldState, |
256 | sender: &Sender<Task>, | 256 | sender: &Sender<Task>, |
257 | f: fn(ServerWorld, R::Params) -> Result<R::Result>, | 257 | f: fn(ServerWorld, R::Params) -> Result<R::Result>, |
258 | ) -> Result<()> | 258 | ) -> Result<()> |
diff --git a/crates/server/src/server_world.rs b/crates/server/src/server_world.rs index 9850822cd..c0d2efb86 100644 --- a/crates/server/src/server_world.rs +++ b/crates/server/src/server_world.rs | |||
@@ -86,7 +86,7 @@ impl ServerWorldState { | |||
86 | Ok(()) | 86 | Ok(()) |
87 | } | 87 | } |
88 | 88 | ||
89 | pub fn snapshot(&mut self) -> ServerWorld { | 89 | pub fn snapshot(&self) -> ServerWorld { |
90 | let pm = self.path_map.clone(); | 90 | let pm = self.path_map.clone(); |
91 | ServerWorld { | 91 | ServerWorld { |
92 | analysis: self.analysis.snapshot(move |id, path| { | 92 | analysis: self.analysis.snapshot(move |id, path| { |