diff options
author | Kirill Bulatov <[email protected]> | 2020-09-07 18:52:37 +0100 |
---|---|---|
committer | Kirill Bulatov <[email protected]> | 2020-09-09 23:42:20 +0100 |
commit | f9c14ac7204c38633e70b3efd47a5b1f9056afd0 (patch) | |
tree | 60d375f39f4737630e9a8166975c71f3ec5f2f9f | |
parent | 6ba479cd058aa54a9f161085c7ff9ac1f12d8df3 (diff) |
Move most of the logic into the completion module
-rw-r--r-- | crates/base_db/src/input.rs | 8 | ||||
-rw-r--r-- | crates/base_db/src/lib.rs | 84 | ||||
-rw-r--r-- | crates/hir_def/src/test_db.rs | 3 | ||||
-rw-r--r-- | crates/hir_expand/src/test_db.rs | 3 | ||||
-rw-r--r-- | crates/hir_ty/src/test_db.rs | 3 | ||||
-rw-r--r-- | crates/ide/src/completion/complete_mod.rs | 116 | ||||
-rw-r--r-- | crates/ide/src/completion/completion_context.rs | 5 | ||||
-rw-r--r-- | crates/ide_db/src/lib.rs | 3 |
8 files changed, 107 insertions, 118 deletions
diff --git a/crates/base_db/src/input.rs b/crates/base_db/src/input.rs index f3d65cdf0..9a61f1d56 100644 --- a/crates/base_db/src/input.rs +++ b/crates/base_db/src/input.rs | |||
@@ -12,7 +12,7 @@ use cfg::CfgOptions; | |||
12 | use rustc_hash::{FxHashMap, FxHashSet}; | 12 | use rustc_hash::{FxHashMap, FxHashSet}; |
13 | use syntax::SmolStr; | 13 | use syntax::SmolStr; |
14 | use tt::TokenExpander; | 14 | use tt::TokenExpander; |
15 | use vfs::file_set::FileSet; | 15 | use vfs::{file_set::FileSet, VfsPath}; |
16 | 16 | ||
17 | pub use vfs::FileId; | 17 | pub use vfs::FileId; |
18 | 18 | ||
@@ -43,6 +43,12 @@ impl SourceRoot { | |||
43 | pub fn new_library(file_set: FileSet) -> SourceRoot { | 43 | pub fn new_library(file_set: FileSet) -> SourceRoot { |
44 | SourceRoot { is_library: true, file_set } | 44 | SourceRoot { is_library: true, file_set } |
45 | } | 45 | } |
46 | pub fn path_for_file(&self, file: &FileId) -> Option<&VfsPath> { | ||
47 | self.file_set.path_for_file(file) | ||
48 | } | ||
49 | pub fn file_for_path(&self, path: &VfsPath) -> Option<&FileId> { | ||
50 | self.file_set.file_for_path(path) | ||
51 | } | ||
46 | pub fn iter(&self) -> impl Iterator<Item = FileId> + '_ { | 52 | pub fn iter(&self) -> impl Iterator<Item = FileId> + '_ { |
47 | self.file_set.iter() | 53 | self.file_set.iter() |
48 | } | 54 | } |
diff --git a/crates/base_db/src/lib.rs b/crates/base_db/src/lib.rs index 321007d33..ee3415850 100644 --- a/crates/base_db/src/lib.rs +++ b/crates/base_db/src/lib.rs | |||
@@ -96,7 +96,6 @@ pub trait FileLoader { | |||
96 | /// `#[path = "C://no/way"]` | 96 | /// `#[path = "C://no/way"]` |
97 | fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId>; | 97 | fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId>; |
98 | fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>>; | 98 | fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>>; |
99 | fn possible_sudmobule_names(&self, module_file: FileId) -> Vec<String>; | ||
100 | } | 99 | } |
101 | 100 | ||
102 | /// Database which stores all significant input facts: source code and project | 101 | /// Database which stores all significant input facts: source code and project |
@@ -156,8 +155,8 @@ impl<T: SourceDatabaseExt> FileLoader for FileLoaderDelegate<&'_ T> { | |||
156 | } | 155 | } |
157 | fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> { | 156 | fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> { |
158 | // FIXME: this *somehow* should be platform agnostic... | 157 | // FIXME: this *somehow* should be platform agnostic... |
159 | // self.source_root(anchor) | 158 | let source_root = self.0.file_source_root(anchor); |
160 | let source_root = self.source_root(anchor); | 159 | let source_root = self.0.source_root(source_root); |
161 | source_root.file_set.resolve_path(anchor, path) | 160 | source_root.file_set.resolve_path(anchor, path) |
162 | } | 161 | } |
163 | 162 | ||
@@ -165,83 +164,4 @@ impl<T: SourceDatabaseExt> FileLoader for FileLoaderDelegate<&'_ T> { | |||
165 | let source_root = self.0.file_source_root(file_id); | 164 | let source_root = self.0.file_source_root(file_id); |
166 | self.0.source_root_crates(source_root) | 165 | self.0.source_root_crates(source_root) |
167 | } | 166 | } |
168 | |||
169 | fn possible_sudmobule_names(&self, module_file: FileId) -> Vec<String> { | ||
170 | possible_sudmobule_names(&self.source_root(module_file).file_set, module_file) | ||
171 | } | ||
172 | } | ||
173 | |||
174 | impl<T: SourceDatabaseExt> FileLoaderDelegate<&'_ T> { | ||
175 | fn source_root(&self, anchor: FileId) -> Arc<SourceRoot> { | ||
176 | let source_root = self.0.file_source_root(anchor); | ||
177 | self.0.source_root(source_root) | ||
178 | } | ||
179 | } | ||
180 | |||
181 | fn possible_sudmobule_names(module_files: &FileSet, module_file: FileId) -> Vec<String> { | ||
182 | let directory_to_look_for_submodules = match module_files | ||
183 | .path_for_file(&module_file) | ||
184 | .and_then(|module_file_path| get_directory_with_submodules(module_file_path)) | ||
185 | { | ||
186 | Some(directory) => directory, | ||
187 | None => return Vec::new(), | ||
188 | }; | ||
189 | module_files | ||
190 | .iter() | ||
191 | .filter(|submodule_file| submodule_file != &module_file) | ||
192 | .filter_map(|submodule_file| { | ||
193 | let submodule_path = module_files.path_for_file(&submodule_file)?; | ||
194 | if submodule_path.parent()? == directory_to_look_for_submodules { | ||
195 | submodule_path.file_name_and_extension() | ||
196 | } else { | ||
197 | None | ||
198 | } | ||
199 | }) | ||
200 | .filter_map(|file_name_and_extension| { | ||
201 | match file_name_and_extension { | ||
202 | // TODO kb wrong resolution for nested non-file modules (mod tests { mod <|> }) | ||
203 | // TODO kb in src/bin when a module is included into another, | ||
204 | // the included file gets "moved" into a directory below and now cannot add any other modules | ||
205 | ("mod", Some("rs")) | ("lib", Some("rs")) | ("main", Some("rs")) => None, | ||
206 | (file_name, Some("rs")) => Some(file_name.to_owned()), | ||
207 | (subdirectory_name, None) => { | ||
208 | let mod_rs_path = | ||
209 | directory_to_look_for_submodules.join(subdirectory_name)?.join("mod.rs")?; | ||
210 | if module_files.file_for_path(&mod_rs_path).is_some() { | ||
211 | Some(subdirectory_name.to_owned()) | ||
212 | } else { | ||
213 | None | ||
214 | } | ||
215 | } | ||
216 | _ => None, | ||
217 | } | ||
218 | }) | ||
219 | .collect() | ||
220 | } | ||
221 | |||
222 | fn get_directory_with_submodules(module_file_path: &VfsPath) -> Option<VfsPath> { | ||
223 | let module_directory_path = module_file_path.parent()?; | ||
224 | match module_file_path.file_name_and_extension()? { | ||
225 | ("mod", Some("rs")) | ("lib", Some("rs")) | ("main", Some("rs")) => { | ||
226 | Some(module_directory_path) | ||
227 | } | ||
228 | (regular_rust_file_name, Some("rs")) => { | ||
229 | if matches!( | ||
230 | ( | ||
231 | module_directory_path | ||
232 | .parent() | ||
233 | .as_ref() | ||
234 | .and_then(|path| path.file_name_and_extension()), | ||
235 | module_directory_path.file_name_and_extension(), | ||
236 | ), | ||
237 | (Some(("src", None)), Some(("bin", None))) | ||
238 | ) { | ||
239 | // files in /src/bin/ can import each other directly | ||
240 | Some(module_directory_path) | ||
241 | } else { | ||
242 | module_directory_path.join(regular_rust_file_name) | ||
243 | } | ||
244 | } | ||
245 | _ => None, | ||
246 | } | ||
247 | } | 167 | } |
diff --git a/crates/hir_def/src/test_db.rs b/crates/hir_def/src/test_db.rs index 5bcfaf464..42a762936 100644 --- a/crates/hir_def/src/test_db.rs +++ b/crates/hir_def/src/test_db.rs | |||
@@ -63,9 +63,6 @@ impl FileLoader for TestDB { | |||
63 | fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> { | 63 | fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> { |
64 | FileLoaderDelegate(self).relevant_crates(file_id) | 64 | FileLoaderDelegate(self).relevant_crates(file_id) |
65 | } | 65 | } |
66 | fn possible_sudmobule_names(&self, module_file: FileId) -> Vec<String> { | ||
67 | FileLoaderDelegate(self).possible_sudmobule_names(module_file) | ||
68 | } | ||
69 | } | 66 | } |
70 | 67 | ||
71 | impl TestDB { | 68 | impl TestDB { |
diff --git a/crates/hir_expand/src/test_db.rs b/crates/hir_expand/src/test_db.rs index cf42dde7a..86a5d867e 100644 --- a/crates/hir_expand/src/test_db.rs +++ b/crates/hir_expand/src/test_db.rs | |||
@@ -46,7 +46,4 @@ impl FileLoader for TestDB { | |||
46 | fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> { | 46 | fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> { |
47 | FileLoaderDelegate(self).relevant_crates(file_id) | 47 | FileLoaderDelegate(self).relevant_crates(file_id) |
48 | } | 48 | } |
49 | fn possible_sudmobule_names(&self, module_file: FileId) -> Vec<String> { | ||
50 | FileLoaderDelegate(self).possible_sudmobule_names(module_file) | ||
51 | } | ||
52 | } | 49 | } |
diff --git a/crates/hir_ty/src/test_db.rs b/crates/hir_ty/src/test_db.rs index 0696f41dd..15b8435e9 100644 --- a/crates/hir_ty/src/test_db.rs +++ b/crates/hir_ty/src/test_db.rs | |||
@@ -73,9 +73,6 @@ impl FileLoader for TestDB { | |||
73 | fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> { | 73 | fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> { |
74 | FileLoaderDelegate(self).relevant_crates(file_id) | 74 | FileLoaderDelegate(self).relevant_crates(file_id) |
75 | } | 75 | } |
76 | fn possible_sudmobule_names(&self, module_file: FileId) -> Vec<String> { | ||
77 | FileLoaderDelegate(self).possible_sudmobule_names(module_file) | ||
78 | } | ||
79 | } | 76 | } |
80 | 77 | ||
81 | impl TestDB { | 78 | impl TestDB { |
diff --git a/crates/ide/src/completion/complete_mod.rs b/crates/ide/src/completion/complete_mod.rs index 4c1e79603..da3d93bad 100644 --- a/crates/ide/src/completion/complete_mod.rs +++ b/crates/ide/src/completion/complete_mod.rs | |||
@@ -1,35 +1,61 @@ | |||
1 | //! Completes mod declarations. | 1 | //! Completes mod declarations. |
2 | 2 | ||
3 | use base_db::FileLoader; | 3 | use base_db::{SourceDatabaseExt, VfsPath}; |
4 | use hir::ModuleSource; | 4 | use hir::{Module, ModuleSource}; |
5 | use ide_db::RootDatabase; | ||
5 | 6 | ||
6 | use super::{completion_context::CompletionContext, completion_item::Completions}; | 7 | use super::{completion_context::CompletionContext, completion_item::Completions}; |
7 | 8 | ||
8 | /// Complete mod declaration, i.e. `mod <|> ;` | 9 | /// Complete mod declaration, i.e. `mod <|> ;` |
9 | pub(super) fn complete_mod(acc: &mut Completions, ctx: &CompletionContext) { | 10 | pub(super) fn complete_mod(acc: &mut Completions, ctx: &CompletionContext) { |
10 | let module_names_for_import = ctx | 11 | let module_names_for_import = ctx |
11 | .sema | 12 | .scope |
12 | // TODO kb this is wrong, since we need not the file module | 13 | .module() |
13 | .to_module_def(ctx.position.file_id) | ||
14 | .and_then(|current_module| { | 14 | .and_then(|current_module| { |
15 | dbg!(current_module.name(ctx.db)); | 15 | let module_path = path_to_closest_containing_module_file(current_module, ctx.db); |
16 | dbg!(current_module.definition_source(ctx.db)); | ||
17 | dbg!(current_module.declaration_source(ctx.db)); | ||
18 | let mut zz = Vec::new(); | ||
19 | let mut vv = Some(current_module); | ||
20 | while let Some(ModuleSource::Module(_)) = | ||
21 | vv.map(|vv| vv.definition_source(ctx.db).value) | ||
22 | { | ||
23 | zz.push(current_module.name(ctx.db)); | ||
24 | vv = current_module.parent(ctx.db); | ||
25 | } | ||
26 | dbg!(zz); | ||
27 | let definition_source = current_module.definition_source(ctx.db); | ||
28 | // TODO kb filter out declarations in possible_sudmobule_names | 16 | // TODO kb filter out declarations in possible_sudmobule_names |
29 | // let declaration_source = current_module.declaration_source(ctx.db); | 17 | // let declaration_source = current_module.declaration_source(ctx.db); |
30 | let module_definition_source_file = definition_source.file_id.original_file(ctx.db); | 18 | let module_definition_source_file = |
31 | let mod_declaration_candidates = | 19 | current_module.definition_source(ctx.db).file_id.original_file(ctx.db); |
32 | ctx.db.possible_sudmobule_names(module_definition_source_file); | 20 | |
21 | let source_root_id = ctx.db.file_source_root(module_definition_source_file); | ||
22 | let source_root = ctx.db.source_root(source_root_id); | ||
23 | let directory_to_look_for_submodules = source_root | ||
24 | .path_for_file(&module_definition_source_file) | ||
25 | .and_then(|module_file_path| get_directory_with_submodules(module_file_path))?; | ||
26 | |||
27 | let mod_declaration_candidates = source_root | ||
28 | .iter() | ||
29 | .filter(|submodule_file| submodule_file != &module_definition_source_file) | ||
30 | .filter_map(|submodule_file| { | ||
31 | let submodule_path = source_root.path_for_file(&submodule_file)?; | ||
32 | if submodule_path.parent()? == directory_to_look_for_submodules { | ||
33 | submodule_path.file_name_and_extension() | ||
34 | } else { | ||
35 | None | ||
36 | } | ||
37 | }) | ||
38 | .filter_map(|file_name_and_extension| { | ||
39 | match file_name_and_extension { | ||
40 | // TODO kb wrong resolution for nested non-file modules (mod tests { mod <|> }) | ||
41 | // TODO kb in src/bin when a module is included into another, | ||
42 | // the included file gets "moved" into a directory below and now cannot add any other modules | ||
43 | ("mod", Some("rs")) | ("lib", Some("rs")) | ("main", Some("rs")) => None, | ||
44 | (file_name, Some("rs")) => Some(file_name.to_owned()), | ||
45 | (subdirectory_name, None) => { | ||
46 | let mod_rs_path = directory_to_look_for_submodules | ||
47 | .join(subdirectory_name)? | ||
48 | .join("mod.rs")?; | ||
49 | if source_root.file_for_path(&mod_rs_path).is_some() { | ||
50 | Some(subdirectory_name.to_owned()) | ||
51 | } else { | ||
52 | None | ||
53 | } | ||
54 | } | ||
55 | _ => None, | ||
56 | } | ||
57 | }) | ||
58 | .collect::<Vec<_>>(); | ||
33 | dbg!(mod_declaration_candidates); | 59 | dbg!(mod_declaration_candidates); |
34 | // TODO kb exlude existing children from the candidates | 60 | // TODO kb exlude existing children from the candidates |
35 | let existing_children = current_module.children(ctx.db).collect::<Vec<_>>(); | 61 | let existing_children = current_module.children(ctx.db).collect::<Vec<_>>(); |
@@ -37,3 +63,51 @@ pub(super) fn complete_mod(acc: &mut Completions, ctx: &CompletionContext) { | |||
37 | }) | 63 | }) |
38 | .unwrap_or_default(); | 64 | .unwrap_or_default(); |
39 | } | 65 | } |
66 | |||
67 | fn path_to_closest_containing_module_file( | ||
68 | current_module: Module, | ||
69 | db: &RootDatabase, | ||
70 | ) -> Vec<Module> { | ||
71 | let mut path = Vec::new(); | ||
72 | |||
73 | let mut current_module = Some(current_module); | ||
74 | while let Some(ModuleSource::Module(_)) = | ||
75 | current_module.map(|module| module.definition_source(db).value) | ||
76 | { | ||
77 | if let Some(module) = current_module { | ||
78 | path.insert(0, module); | ||
79 | current_module = module.parent(db); | ||
80 | } else { | ||
81 | current_module = None; | ||
82 | } | ||
83 | } | ||
84 | |||
85 | path | ||
86 | } | ||
87 | |||
88 | fn get_directory_with_submodules(module_file_path: &VfsPath) -> Option<VfsPath> { | ||
89 | let module_directory_path = module_file_path.parent()?; | ||
90 | match module_file_path.file_name_and_extension()? { | ||
91 | ("mod", Some("rs")) | ("lib", Some("rs")) | ("main", Some("rs")) => { | ||
92 | Some(module_directory_path) | ||
93 | } | ||
94 | (regular_rust_file_name, Some("rs")) => { | ||
95 | if matches!( | ||
96 | ( | ||
97 | module_directory_path | ||
98 | .parent() | ||
99 | .as_ref() | ||
100 | .and_then(|path| path.file_name_and_extension()), | ||
101 | module_directory_path.file_name_and_extension(), | ||
102 | ), | ||
103 | (Some(("src", None)), Some(("bin", None))) | ||
104 | ) { | ||
105 | // files in /src/bin/ can import each other directly | ||
106 | Some(module_directory_path) | ||
107 | } else { | ||
108 | module_directory_path.join(regular_rust_file_name) | ||
109 | } | ||
110 | } | ||
111 | _ => None, | ||
112 | } | ||
113 | } | ||
diff --git a/crates/ide/src/completion/completion_context.rs b/crates/ide/src/completion/completion_context.rs index 31886942a..47355d5dc 100644 --- a/crates/ide/src/completion/completion_context.rs +++ b/crates/ide/src/completion/completion_context.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use base_db::{FileLoader, SourceDatabase}; | 3 | use base_db::SourceDatabase; |
4 | use hir::{ModuleSource, Semantics, SemanticsScope, Type}; | 4 | use hir::{Semantics, SemanticsScope, Type}; |
5 | use ide_db::RootDatabase; | 5 | use ide_db::RootDatabase; |
6 | use syntax::{ | 6 | use syntax::{ |
7 | algo::{find_covering_element, find_node_at_offset}, | 7 | algo::{find_covering_element, find_node_at_offset}, |
@@ -112,6 +112,7 @@ impl<'a> CompletionContext<'a> { | |||
112 | }; | 112 | }; |
113 | let fake_ident_token = | 113 | let fake_ident_token = |
114 | file_with_fake_ident.syntax().token_at_offset(position.offset).right_biased().unwrap(); | 114 | file_with_fake_ident.syntax().token_at_offset(position.offset).right_biased().unwrap(); |
115 | |||
115 | let krate = sema.to_module_def(position.file_id).map(|m| m.krate()); | 116 | let krate = sema.to_module_def(position.file_id).map(|m| m.krate()); |
116 | let original_token = | 117 | let original_token = |
117 | original_file.syntax().token_at_offset(position.offset).left_biased()?; | 118 | original_file.syntax().token_at_offset(position.offset).left_biased()?; |
diff --git a/crates/ide_db/src/lib.rs b/crates/ide_db/src/lib.rs index 9f3be8601..70ada02f3 100644 --- a/crates/ide_db/src/lib.rs +++ b/crates/ide_db/src/lib.rs | |||
@@ -74,9 +74,6 @@ impl FileLoader for RootDatabase { | |||
74 | fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> { | 74 | fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> { |
75 | FileLoaderDelegate(self).relevant_crates(file_id) | 75 | FileLoaderDelegate(self).relevant_crates(file_id) |
76 | } | 76 | } |
77 | fn possible_sudmobule_names(&self, module_file: FileId) -> Vec<String> { | ||
78 | FileLoaderDelegate(self).possible_sudmobule_names(module_file) | ||
79 | } | ||
80 | } | 77 | } |
81 | 78 | ||
82 | impl salsa::Database for RootDatabase { | 79 | impl salsa::Database for RootDatabase { |