Skip to content

Commit 3fd6f45

Browse files
Properly handle nested submodules in the same file
1 parent f9c14ac commit 3fd6f45

File tree

1 file changed

+79
-70
lines changed

1 file changed

+79
-70
lines changed

crates/ide/src/completion/complete_mod.rs

Lines changed: 79 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -7,87 +7,66 @@ use ide_db::RootDatabase;
77
use super::{completion_context::CompletionContext, completion_item::Completions};
88

99
/// Complete mod declaration, i.e. `mod <|> ;`
10-
pub(super) fn complete_mod(acc: &mut Completions, ctx: &CompletionContext) {
11-
let module_names_for_import = ctx
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);
10+
pub(super) fn complete_mod(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
11+
let current_module = ctx.scope.module()?;
2012

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))?;
13+
// TODO kb filter out declarations in possible_sudmobule_names
14+
// let declaration_source = current_module.declaration_source(ctx.db);
15+
let module_definition_source_file =
16+
current_module.definition_source(ctx.db).file_id.original_file(ctx.db);
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+
)?;
2623

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()
24+
let mod_declaration_candidates = source_root
25+
.iter()
26+
.filter(|submodule_file| submodule_file != &module_definition_source_file)
27+
.filter_map(|submodule_file| {
28+
let submodule_path = source_root.path_for_file(&submodule_file)?;
29+
if submodule_path.parent()? == directory_to_look_for_submodules {
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())
3446
} else {
3547
None
3648
}
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<_>>();
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>>
49+
}
50+
_ => None,
51+
}
6352
})
64-
.unwrap_or_default();
65-
}
53+
.collect::<Vec<_>>();
54+
dbg!(mod_declaration_candidates);
6655

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-
}
56+
// TODO kb exlude existing children from the candidates
57+
let existing_children = current_module.children(ctx.db).collect::<Vec<_>>();
8458

85-
path
59+
Some(())
8660
}
8761

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> {
8967
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()? {
9170
("mod", Some("rs")) | ("lib", Some("rs")) | ("main", Some("rs")) => {
9271
Some(module_directory_path)
9372
}
@@ -109,5 +88,35 @@ fn get_directory_with_submodules(module_file_path: &VfsPath) -> Option<VfsPath>
10988
}
11089
}
11190
_ => 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+
}
112119
}
120+
121+
path
113122
}

0 commit comments

Comments
 (0)