aboutsummaryrefslogtreecommitdiff
path: root/crates/assists/src/handlers
diff options
context:
space:
mode:
Diffstat (limited to 'crates/assists/src/handlers')
-rw-r--r--crates/assists/src/handlers/extract_module_to_file.rs170
1 files changed, 170 insertions, 0 deletions
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
index 000000000..5fc190fa6
--- /dev/null
+++ b/crates/assists/src/handlers/extract_module_to_file.rs
@@ -0,0 +1,170 @@
1use ast::edit::IndentLevel;
2use ide_db::base_db::{AnchoredPathBuf, SourceDatabaseExt};
3use syntax::{
4 ast::{self, edit::AstNodeEdit, NameOwner},
5 AstNode,
6};
7
8use crate::{AssistContext, AssistId, AssistKind, Assists};
9
10// Assist: extract_module_to_file
11//
12// This assist extract module to file.
13//
14// ```
15// mod foo {<|>
16// fn t() {}
17// }
18// ```
19// ->
20// ```
21// mod foo;
22// ```
23pub(crate) fn extract_module_to_file(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
24 let assist_id = AssistId("extract_module_to_file", AssistKind::RefactorExtract);
25 let assist_label = "Extract module to file";
26 let db = ctx.db();
27 let module_ast = ctx.find_node_at_offset::<ast::Module>()?;
28 let module_items = module_ast.item_list()?;
29 let dedent_module_items_text = module_items.dedent(IndentLevel(1)).to_string();
30 let module_name = module_ast.name()?;
31 let target = module_ast.syntax().text_range();
32 let anchor_file_id = ctx.frange.file_id;
33 let sr = db.file_source_root(anchor_file_id);
34 let sr = db.source_root(sr);
35 let file_path = sr.path_for_file(&anchor_file_id)?;
36 let (file_name, file_ext) = file_path.name_and_extension()?;
37 acc.add(assist_id, assist_label, target, |builder| {
38 builder.replace(target, format!("mod {};", module_name));
39 let path = if is_main_or_lib(file_name) {
40 format!("./{}.{}", module_name, file_ext.unwrap())
41 } else {
42 format!("./{}/{}.{}", file_name, module_name, file_ext.unwrap())
43 };
44 let dst = AnchoredPathBuf { anchor: anchor_file_id, path };
45 let contents = update_module_items_string(dedent_module_items_text);
46 builder.create_file(dst, contents);
47 })
48}
49fn is_main_or_lib(file_name: &str) -> bool {
50 file_name == "main".to_string() || file_name == "lib".to_string()
51}
52fn update_module_items_string(items_str: String) -> String {
53 let mut items_string_lines: Vec<&str> = items_str.lines().collect();
54 items_string_lines.pop(); // Delete last line
55 items_string_lines.reverse();
56 items_string_lines.pop(); // Delete first line
57 items_string_lines.reverse();
58
59 let string = items_string_lines.join("\n");
60 format!("{}", string)
61}
62
63#[cfg(test)]
64mod tests {
65 use crate::tests::check_assist;
66
67 use super::*;
68
69 #[test]
70 fn extract_module_to_file_with_basic_module() {
71 check_assist(
72 extract_module_to_file,
73 r#"
74//- /foo.rs crate:foo
75mod tests {<|>
76 #[test] fn t() {}
77}
78"#,
79 r#"
80//- /foo.rs
81mod tests;
82//- /foo/tests.rs
83#[test] fn t() {}"#,
84 )
85 }
86
87 #[test]
88 fn extract_module_to_file_with_file_path() {
89 check_assist(
90 extract_module_to_file,
91 r#"
92//- /src/foo.rs crate:foo
93mod bar {<|>
94 fn f() {
95
96 }
97}
98fn main() {
99 println!("Hello, world!");
100}
101"#,
102 r#"
103//- /src/foo.rs
104mod bar;
105fn main() {
106 println!("Hello, world!");
107}
108//- /src/foo/bar.rs
109fn f() {
110
111}"#,
112 )
113 }
114
115 #[test]
116 fn extract_module_to_file_with_main_filw() {
117 check_assist(
118 extract_module_to_file,
119 r#"
120//- /main.rs
121mod foo {<|>
122 fn f() {
123
124 }
125}
126fn main() {
127 println!("Hello, world!");
128}
129"#,
130 r#"
131//- /main.rs
132mod foo;
133fn main() {
134 println!("Hello, world!");
135}
136//- /foo.rs
137fn f() {
138
139}"#,
140 )
141 }
142
143 #[test]
144 fn extract_module_to_file_with_lib_file() {
145 check_assist(
146 extract_module_to_file,
147 r#"
148//- /lib.rs
149mod foo {<|>
150 fn f() {
151
152 }
153}
154fn main() {
155 println!("Hello, world!");
156}
157"#,
158 r#"
159//- /lib.rs
160mod foo;
161fn main() {
162 println!("Hello, world!");
163}
164//- /foo.rs
165fn f() {
166
167}"#,
168 )
169 }
170}