diff options
author | Kirill Bulatov <[email protected]> | 2020-09-07 19:39:23 +0100 |
---|---|---|
committer | Kirill Bulatov <[email protected]> | 2020-09-09 23:42:20 +0100 |
commit | 3fd6f451417fee0e8d95d06fb298c94b22bca917 (patch) | |
tree | 3a360dfbd93ea0a6111a7a0ea339da6a462d2a8b /crates/ide/src | |
parent | f9c14ac7204c38633e70b3efd47a5b1f9056afd0 (diff) |
Properly handle nested submodules in the same file
Diffstat (limited to 'crates/ide/src')
-rw-r--r-- | crates/ide/src/completion/complete_mod.rs | 149 |
1 files changed, 79 insertions, 70 deletions
diff --git a/crates/ide/src/completion/complete_mod.rs b/crates/ide/src/completion/complete_mod.rs index da3d93bad..def8b8968 100644 --- a/crates/ide/src/completion/complete_mod.rs +++ b/crates/ide/src/completion/complete_mod.rs | |||
@@ -7,87 +7,66 @@ use ide_db::RootDatabase; | |||
7 | use super::{completion_context::CompletionContext, completion_item::Completions}; | 7 | use super::{completion_context::CompletionContext, completion_item::Completions}; |
8 | 8 | ||
9 | /// Complete mod declaration, i.e. `mod <|> ;` | 9 | /// Complete mod declaration, i.e. `mod <|> ;` |
10 | pub(super) fn complete_mod(acc: &mut Completions, ctx: &CompletionContext) { | 10 | pub(super) fn complete_mod(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { |
11 | let module_names_for_import = ctx | 11 | let current_module = ctx.scope.module()?; |
12 | .scope | ||
13 | .module() | ||
14 | .and_then(|current_module| { | ||
15 | let module_path = path_to_closest_containing_module_file(current_module, ctx.db); | ||
16 | // TODO kb filter out declarations in possible_sudmobule_names | ||
17 | // let declaration_source = current_module.declaration_source(ctx.db); | ||
18 | let module_definition_source_file = | ||
19 | current_module.definition_source(ctx.db).file_id.original_file(ctx.db); | ||
20 | 12 | ||
21 | let source_root_id = ctx.db.file_source_root(module_definition_source_file); | 13 | // TODO kb filter out declarations in possible_sudmobule_names |
22 | let source_root = ctx.db.source_root(source_root_id); | 14 | // let declaration_source = current_module.declaration_source(ctx.db); |
23 | let directory_to_look_for_submodules = source_root | 15 | let module_definition_source_file = |
24 | .path_for_file(&module_definition_source_file) | 16 | current_module.definition_source(ctx.db).file_id.original_file(ctx.db); |
25 | .and_then(|module_file_path| get_directory_with_submodules(module_file_path))?; | 17 | let source_root = ctx.db.source_root(ctx.db.file_source_root(module_definition_source_file)); |
18 | let directory_to_look_for_submodules = directory_to_look_for_submodules( | ||
19 | current_module, | ||
20 | ctx.db, | ||
21 | source_root.path_for_file(&module_definition_source_file)?, | ||
22 | )?; | ||
26 | 23 | ||
27 | let mod_declaration_candidates = source_root | 24 | let mod_declaration_candidates = source_root |
28 | .iter() | 25 | .iter() |
29 | .filter(|submodule_file| submodule_file != &module_definition_source_file) | 26 | .filter(|submodule_file| submodule_file != &module_definition_source_file) |
30 | .filter_map(|submodule_file| { | 27 | .filter_map(|submodule_file| { |
31 | let submodule_path = source_root.path_for_file(&submodule_file)?; | 28 | let submodule_path = source_root.path_for_file(&submodule_file)?; |
32 | if submodule_path.parent()? == directory_to_look_for_submodules { | 29 | if submodule_path.parent()? == directory_to_look_for_submodules { |
33 | submodule_path.file_name_and_extension() | 30 | submodule_path.file_name_and_extension() |
31 | } else { | ||
32 | None | ||
33 | } | ||
34 | }) | ||
35 | .filter_map(|file_name_and_extension| { | ||
36 | match file_name_and_extension { | ||
37 | // TODO kb in src/bin when a module is included into another, | ||
38 | // the included file gets "moved" into a directory below and now cannot add any other modules | ||
39 | ("mod", Some("rs")) | ("lib", Some("rs")) | ("main", Some("rs")) => None, | ||
40 | (file_name, Some("rs")) => Some(file_name.to_owned()), | ||
41 | (subdirectory_name, None) => { | ||
42 | let mod_rs_path = | ||
43 | directory_to_look_for_submodules.join(subdirectory_name)?.join("mod.rs")?; | ||
44 | if source_root.file_for_path(&mod_rs_path).is_some() { | ||
45 | Some(subdirectory_name.to_owned()) | ||
34 | } else { | 46 | } else { |
35 | None | 47 | None |
36 | } | 48 | } |
37 | }) | 49 | } |
38 | .filter_map(|file_name_and_extension| { | 50 | _ => None, |
39 | match file_name_and_extension { | 51 | } |
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<_>>(); | ||
59 | dbg!(mod_declaration_candidates); | ||
60 | // TODO kb exlude existing children from the candidates | ||
61 | let existing_children = current_module.children(ctx.db).collect::<Vec<_>>(); | ||
62 | None::<Vec<String>> | ||
63 | }) | 52 | }) |
64 | .unwrap_or_default(); | 53 | .collect::<Vec<_>>(); |
65 | } | 54 | dbg!(mod_declaration_candidates); |
66 | 55 | ||
67 | fn path_to_closest_containing_module_file( | 56 | // TODO kb exlude existing children from the candidates |
68 | current_module: Module, | 57 | let existing_children = current_module.children(ctx.db).collect::<Vec<_>>(); |
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 | 58 | ||
85 | path | 59 | Some(()) |
86 | } | 60 | } |
87 | 61 | ||
88 | fn get_directory_with_submodules(module_file_path: &VfsPath) -> Option<VfsPath> { | 62 | fn directory_to_look_for_submodules( |
63 | module: Module, | ||
64 | db: &RootDatabase, | ||
65 | module_file_path: &VfsPath, | ||
66 | ) -> Option<VfsPath> { | ||
89 | let module_directory_path = module_file_path.parent()?; | 67 | let module_directory_path = module_file_path.parent()?; |
90 | match module_file_path.file_name_and_extension()? { | 68 | |
69 | let base_directory = match module_file_path.file_name_and_extension()? { | ||
91 | ("mod", Some("rs")) | ("lib", Some("rs")) | ("main", Some("rs")) => { | 70 | ("mod", Some("rs")) | ("lib", Some("rs")) | ("main", Some("rs")) => { |
92 | Some(module_directory_path) | 71 | Some(module_directory_path) |
93 | } | 72 | } |
@@ -109,5 +88,35 @@ fn get_directory_with_submodules(module_file_path: &VfsPath) -> Option<VfsPath> | |||
109 | } | 88 | } |
110 | } | 89 | } |
111 | _ => None, | 90 | _ => None, |
91 | }?; | ||
92 | |||
93 | let mut resulting_path = base_directory; | ||
94 | for module in module_chain_to_containing_module_file(module, db) { | ||
95 | if let Some(name) = module.name(db) { | ||
96 | resulting_path = resulting_path.join(&name.to_string())?; | ||
97 | } | ||
98 | } | ||
99 | |||
100 | Some(resulting_path) | ||
101 | } | ||
102 | |||
103 | fn module_chain_to_containing_module_file( | ||
104 | current_module: Module, | ||
105 | db: &RootDatabase, | ||
106 | ) -> Vec<Module> { | ||
107 | let mut path = Vec::new(); | ||
108 | |||
109 | let mut current_module = Some(current_module); | ||
110 | while let Some(ModuleSource::Module(_)) = | ||
111 | current_module.map(|module| module.definition_source(db).value) | ||
112 | { | ||
113 | if let Some(module) = current_module { | ||
114 | path.insert(0, module); | ||
115 | current_module = module.parent(db); | ||
116 | } else { | ||
117 | current_module = None; | ||
118 | } | ||
112 | } | 119 | } |
120 | |||
121 | path | ||
113 | } | 122 | } |