Skip to content

Commit c1245e1

Browse files
committed
Add new assist toggle_macro_delimiter
1 parent e12408b commit c1245e1

File tree

2 files changed

+229
-0
lines changed

2 files changed

+229
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
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+
// sth! $0( );
16+
// ```
17+
// ->
18+
// ```
19+
// macro_rules! sth! ();
20+
// sth! { }
21+
// ```
22+
pub(crate) fn toggle_macro_delimiter(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
23+
#[derive(Debug)]
24+
enum MacroDelims {
25+
LPar,
26+
RPar,
27+
LBra,
28+
RBra,
29+
LCur,
30+
RCur,
31+
}
32+
33+
enum MakroTypes {
34+
MacroRules(ast::MacroRules),
35+
MacroCall(ast::MacroCall),
36+
}
37+
38+
let makro = if let Some(mc) = ctx.find_node_at_offset_with_descend::<ast::MacroCall>() {
39+
MakroTypes::MacroCall(mc)
40+
} else if let Some(mr) = ctx.find_node_at_offset_with_descend::<ast::MacroRules>() {
41+
MakroTypes::MacroRules(mr)
42+
} else {
43+
return None;
44+
};
45+
46+
let cursor_offset = ctx.offset();
47+
let token_tree = match makro {
48+
MakroTypes::MacroRules(mr) => mr.token_tree()?.clone_for_update(),
49+
MakroTypes::MacroCall(md) => md.token_tree()?.clone_for_update(),
50+
};
51+
52+
let token_tree_text_range = token_tree.syntax().text_range();
53+
let ltoken = token_tree.left_delimiter_token()?;
54+
let rtoken = token_tree.right_delimiter_token()?;
55+
56+
if !ltoken.text_range().contains(cursor_offset) && !rtoken.text_range().contains(cursor_offset)
57+
{
58+
return None;
59+
}
60+
61+
let token = match ltoken.kind() {
62+
T!['{'] => MacroDelims::LCur,
63+
T!['('] => MacroDelims::LPar,
64+
T!['['] => MacroDelims::LBra,
65+
T!['}'] => MacroDelims::RBra,
66+
T![')'] => MacroDelims::RPar,
67+
T!['}'] => MacroDelims::RCur,
68+
_ => return None,
69+
};
70+
71+
acc.add(
72+
AssistId("add_braces", AssistKind::Refactor),
73+
match token {
74+
MacroDelims::LPar => "Replace delimiters with braces",
75+
MacroDelims::RPar => "Replace delimiters with braces",
76+
MacroDelims::LBra => "Replace delimiters with parentheses",
77+
MacroDelims::RBra => "Replace delimiters with parentheses",
78+
MacroDelims::LCur => "Replace delimiters with brackets",
79+
MacroDelims::RCur => "Replace delimiters with brackets",
80+
},
81+
token_tree.syntax().text_range(),
82+
|builder| {
83+
match token {
84+
MacroDelims::LPar | MacroDelims::RPar => {
85+
ted::replace(ltoken, make::token(T!['{']));
86+
ted::replace(rtoken, make::token(T!['}']));
87+
}
88+
MacroDelims::LBra | MacroDelims::RBra => {
89+
ted::replace(ltoken, make::token(T!['(']));
90+
ted::replace(rtoken, make::token(T![')']));
91+
}
92+
MacroDelims::LCur | MacroDelims::RCur => {
93+
ted::replace(ltoken, make::token(T!['[']));
94+
ted::replace(rtoken, make::token(T![']']));
95+
}
96+
}
97+
builder.replace(token_tree_text_range, token_tree.syntax().text());
98+
},
99+
)
100+
}
101+
102+
#[cfg(test)]
103+
mod tests {
104+
use crate::tests::{check_assist, check_assist_not_applicable};
105+
106+
use super::*;
107+
108+
#[test]
109+
fn test_par() {
110+
check_assist(
111+
toggle_macro_delimiter,
112+
r#"
113+
macro_rules! sth ();
114+
sth! $0( );
115+
"#,
116+
r#"
117+
macro_rules! sth ();
118+
sth! { };
119+
"#,
120+
)
121+
}
122+
123+
#[test]
124+
fn test_braclets() {
125+
check_assist(
126+
toggle_macro_delimiter,
127+
r#"
128+
macro_rules! sth ();
129+
sth! $0{ };
130+
"#,
131+
r#"
132+
macro_rules! sth ();
133+
sth! [ ];
134+
"#,
135+
)
136+
}
137+
138+
#[test]
139+
fn test_brackets() {
140+
check_assist(
141+
toggle_macro_delimiter,
142+
r#"
143+
macro_rules! sth ();
144+
sth! $0[ ];
145+
"#,
146+
r#"
147+
macro_rules! sth ();
148+
sth! ( );
149+
"#,
150+
)
151+
}
152+
153+
#[test]
154+
fn test_indent() {
155+
check_assist(
156+
toggle_macro_delimiter,
157+
r#"
158+
mod abc {
159+
macro_rules! sth ();
160+
sth! $0{ };
161+
}
162+
"#,
163+
r#"
164+
mod abc {
165+
macro_rules! sth ();
166+
sth! [ ];
167+
}
168+
"#,
169+
)
170+
}
171+
172+
#[test]
173+
fn test_rules_par() {
174+
check_assist(
175+
toggle_macro_delimiter,
176+
r#"
177+
macro_rules! sth $0();
178+
sth! ( );
179+
"#,
180+
r#"
181+
macro_rules! sth {};
182+
sth! ( );
183+
"#,
184+
)
185+
}
186+
187+
#[test]
188+
fn test_rules_braclets() {
189+
check_assist(
190+
toggle_macro_delimiter,
191+
r#"
192+
macro_rules! sth $0{};
193+
sth! ( );
194+
"#,
195+
r#"
196+
macro_rules! sth [];
197+
sth! ( );
198+
"#,
199+
)
200+
}
201+
202+
#[test]
203+
fn test_rules_brackets() {
204+
check_assist(
205+
toggle_macro_delimiter,
206+
r#"
207+
macro_rules! sth $0[];
208+
sth! ( );
209+
"#,
210+
r#"
211+
macro_rules! sth ();
212+
sth! ( );
213+
"#,
214+
)
215+
}
216+
217+
#[test]
218+
fn test_unrelated_par() {
219+
check_assist_not_applicable(
220+
toggle_macro_delimiter,
221+
r#"
222+
macro_rules! sth [def$0()];
223+
sth! ( );
224+
"#,
225+
)
226+
}
227+
}

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,

0 commit comments

Comments
 (0)