diff options
author | Aleksey Kladov <[email protected]> | 2021-01-06 13:24:47 +0000 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2021-01-06 13:32:45 +0000 |
commit | 25edc3c60a8fe9a01b1ff7b6a20ceb83d78e2965 (patch) | |
tree | 4818fcd60f5f4110037faac367744c925d5f5075 /crates/assists/src/handlers/move_module_to_file.rs | |
parent | ed732e86eb88393cdec471b263303adea6ffcb73 (diff) |
Better target for move module
Diffstat (limited to 'crates/assists/src/handlers/move_module_to_file.rs')
-rw-r--r-- | crates/assists/src/handlers/move_module_to_file.rs | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/crates/assists/src/handlers/move_module_to_file.rs b/crates/assists/src/handlers/move_module_to_file.rs new file mode 100644 index 000000000..165faaf61 --- /dev/null +++ b/crates/assists/src/handlers/move_module_to_file.rs | |||
@@ -0,0 +1,145 @@ | |||
1 | use ast::edit::IndentLevel; | ||
2 | use ide_db::base_db::AnchoredPathBuf; | ||
3 | use syntax::{ | ||
4 | ast::{self, edit::AstNodeEdit, NameOwner}, | ||
5 | AstNode, TextRange, | ||
6 | }; | ||
7 | use test_utils::mark; | ||
8 | |||
9 | use crate::{AssistContext, AssistId, AssistKind, Assists}; | ||
10 | |||
11 | // Assist: move_module_to_file | ||
12 | // | ||
13 | // Moves inline module's contents to a separate file. | ||
14 | // | ||
15 | // ``` | ||
16 | // mod <|>foo { | ||
17 | // fn t() {} | ||
18 | // } | ||
19 | // ``` | ||
20 | // -> | ||
21 | // ``` | ||
22 | // mod foo; | ||
23 | // ``` | ||
24 | pub(crate) fn move_module_to_file(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | ||
25 | let module_ast = ctx.find_node_at_offset::<ast::Module>()?; | ||
26 | let module_items = module_ast.item_list()?; | ||
27 | |||
28 | let l_curly_offset = module_items.syntax().text_range().start(); | ||
29 | if l_curly_offset <= ctx.offset() { | ||
30 | mark::hit!(available_before_curly); | ||
31 | return None; | ||
32 | } | ||
33 | let target = TextRange::new(module_ast.syntax().text_range().start(), l_curly_offset); | ||
34 | |||
35 | let module_name = module_ast.name()?; | ||
36 | |||
37 | let module_def = ctx.sema.to_def(&module_ast)?; | ||
38 | let parent_module = module_def.parent(ctx.db())?; | ||
39 | |||
40 | acc.add( | ||
41 | AssistId("move_module_to_file", AssistKind::RefactorExtract), | ||
42 | "Extract module to file", | ||
43 | target, | ||
44 | |builder| { | ||
45 | let path = { | ||
46 | let dir = match parent_module.name(ctx.db()) { | ||
47 | Some(name) if !parent_module.is_mod_rs(ctx.db()) => format!("{}/", name), | ||
48 | _ => String::new(), | ||
49 | }; | ||
50 | format!("./{}{}.rs", dir, module_name) | ||
51 | }; | ||
52 | let contents = { | ||
53 | let items = module_items.dedent(IndentLevel(1)).to_string(); | ||
54 | let mut items = | ||
55 | items.trim_start_matches('{').trim_end_matches('}').trim().to_string(); | ||
56 | if !items.is_empty() { | ||
57 | items.push('\n'); | ||
58 | } | ||
59 | items | ||
60 | }; | ||
61 | |||
62 | builder.replace(module_ast.syntax().text_range(), format!("mod {};", module_name)); | ||
63 | |||
64 | let dst = AnchoredPathBuf { anchor: ctx.frange.file_id, path }; | ||
65 | builder.create_file(dst, contents); | ||
66 | }, | ||
67 | ) | ||
68 | } | ||
69 | |||
70 | #[cfg(test)] | ||
71 | mod tests { | ||
72 | use crate::tests::{check_assist, check_assist_not_applicable}; | ||
73 | |||
74 | use super::*; | ||
75 | |||
76 | #[test] | ||
77 | fn extract_from_root() { | ||
78 | check_assist( | ||
79 | move_module_to_file, | ||
80 | r#" | ||
81 | mod <|>tests { | ||
82 | #[test] fn t() {} | ||
83 | } | ||
84 | "#, | ||
85 | r#" | ||
86 | //- /main.rs | ||
87 | mod tests; | ||
88 | //- /tests.rs | ||
89 | #[test] fn t() {} | ||
90 | "#, | ||
91 | ); | ||
92 | } | ||
93 | |||
94 | #[test] | ||
95 | fn extract_from_submodule() { | ||
96 | check_assist( | ||
97 | move_module_to_file, | ||
98 | r#" | ||
99 | //- /main.rs | ||
100 | mod submod; | ||
101 | //- /submod.rs | ||
102 | <|>mod inner { | ||
103 | fn f() {} | ||
104 | } | ||
105 | fn g() {} | ||
106 | "#, | ||
107 | r#" | ||
108 | //- /submod.rs | ||
109 | mod inner; | ||
110 | fn g() {} | ||
111 | //- /submod/inner.rs | ||
112 | fn f() {} | ||
113 | "#, | ||
114 | ); | ||
115 | } | ||
116 | |||
117 | #[test] | ||
118 | fn extract_from_mod_rs() { | ||
119 | check_assist( | ||
120 | move_module_to_file, | ||
121 | r#" | ||
122 | //- /main.rs | ||
123 | mod submodule; | ||
124 | //- /submodule/mod.rs | ||
125 | mod inner<|> { | ||
126 | fn f() {} | ||
127 | } | ||
128 | fn g() {} | ||
129 | "#, | ||
130 | r#" | ||
131 | //- /submodule/mod.rs | ||
132 | mod inner; | ||
133 | fn g() {} | ||
134 | //- /submodule/inner.rs | ||
135 | fn f() {} | ||
136 | "#, | ||
137 | ); | ||
138 | } | ||
139 | |||
140 | #[test] | ||
141 | fn available_before_curly() { | ||
142 | mark::check!(available_before_curly); | ||
143 | check_assist_not_applicable(move_module_to_file, r#"mod m { <|> }"#); | ||
144 | } | ||
145 | } | ||