Skip to content

Commit 199c01d

Browse files
committed
Auto merge of #17757 - alibektas:toggle_macro_delimiters, r=Veykril
assist: Add new assist toggle_macro_delimiter Closes #17716
2 parents 2dce250 + c9a3b02 commit 199c01d

File tree

3 files changed

+279
-0
lines changed

3 files changed

+279
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
1+
use ide_db::assists::{AssistId, AssistKind};
2+
use syntax::{
3+
ast::{self, make},
4+
ted, AstNode, T,
5+
};
6+
7+
use crate::{AssistContext, Assists};
8+
9+
// Assist: toggle_macro_delimiter
10+
//
11+
// Change macro delimiters in the order of `( -> { -> [ -> (`.
12+
//
13+
// ```
14+
// macro_rules! sth {
15+
// () => {};
16+
// }
17+
//
18+
// sth!$0( );
19+
// ```
20+
// ->
21+
// ```
22+
// macro_rules! sth {
23+
// () => {};
24+
// }
25+
//
26+
// sth!{ }
27+
// ```
28+
pub(crate) fn toggle_macro_delimiter(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
29+
#[derive(Debug)]
30+
enum MacroDelims {
31+
LPar,
32+
RPar,
33+
LBra,
34+
RBra,
35+
LCur,
36+
RCur,
37+
}
38+
39+
let makro = ctx.find_node_at_offset::<ast::MacroCall>()?.clone_for_update();
40+
let makro_text_range = makro.syntax().text_range();
41+
42+
let cursor_offset = ctx.offset();
43+
let semicolon = makro.semicolon_token();
44+
let token_tree = makro.token_tree()?;
45+
46+
let ltoken = token_tree.left_delimiter_token()?;
47+
let rtoken = token_tree.right_delimiter_token()?;
48+
49+
if !ltoken.text_range().contains(cursor_offset) && !rtoken.text_range().contains(cursor_offset)
50+
{
51+
return None;
52+
}
53+
54+
let token = match ltoken.kind() {
55+
T!['{'] => MacroDelims::LCur,
56+
T!['('] => MacroDelims::LPar,
57+
T!['['] => MacroDelims::LBra,
58+
T!['}'] => MacroDelims::RBra,
59+
T![')'] => MacroDelims::RPar,
60+
T!['}'] => MacroDelims::RCur,
61+
_ => return None,
62+
};
63+
64+
acc.add(
65+
AssistId("toggle_macro_delimiter", AssistKind::Refactor),
66+
match token {
67+
MacroDelims::LPar => "Replace delimiters with braces",
68+
MacroDelims::RPar => "Replace delimiters with braces",
69+
MacroDelims::LBra => "Replace delimiters with parentheses",
70+
MacroDelims::RBra => "Replace delimiters with parentheses",
71+
MacroDelims::LCur => "Replace delimiters with brackets",
72+
MacroDelims::RCur => "Replace delimiters with brackets",
73+
},
74+
token_tree.syntax().text_range(),
75+
|builder| {
76+
match token {
77+
MacroDelims::LPar | MacroDelims::RPar => {
78+
ted::replace(ltoken, make::token(T!['{']));
79+
ted::replace(rtoken, make::token(T!['}']));
80+
if let Some(sc) = semicolon {
81+
ted::remove(sc);
82+
}
83+
}
84+
MacroDelims::LBra | MacroDelims::RBra => {
85+
ted::replace(ltoken, make::token(T!['(']));
86+
ted::replace(rtoken, make::token(T![')']));
87+
}
88+
MacroDelims::LCur | MacroDelims::RCur => {
89+
ted::replace(ltoken, make::token(T!['[']));
90+
ted::replace(rtoken, make::token(T![']']));
91+
}
92+
}
93+
builder.replace(makro_text_range, makro.syntax().text());
94+
},
95+
)
96+
}
97+
98+
#[cfg(test)]
99+
mod tests {
100+
use crate::tests::{check_assist, check_assist_not_applicable};
101+
102+
use super::*;
103+
104+
#[test]
105+
fn test_par() {
106+
check_assist(
107+
toggle_macro_delimiter,
108+
r#"
109+
macro_rules! sth {
110+
() => {};
111+
}
112+
113+
sth!$0( );
114+
"#,
115+
r#"
116+
macro_rules! sth {
117+
() => {};
118+
}
119+
120+
sth!{ }
121+
"#,
122+
)
123+
}
124+
125+
#[test]
126+
fn test_braces() {
127+
check_assist(
128+
toggle_macro_delimiter,
129+
r#"
130+
macro_rules! sth {
131+
() => {};
132+
}
133+
134+
sth!$0{ };
135+
"#,
136+
r#"
137+
macro_rules! sth {
138+
() => {};
139+
}
140+
141+
sth![ ];
142+
"#,
143+
)
144+
}
145+
146+
#[test]
147+
fn test_brackets() {
148+
check_assist(
149+
toggle_macro_delimiter,
150+
r#"
151+
macro_rules! sth {
152+
() => {};
153+
}
154+
155+
sth!$0[ ];
156+
"#,
157+
r#"
158+
macro_rules! sth {
159+
() => {};
160+
}
161+
162+
sth!( );
163+
"#,
164+
)
165+
}
166+
167+
#[test]
168+
fn test_indent() {
169+
check_assist(
170+
toggle_macro_delimiter,
171+
r#"
172+
mod abc {
173+
macro_rules! sth {
174+
() => {};
175+
}
176+
177+
sth!$0{ };
178+
}
179+
"#,
180+
r#"
181+
mod abc {
182+
macro_rules! sth {
183+
() => {};
184+
}
185+
186+
sth![ ];
187+
}
188+
"#,
189+
)
190+
}
191+
192+
#[test]
193+
fn test_unrelated_par() {
194+
check_assist_not_applicable(
195+
toggle_macro_delimiter,
196+
r#"
197+
macro_rules! prt {
198+
($e:expr) => {{
199+
println!("{}", stringify!{$e});
200+
}};
201+
}
202+
203+
prt!(($03 + 5));
204+
205+
"#,
206+
)
207+
}
208+
209+
#[test]
210+
fn test_longer_macros() {
211+
check_assist(
212+
toggle_macro_delimiter,
213+
r#"
214+
macro_rules! prt {
215+
($e:expr) => {{
216+
println!("{}", stringify!{$e});
217+
}};
218+
}
219+
220+
prt!$0((3 + 5));
221+
"#,
222+
r#"
223+
macro_rules! prt {
224+
($e:expr) => {{
225+
println!("{}", stringify!{$e});
226+
}};
227+
}
228+
229+
prt!{(3 + 5)}
230+
"#,
231+
)
232+
}
233+
234+
// FIXME @alibektas : Inner macro_call is not seen as such. So this doesn't work.
235+
#[test]
236+
fn test_nested_macros() {
237+
check_assist_not_applicable(
238+
toggle_macro_delimiter,
239+
r#"
240+
macro_rules! prt {
241+
($e:expr) => {{
242+
println!("{}", stringify!{$e});
243+
}};
244+
}
245+
246+
macro_rules! abc {
247+
($e:expr) => {{
248+
println!("{}", stringify!{$e});
249+
}};
250+
}
251+
252+
prt!{abc!($03 + 5)};
253+
"#,
254+
)
255+
}
256+
}

Diff for: src/tools/rust-analyzer/crates/ide-assists/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@ mod handlers {
213213
mod term_search;
214214
mod toggle_async_sugar;
215215
mod toggle_ignore;
216+
mod toggle_macro_delimiter;
216217
mod unmerge_match_arm;
217218
mod unmerge_use;
218219
mod unnecessary_async;
@@ -343,6 +344,7 @@ mod handlers {
343344
split_import::split_import,
344345
term_search::term_search,
345346
toggle_ignore::toggle_ignore,
347+
toggle_macro_delimiter::toggle_macro_delimiter,
346348
unmerge_match_arm::unmerge_match_arm,
347349
unmerge_use::unmerge_use,
348350
unnecessary_async::unnecessary_async,

Diff for: src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs

+21
Original file line numberDiff line numberDiff line change
@@ -3091,6 +3091,27 @@ fn arithmetics {
30913091
)
30923092
}
30933093

3094+
#[test]
3095+
fn doctest_toggle_macro_delimiter() {
3096+
check_doc_test(
3097+
"toggle_macro_delimiter",
3098+
r#####"
3099+
macro_rules! sth {
3100+
() => {};
3101+
}
3102+
3103+
sth!$0( );
3104+
"#####,
3105+
r#####"
3106+
macro_rules! sth {
3107+
() => {};
3108+
}
3109+
3110+
sth!{ }
3111+
"#####,
3112+
)
3113+
}
3114+
30943115
#[test]
30953116
fn doctest_unmerge_match_arm() {
30963117
check_doc_test(

0 commit comments

Comments
 (0)