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 /crates/ide/src/completion | |
parent | 6ba479cd058aa54a9f161085c7ff9ac1f12d8df3 (diff) |
Move most of the logic into the completion module
Diffstat (limited to 'crates/ide/src/completion')
-rw-r--r-- | crates/ide/src/completion/complete_mod.rs | 116 | ||||
-rw-r--r-- | crates/ide/src/completion/completion_context.rs | 5 |
2 files changed, 98 insertions, 23 deletions
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()?; |