Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide-assists/src/handlers/move_from_mod_rs.rs')
-rw-r--r--crates/ide-assists/src/handlers/move_from_mod_rs.rs130
1 files changed, 130 insertions, 0 deletions
diff --git a/crates/ide-assists/src/handlers/move_from_mod_rs.rs b/crates/ide-assists/src/handlers/move_from_mod_rs.rs
new file mode 100644
index 0000000000..b49c2e5da5
--- /dev/null
+++ b/crates/ide-assists/src/handlers/move_from_mod_rs.rs
@@ -0,0 +1,130 @@
+use ide_db::{
+ assists::{AssistId, AssistKind},
+ base_db::AnchoredPathBuf,
+};
+use syntax::{ast, AstNode};
+
+use crate::{
+ assist_context::{AssistContext, Assists},
+ utils::trimmed_text_range,
+};
+
+// Assist: move_from_mod_rs
+//
+// Moves xxx/mod.rs to xxx.rs.
+//
+// ```
+// //- /main.rs
+// mod a;
+// //- /a/mod.rs
+// $0fn t() {}$0
+// ```
+// ->
+// ```
+// fn t() {}
+// ```
+pub(crate) fn move_from_mod_rs(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
+ let source_file = ctx.find_node_at_offset::<ast::SourceFile>()?;
+ let module = ctx.sema.to_module_def(ctx.file_id())?;
+ // Enable this assist if the user select all "meaningful" content in the source file
+ let trimmed_selected_range = trimmed_text_range(&source_file, ctx.selection_trimmed());
+ let trimmed_file_range = trimmed_text_range(&source_file, source_file.syntax().text_range());
+ if !module.is_mod_rs(ctx.db()) {
+ cov_mark::hit!(not_mod_rs);
+ return None;
+ }
+ if trimmed_selected_range != trimmed_file_range {
+ cov_mark::hit!(not_all_selected);
+ return None;
+ }
+
+ let target = source_file.syntax().text_range();
+ let module_name = module.name(ctx.db())?.to_string();
+ let path = format!("../{}.rs", module_name);
+ let dst = AnchoredPathBuf { anchor: ctx.file_id(), path };
+ acc.add(
+ AssistId("move_from_mod_rs", AssistKind::Refactor),
+ format!("Convert {}/mod.rs to {}.rs", module_name, module_name),
+ target,
+ |builder| {
+ builder.move_file(ctx.file_id(), dst);
+ },
+ )
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::tests::{check_assist, check_assist_not_applicable};
+
+ use super::*;
+
+ #[test]
+ fn trivial() {
+ check_assist(
+ move_from_mod_rs,
+ r#"
+//- /main.rs
+mod a;
+//- /a/mod.rs
+$0fn t() {}
+$0"#,
+ r#"
+//- /a.rs
+fn t() {}
+"#,
+ );
+ }
+
+ #[test]
+ fn must_select_all_file() {
+ cov_mark::check!(not_all_selected);
+ check_assist_not_applicable(
+ move_from_mod_rs,
+ r#"
+//- /main.rs
+mod a;
+//- /a/mod.rs
+fn t() {}$0
+"#,
+ );
+ cov_mark::check!(not_all_selected);
+ check_assist_not_applicable(
+ move_from_mod_rs,
+ r#"
+//- /main.rs
+mod a;
+//- /a/mod.rs
+$0fn$0 t() {}
+"#,
+ );
+ }
+
+ #[test]
+ fn cannot_move_not_mod_rs() {
+ cov_mark::check!(not_mod_rs);
+ check_assist_not_applicable(
+ move_from_mod_rs,
+ r#"//- /main.rs
+mod a;
+//- /a.rs
+$0fn t() {}$0
+"#,
+ );
+ }
+
+ #[test]
+ fn cannot_downgrade_main_and_lib_rs() {
+ check_assist_not_applicable(
+ move_from_mod_rs,
+ r#"//- /main.rs
+$0fn t() {}$0
+"#,
+ );
+ check_assist_not_applicable(
+ move_from_mod_rs,
+ r#"//- /lib.rs
+$0fn t() {}$0
+"#,
+ );
+ }
+}