diff options
| author | bors <bors@rust-lang.org> | 2024-08-27 12:25:43 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2024-08-27 12:25:43 +0000 |
| commit | 199c01df7a138694387a8635e7b10a0ff1578d14 (patch) | |
| tree | 06ead91569b6e7771f190e69cce1a8eaeb9a2d0a | |
| parent | 2dce25020e412fbb6a33b94def67e2958e6f2dbf (diff) | |
| parent | c9a3b022818fb61b7af1e2bcdb6b707ea9f6df6f (diff) | |
| download | rust-199c01df7a138694387a8635e7b10a0ff1578d14.tar.gz rust-199c01df7a138694387a8635e7b10a0ff1578d14.zip | |
Auto merge of #17757 - alibektas:toggle_macro_delimiters, r=Veykril
assist: Add new assist toggle_macro_delimiter Closes #17716
3 files changed, 279 insertions, 0 deletions
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_macro_delimiter.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_macro_delimiter.rs new file mode 100644 index 00000000000..eedb2ea3b9a --- /dev/null +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_macro_delimiter.rs @@ -0,0 +1,256 @@ +use ide_db::assists::{AssistId, AssistKind}; +use syntax::{ + ast::{self, make}, + ted, AstNode, T, +}; + +use crate::{AssistContext, Assists}; + +// Assist: toggle_macro_delimiter +// +// Change macro delimiters in the order of `( -> { -> [ -> (`. +// +// ``` +// macro_rules! sth { +// () => {}; +// } +// +// sth!$0( ); +// ``` +// -> +// ``` +// macro_rules! sth { +// () => {}; +// } +// +// sth!{ } +// ``` +pub(crate) fn toggle_macro_delimiter(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { + #[derive(Debug)] + enum MacroDelims { + LPar, + RPar, + LBra, + RBra, + LCur, + RCur, + } + + let makro = ctx.find_node_at_offset::<ast::MacroCall>()?.clone_for_update(); + let makro_text_range = makro.syntax().text_range(); + + let cursor_offset = ctx.offset(); + let semicolon = makro.semicolon_token(); + let token_tree = makro.token_tree()?; + + let ltoken = token_tree.left_delimiter_token()?; + let rtoken = token_tree.right_delimiter_token()?; + + if !ltoken.text_range().contains(cursor_offset) && !rtoken.text_range().contains(cursor_offset) + { + return None; + } + + let token = match ltoken.kind() { + T!['{'] => MacroDelims::LCur, + T!['('] => MacroDelims::LPar, + T!['['] => MacroDelims::LBra, + T!['}'] => MacroDelims::RBra, + T![')'] => MacroDelims::RPar, + T!['}'] => MacroDelims::RCur, + _ => return None, + }; + + acc.add( + AssistId("toggle_macro_delimiter", AssistKind::Refactor), + match token { + MacroDelims::LPar => "Replace delimiters with braces", + MacroDelims::RPar => "Replace delimiters with braces", + MacroDelims::LBra => "Replace delimiters with parentheses", + MacroDelims::RBra => "Replace delimiters with parentheses", + MacroDelims::LCur => "Replace delimiters with brackets", + MacroDelims::RCur => "Replace delimiters with brackets", + }, + token_tree.syntax().text_range(), + |builder| { + match token { + MacroDelims::LPar | MacroDelims::RPar => { + ted::replace(ltoken, make::token(T!['{'])); + ted::replace(rtoken, make::token(T!['}'])); + if let Some(sc) = semicolon { + ted::remove(sc); + } + } + MacroDelims::LBra | MacroDelims::RBra => { + ted::replace(ltoken, make::token(T!['('])); + ted::replace(rtoken, make::token(T![')'])); + } + MacroDelims::LCur | MacroDelims::RCur => { + ted::replace(ltoken, make::token(T!['['])); + ted::replace(rtoken, make::token(T![']'])); + } + } + builder.replace(makro_text_range, makro.syntax().text()); + }, + ) +} + +#[cfg(test)] +mod tests { + use crate::tests::{check_assist, check_assist_not_applicable}; + + use super::*; + + #[test] + fn test_par() { + check_assist( + toggle_macro_delimiter, + r#" +macro_rules! sth { + () => {}; +} + +sth!$0( ); + "#, + r#" +macro_rules! sth { + () => {}; +} + +sth!{ } + "#, + ) + } + + #[test] + fn test_braces() { + check_assist( + toggle_macro_delimiter, + r#" +macro_rules! sth { + () => {}; +} + +sth!$0{ }; + "#, + r#" +macro_rules! sth { + () => {}; +} + +sth![ ]; + "#, + ) + } + + #[test] + fn test_brackets() { + check_assist( + toggle_macro_delimiter, + r#" +macro_rules! sth { + () => {}; +} + +sth!$0[ ]; + "#, + r#" +macro_rules! sth { + () => {}; +} + +sth!( ); + "#, + ) + } + + #[test] + fn test_indent() { + check_assist( + toggle_macro_delimiter, + r#" +mod abc { + macro_rules! sth { + () => {}; + } + + sth!$0{ }; +} + "#, + r#" +mod abc { + macro_rules! sth { + () => {}; + } + + sth![ ]; +} + "#, + ) + } + + #[test] + fn test_unrelated_par() { + check_assist_not_applicable( + toggle_macro_delimiter, + r#" +macro_rules! prt { + ($e:expr) => {{ + println!("{}", stringify!{$e}); + }}; +} + +prt!(($03 + 5)); + + "#, + ) + } + + #[test] + fn test_longer_macros() { + check_assist( + toggle_macro_delimiter, + r#" +macro_rules! prt { + ($e:expr) => {{ + println!("{}", stringify!{$e}); + }}; +} + +prt!$0((3 + 5)); +"#, + r#" +macro_rules! prt { + ($e:expr) => {{ + println!("{}", stringify!{$e}); + }}; +} + +prt!{(3 + 5)} +"#, + ) + } + + // FIXME @alibektas : Inner macro_call is not seen as such. So this doesn't work. + #[test] + fn test_nested_macros() { + check_assist_not_applicable( + toggle_macro_delimiter, + r#" +macro_rules! prt { + ($e:expr) => {{ + println!("{}", stringify!{$e}); + }}; +} + +macro_rules! abc { + ($e:expr) => {{ + println!("{}", stringify!{$e}); + }}; +} + +prt!{abc!($03 + 5)}; +"#, + ) + } +} diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs index a9399ba6b7f..b97f0f27398 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs @@ -213,6 +213,7 @@ mod handlers { mod term_search; mod toggle_async_sugar; mod toggle_ignore; + mod toggle_macro_delimiter; mod unmerge_match_arm; mod unmerge_use; mod unnecessary_async; @@ -343,6 +344,7 @@ mod handlers { split_import::split_import, term_search::term_search, toggle_ignore::toggle_ignore, + toggle_macro_delimiter::toggle_macro_delimiter, unmerge_match_arm::unmerge_match_arm, unmerge_use::unmerge_use, unnecessary_async::unnecessary_async, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs index a2287b2977d..595ce1affb0 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs @@ -3092,6 +3092,27 @@ fn arithmetics { } #[test] +fn doctest_toggle_macro_delimiter() { + check_doc_test( + "toggle_macro_delimiter", + r#####" +macro_rules! sth { + () => {}; +} + +sth!$0( ); +"#####, + r#####" +macro_rules! sth { + () => {}; +} + +sth!{ } +"#####, + ) +} + +#[test] fn doctest_unmerge_match_arm() { check_doc_test( "unmerge_match_arm", |
