]> git.lizzy.rs Git - rust.git/commitdiff
Properly handle nested submodules in the same file
authorKirill Bulatov <mail4score@gmail.com>
Mon, 7 Sep 2020 18:39:23 +0000 (21:39 +0300)
committerKirill Bulatov <mail4score@gmail.com>
Wed, 9 Sep 2020 22:42:20 +0000 (01:42 +0300)
crates/ide/src/completion/complete_mod.rs

index da3d93bada8fba954a16c485a0150674d080e4e0..def8b8968dccdf332944e003cca0e23ab8b28dcd 100644 (file)
@@ -7,87 +7,66 @@
 use super::{completion_context::CompletionContext, completion_item::Completions};
 
 /// Complete mod declaration, i.e. `mod <|> ;`
-pub(super) fn complete_mod(acc: &mut Completions, ctx: &CompletionContext) {
-    let module_names_for_import = ctx
-        .scope
-        .module()
-        .and_then(|current_module| {
-            let module_path = path_to_closest_containing_module_file(current_module, ctx.db);
-            // TODO kb filter out declarations in possible_sudmobule_names
-            // let declaration_source = current_module.declaration_source(ctx.db);
-            let module_definition_source_file =
-                current_module.definition_source(ctx.db).file_id.original_file(ctx.db);
+pub(super) fn complete_mod(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
+    let current_module = ctx.scope.module()?;
 
-            let source_root_id = ctx.db.file_source_root(module_definition_source_file);
-            let source_root = ctx.db.source_root(source_root_id);
-            let directory_to_look_for_submodules = source_root
-                .path_for_file(&module_definition_source_file)
-                .and_then(|module_file_path| get_directory_with_submodules(module_file_path))?;
+    // TODO kb filter out declarations in possible_sudmobule_names
+    // let declaration_source = current_module.declaration_source(ctx.db);
+    let module_definition_source_file =
+        current_module.definition_source(ctx.db).file_id.original_file(ctx.db);
+    let source_root = ctx.db.source_root(ctx.db.file_source_root(module_definition_source_file));
+    let directory_to_look_for_submodules = directory_to_look_for_submodules(
+        current_module,
+        ctx.db,
+        source_root.path_for_file(&module_definition_source_file)?,
+    )?;
 
-            let mod_declaration_candidates = source_root
-                .iter()
-                .filter(|submodule_file| submodule_file != &module_definition_source_file)
-                .filter_map(|submodule_file| {
-                    let submodule_path = source_root.path_for_file(&submodule_file)?;
-                    if submodule_path.parent()? == directory_to_look_for_submodules {
-                        submodule_path.file_name_and_extension()
+    let mod_declaration_candidates = source_root
+        .iter()
+        .filter(|submodule_file| submodule_file != &module_definition_source_file)
+        .filter_map(|submodule_file| {
+            let submodule_path = source_root.path_for_file(&submodule_file)?;
+            if submodule_path.parent()? == directory_to_look_for_submodules {
+                submodule_path.file_name_and_extension()
+            } else {
+                None
+            }
+        })
+        .filter_map(|file_name_and_extension| {
+            match file_name_and_extension {
+                // TODO kb in src/bin when a module is included into another,
+                // the included file gets "moved" into a directory below and now cannot add any other modules
+                ("mod", Some("rs")) | ("lib", Some("rs")) | ("main", Some("rs")) => None,
+                (file_name, Some("rs")) => Some(file_name.to_owned()),
+                (subdirectory_name, None) => {
+                    let mod_rs_path =
+                        directory_to_look_for_submodules.join(subdirectory_name)?.join("mod.rs")?;
+                    if source_root.file_for_path(&mod_rs_path).is_some() {
+                        Some(subdirectory_name.to_owned())
                     } else {
                         None
                     }
-                })
-                .filter_map(|file_name_and_extension| {
-                    match file_name_and_extension {
-                        // TODO kb wrong resolution for nested non-file modules (mod tests { mod <|> })
-                        // TODO kb in src/bin when a module is included into another,
-                        // the included file gets "moved" into a directory below and now cannot add any other modules
-                        ("mod", Some("rs")) | ("lib", Some("rs")) | ("main", Some("rs")) => None,
-                        (file_name, Some("rs")) => Some(file_name.to_owned()),
-                        (subdirectory_name, None) => {
-                            let mod_rs_path = directory_to_look_for_submodules
-                                .join(subdirectory_name)?
-                                .join("mod.rs")?;
-                            if source_root.file_for_path(&mod_rs_path).is_some() {
-                                Some(subdirectory_name.to_owned())
-                            } else {
-                                None
-                            }
-                        }
-                        _ => None,
-                    }
-                })
-                .collect::<Vec<_>>();
-            dbg!(mod_declaration_candidates);
-            // TODO kb exlude existing children from the candidates
-            let existing_children = current_module.children(ctx.db).collect::<Vec<_>>();
-            None::<Vec<String>>
+                }
+                _ => None,
+            }
         })
-        .unwrap_or_default();
-}
+        .collect::<Vec<_>>();
+    dbg!(mod_declaration_candidates);
 
-fn path_to_closest_containing_module_file(
-    current_module: Module,
-    db: &RootDatabase,
-) -> Vec<Module> {
-    let mut path = Vec::new();
-
-    let mut current_module = Some(current_module);
-    while let Some(ModuleSource::Module(_)) =
-        current_module.map(|module| module.definition_source(db).value)
-    {
-        if let Some(module) = current_module {
-            path.insert(0, module);
-            current_module = module.parent(db);
-        } else {
-            current_module = None;
-        }
-    }
+    // TODO kb exlude existing children from the candidates
+    let existing_children = current_module.children(ctx.db).collect::<Vec<_>>();
 
-    path
+    Some(())
 }
 
-fn get_directory_with_submodules(module_file_path: &VfsPath) -> Option<VfsPath> {
+fn directory_to_look_for_submodules(
+    module: Module,
+    db: &RootDatabase,
+    module_file_path: &VfsPath,
+) -> Option<VfsPath> {
     let module_directory_path = module_file_path.parent()?;
-    match module_file_path.file_name_and_extension()? {
+
+    let base_directory = match module_file_path.file_name_and_extension()? {
         ("mod", Some("rs")) | ("lib", Some("rs")) | ("main", Some("rs")) => {
             Some(module_directory_path)
         }
@@ -109,5 +88,35 @@ fn get_directory_with_submodules(module_file_path: &VfsPath) -> Option<VfsPath>
             }
         }
         _ => None,
+    }?;
+
+    let mut resulting_path = base_directory;
+    for module in module_chain_to_containing_module_file(module, db) {
+        if let Some(name) = module.name(db) {
+            resulting_path = resulting_path.join(&name.to_string())?;
+        }
+    }
+
+    Some(resulting_path)
+}
+
+fn module_chain_to_containing_module_file(
+    current_module: Module,
+    db: &RootDatabase,
+) -> Vec<Module> {
+    let mut path = Vec::new();
+
+    let mut current_module = Some(current_module);
+    while let Some(ModuleSource::Module(_)) =
+        current_module.map(|module| module.definition_source(db).value)
+    {
+        if let Some(module) = current_module {
+            path.insert(0, module);
+            current_module = module.parent(db);
+        } else {
+            current_module = None;
+        }
     }
+
+    path
 }