]> git.lizzy.rs Git - rust.git/commitdiff
Add extract_module_to_file assist
authorDaiki Ihara <sasurau4@gmail.com>
Mon, 7 Dec 2020 16:17:54 +0000 (01:17 +0900)
committerDaiki Ihara <sasurau4@gmail.com>
Mon, 21 Dec 2020 06:55:40 +0000 (15:55 +0900)
crates/assists/src/handlers/extract_module_to_file.rs [new file with mode: 0644]
crates/assists/src/lib.rs
crates/assists/src/tests/generated.rs

diff --git a/crates/assists/src/handlers/extract_module_to_file.rs b/crates/assists/src/handlers/extract_module_to_file.rs
new file mode 100644 (file)
index 0000000..5fc190f
--- /dev/null
@@ -0,0 +1,170 @@
+use ast::edit::IndentLevel;
+use ide_db::base_db::{AnchoredPathBuf, SourceDatabaseExt};
+use syntax::{
+    ast::{self, edit::AstNodeEdit, NameOwner},
+    AstNode,
+};
+
+use crate::{AssistContext, AssistId, AssistKind, Assists};
+
+// Assist: extract_module_to_file
+//
+// This assist extract module to file.
+//
+// ```
+// mod foo {<|>
+//     fn t() {}
+// }
+// ```
+// ->
+// ```
+// mod foo;
+// ```
+pub(crate) fn extract_module_to_file(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
+    let assist_id = AssistId("extract_module_to_file", AssistKind::RefactorExtract);
+    let assist_label = "Extract module to file";
+    let db = ctx.db();
+    let module_ast = ctx.find_node_at_offset::<ast::Module>()?;
+    let module_items = module_ast.item_list()?;
+    let dedent_module_items_text = module_items.dedent(IndentLevel(1)).to_string();
+    let module_name = module_ast.name()?;
+    let target = module_ast.syntax().text_range();
+    let anchor_file_id = ctx.frange.file_id;
+    let sr = db.file_source_root(anchor_file_id);
+    let sr = db.source_root(sr);
+    let file_path = sr.path_for_file(&anchor_file_id)?;
+    let (file_name, file_ext) = file_path.name_and_extension()?;
+    acc.add(assist_id, assist_label, target, |builder| {
+        builder.replace(target, format!("mod {};", module_name));
+        let path = if is_main_or_lib(file_name) {
+            format!("./{}.{}", module_name, file_ext.unwrap())
+        } else {
+            format!("./{}/{}.{}", file_name, module_name, file_ext.unwrap())
+        };
+        let dst = AnchoredPathBuf { anchor: anchor_file_id, path };
+        let contents = update_module_items_string(dedent_module_items_text);
+        builder.create_file(dst, contents);
+    })
+}
+fn is_main_or_lib(file_name: &str) -> bool {
+    file_name == "main".to_string() || file_name == "lib".to_string()
+}
+fn update_module_items_string(items_str: String) -> String {
+    let mut items_string_lines: Vec<&str> = items_str.lines().collect();
+    items_string_lines.pop(); // Delete last line
+    items_string_lines.reverse();
+    items_string_lines.pop(); // Delete first line
+    items_string_lines.reverse();
+
+    let string = items_string_lines.join("\n");
+    format!("{}", string)
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::tests::check_assist;
+
+    use super::*;
+
+    #[test]
+    fn extract_module_to_file_with_basic_module() {
+        check_assist(
+            extract_module_to_file,
+            r#"
+//- /foo.rs crate:foo
+mod tests {<|>
+    #[test] fn t() {}
+}
+"#,
+            r#"
+//- /foo.rs
+mod tests;
+//- /foo/tests.rs
+#[test] fn t() {}"#,
+        )
+    }
+
+    #[test]
+    fn extract_module_to_file_with_file_path() {
+        check_assist(
+            extract_module_to_file,
+            r#"
+//- /src/foo.rs crate:foo
+mod bar {<|>
+    fn f() {
+
+    }
+}
+fn main() {
+    println!("Hello, world!");
+}
+"#,
+            r#"
+//- /src/foo.rs
+mod bar;
+fn main() {
+    println!("Hello, world!");
+}
+//- /src/foo/bar.rs
+fn f() {
+
+}"#,
+        )
+    }
+
+    #[test]
+    fn extract_module_to_file_with_main_filw() {
+        check_assist(
+            extract_module_to_file,
+            r#"
+//- /main.rs
+mod foo {<|>
+    fn f() {
+
+    }
+}
+fn main() {
+    println!("Hello, world!");
+}
+"#,
+            r#"
+//- /main.rs
+mod foo;
+fn main() {
+    println!("Hello, world!");
+}
+//- /foo.rs
+fn f() {
+
+}"#,
+        )
+    }
+
+    #[test]
+    fn extract_module_to_file_with_lib_file() {
+        check_assist(
+            extract_module_to_file,
+            r#"
+//- /lib.rs
+mod foo {<|>
+    fn f() {
+
+    }
+}
+fn main() {
+    println!("Hello, world!");
+}
+"#,
+            r#"
+//- /lib.rs
+mod foo;
+fn main() {
+    println!("Hello, world!");
+}
+//- /foo.rs
+fn f() {
+
+}"#,
+        )
+    }
+}
index 6e736ccb38906cecee990a46503ce3c83a392bdb..6b89b2d044397385732fa959f415666919253907 100644 (file)
@@ -129,6 +129,7 @@ mod handlers {
     mod convert_integer_literal;
     mod early_return;
     mod expand_glob_import;
+    mod extract_module_to_file;
     mod extract_struct_from_enum_variant;
     mod extract_variable;
     mod fill_match_arms;
@@ -179,6 +180,7 @@ pub(crate) fn all() -> &'static [Handler] {
             convert_integer_literal::convert_integer_literal,
             early_return::convert_to_guarded_return,
             expand_glob_import::expand_glob_import,
+            extract_module_to_file::extract_module_to_file,
             extract_struct_from_enum_variant::extract_struct_from_enum_variant,
             extract_variable::extract_variable,
             fill_match_arms::fill_match_arms,
index cc7c4a3433a327c27a17ece7bb71303d54a2027c..e9093ec536122f034189dbc1c7faadbdc3686317 100644 (file)
@@ -235,6 +235,21 @@ fn qux(bar: Bar, baz: Baz) {}
     )
 }
 
+#[test]
+fn doctest_extract_module_to_file() {
+    check_doc_test(
+        "extract_module_to_file",
+        r#####"
+mod foo {<|>
+    fn t() {}
+}
+"#####,
+        r#####"
+mod foo;
+"#####,
+    )
+}
+
 #[test]
 fn doctest_extract_struct_from_enum_variant() {
     check_doc_test(