Unnamed repository; edit this file 'description' to name the repository.
Add promote_mod_file assist
longfangsong 2021-09-12
parent d270679 · commit fede1a3
-rw-r--r--crates/ide_assists/src/assist_context.rs4
-rw-r--r--crates/ide_assists/src/handlers/promote_mod_file.rs148
-rw-r--r--crates/ide_assists/src/lib.rs2
-rw-r--r--crates/ide_assists/src/tests.rs23
4 files changed, 167 insertions, 10 deletions
diff --git a/crates/ide_assists/src/assist_context.rs b/crates/ide_assists/src/assist_context.rs
index 0244f5fb29..11e19304f1 100644
--- a/crates/ide_assists/src/assist_context.rs
+++ b/crates/ide_assists/src/assist_context.rs
@@ -294,6 +294,10 @@ impl AssistBuilder {
let file_system_edit = FileSystemEdit::CreateFile { dst, initial_contents: content.into() };
self.source_change.push_file_system_edit(file_system_edit);
}
+ pub(crate) fn move_file(&mut self, src: FileId, dst: AnchoredPathBuf) {
+ let file_system_edit = FileSystemEdit::MoveFile { src, dst };
+ self.source_change.push_file_system_edit(file_system_edit);
+ }
fn finish(mut self) -> SourceChange {
self.commit();
diff --git a/crates/ide_assists/src/handlers/promote_mod_file.rs b/crates/ide_assists/src/handlers/promote_mod_file.rs
new file mode 100644
index 0000000000..c5c37def07
--- /dev/null
+++ b/crates/ide_assists/src/handlers/promote_mod_file.rs
@@ -0,0 +1,148 @@
+use ide_db::{
+ assists::{AssistId, AssistKind},
+ base_db::AnchoredPathBuf,
+};
+use syntax::{
+ ast::{self},
+ AstNode, TextRange,
+};
+
+use crate::assist_context::{AssistContext, Assists};
+
+pub(crate) fn promote_mod_file(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
+ let source_file = ctx.find_node_at_offset::<ast::SourceFile>()?;
+ let module = ctx.sema.to_module_def(ctx.frange.file_id)?;
+ if module.is_mod_rs(ctx.db()) {
+ return None;
+ }
+ let target = TextRange::new(
+ source_file.syntax().text_range().start(),
+ source_file.syntax().text_range().end(),
+ );
+ let path = format!("./{}/mod.rs", module.name(ctx.db())?.to_string());
+ let dst = AnchoredPathBuf { anchor: ctx.frange.file_id, path };
+ acc.add(
+ AssistId("promote_mod_file", AssistKind::Refactor),
+ "Promote Module to directory",
+ target,
+ |builder| {
+ builder.move_file(ctx.frange.file_id, dst);
+ },
+ )
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::tests::{check_assist, check_assist_not_applicable};
+
+ use super::*;
+
+ #[test]
+ fn trivial() {
+ check_assist(
+ promote_mod_file,
+ r#"
+//- /main.rs
+mod a;
+//- /a.rs
+$0fn t() {}
+"#,
+ r#"
+//- /a/mod.rs
+fn t() {}
+"#,
+ );
+ }
+
+ #[test]
+ fn cursor_can_be_putted_anywhere() {
+ check_assist(
+ promote_mod_file,
+ r#"
+//- /main.rs
+mod a;
+//- /a.rs
+fn t() {}$0
+"#,
+ r#"
+//- /a/mod.rs
+fn t() {}
+"#,
+ );
+ check_assist(
+ promote_mod_file,
+ r#"
+//- /main.rs
+mod a;
+//- /a.rs
+fn t()$0 {}
+"#,
+ r#"
+//- /a/mod.rs
+fn t() {}
+"#,
+ );
+ check_assist(
+ promote_mod_file,
+ r#"
+//- /main.rs
+mod a;
+//- /a.rs
+fn t($0) {}
+"#,
+ r#"
+//- /a/mod.rs
+fn t() {}
+"#,
+ );
+ }
+
+ #[test]
+ fn cannot_promote_mod_rs() {
+ check_assist_not_applicable(
+ promote_mod_file,
+ r#"//- /main.rs
+mod a;
+//- /a/mod.rs
+$0fn t() {}
+"#,
+ );
+ }
+
+ #[test]
+ fn cannot_promote_main_and_lib_rs() {
+ check_assist_not_applicable(
+ promote_mod_file,
+ r#"//- /main.rs
+$0fn t() {}
+"#,
+ );
+ check_assist_not_applicable(
+ promote_mod_file,
+ r#"//- /lib.rs
+$0fn t() {}
+"#,
+ );
+ }
+
+ #[test]
+ fn works_in_mod() {
+ // note: /a/b.rs remains untouched
+ check_assist(
+ promote_mod_file,
+ r#"//- /main.rs
+mod a;
+//- /a.rs
+mod b;
+$0fn t() {}
+//- /a/b.rs
+fn t1() {}
+"#,
+ r#"
+//- /a/mod.rs
+mod b;
+fn t() {}
+"#,
+ );
+ }
+}
diff --git a/crates/ide_assists/src/lib.rs b/crates/ide_assists/src/lib.rs
index 7c074a4f63..57007691b5 100644
--- a/crates/ide_assists/src/lib.rs
+++ b/crates/ide_assists/src/lib.rs
@@ -96,6 +96,7 @@ mod handlers {
mod move_bounds;
mod move_guard;
mod move_module_to_file;
+ mod promote_mod_file;
mod pull_assignment_up;
mod qualify_path;
mod raw_string;
@@ -167,6 +168,7 @@ mod handlers {
move_guard::move_arm_cond_to_match_guard,
move_guard::move_guard_to_arm_body,
move_module_to_file::move_module_to_file,
+ promote_mod_file::promote_mod_file,
pull_assignment_up::pull_assignment_up,
qualify_path::qualify_path,
raw_string::add_hash,
diff --git a/crates/ide_assists/src/tests.rs b/crates/ide_assists/src/tests.rs
index 5cd3642ce0..e211b09987 100644
--- a/crates/ide_assists/src/tests.rs
+++ b/crates/ide_assists/src/tests.rs
@@ -142,7 +142,6 @@ fn check(handler: Handler, before: &str, expected: ExpectedResult, assist_label:
(Some(assist), ExpectedResult::After(after)) => {
let source_change =
assist.source_change.expect("Assist did not contain any source changes");
- assert!(!source_change.source_file_edits.is_empty());
let skip_header = source_change.source_file_edits.len() == 1
&& source_change.file_system_edits.len() == 0;
@@ -160,15 +159,19 @@ fn check(handler: Handler, before: &str, expected: ExpectedResult, assist_label:
}
for file_system_edit in source_change.file_system_edits {
- if let FileSystemEdit::CreateFile { dst, initial_contents } = file_system_edit {
- let sr = db.file_source_root(dst.anchor);
- let sr = db.source_root(sr);
- let mut base = sr.path_for_file(&dst.anchor).unwrap().clone();
- base.pop();
- let created_file_path = format!("{}{}", base.to_string(), &dst.path[1..]);
- format_to!(buf, "//- {}\n", created_file_path);
- buf.push_str(&initial_contents);
- }
+ let (dst, contents) = match file_system_edit {
+ FileSystemEdit::CreateFile { dst, initial_contents } => (dst, initial_contents),
+ FileSystemEdit::MoveFile { src, dst } => {
+ (dst, db.file_text(src).as_ref().to_owned())
+ }
+ };
+ let sr = db.file_source_root(dst.anchor);
+ let sr = db.source_root(sr);
+ let mut base = sr.path_for_file(&dst.anchor).unwrap().clone();
+ base.pop();
+ let created_file_path = format!("{}{}", base.to_string(), &dst.path[1..]);
+ format_to!(buf, "//- {}\n", created_file_path);
+ buf.push_str(&contents);
}
assert_eq_text!(after, &buf);