From c1245e16df93ffc583234063265afce8dbd7b43e Mon Sep 17 00:00:00 2001 From: Ali Bektas Date: Thu, 1 Aug 2024 02:36:31 +0200 Subject: [PATCH 1/3] Add new assist toggle_macro_delimiter --- .../src/handlers/toggle_macro_delimiter.rs | 227 ++++++++++++++++++ .../crates/ide-assists/src/lib.rs | 2 + 2 files changed, 229 insertions(+) create mode 100644 src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_macro_delimiter.rs 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..490957d04a0 --- /dev/null +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_macro_delimiter.rs @@ -0,0 +1,227 @@ +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, + } + + enum MakroTypes { + MacroRules(ast::MacroRules), + MacroCall(ast::MacroCall), + } + + let makro = if let Some(mc) = ctx.find_node_at_offset_with_descend::() { + MakroTypes::MacroCall(mc) + } else if let Some(mr) = ctx.find_node_at_offset_with_descend::() { + MakroTypes::MacroRules(mr) + } else { + return None; + }; + + let cursor_offset = ctx.offset(); + let token_tree = match makro { + MakroTypes::MacroRules(mr) => mr.token_tree()?.clone_for_update(), + MakroTypes::MacroCall(md) => md.token_tree()?.clone_for_update(), + }; + + let token_tree_text_range = token_tree.syntax().text_range(); + 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("add_braces", 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!['}'])); + } + 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(token_tree_text_range, token_tree.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_braclets() { + 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_rules_par() { + check_assist( + toggle_macro_delimiter, + r#" +macro_rules! sth $0(); +sth! ( ); + "#, + r#" +macro_rules! sth {}; +sth! ( ); + "#, + ) + } + + #[test] + fn test_rules_braclets() { + check_assist( + toggle_macro_delimiter, + r#" +macro_rules! sth $0{}; +sth! ( ); + "#, + r#" +macro_rules! sth []; +sth! ( ); + "#, + ) + } + + #[test] + fn test_rules_brackets() { + check_assist( + toggle_macro_delimiter, + r#" +macro_rules! sth $0[]; +sth! ( ); + "#, + r#" +macro_rules! sth (); +sth! ( ); + "#, + ) + } + + #[test] + fn test_unrelated_par() { + check_assist_not_applicable( + toggle_macro_delimiter, + r#" +macro_rules! sth [def$0()]; +sth! ( ); + "#, + ) + } +} 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 @@ pub(crate) fn all() -> &'static [Handler] { 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, From 662f02fc9bbd996a001779d5ec1b31a495944049 Mon Sep 17 00:00:00 2001 From: Ali Bektas Date: Fri, 2 Aug 2024 02:00:26 +0200 Subject: [PATCH 2/3] Make toggle_macro_delimiters work only for macro_calls --- .../src/handlers/toggle_macro_delimiter.rs | 181 ++++++++++-------- .../crates/ide-assists/src/tests/generated.rs | 21 ++ 2 files changed, 126 insertions(+), 76 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 index 490957d04a0..6fa5ff761f6 100644 --- 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 @@ -11,12 +11,18 @@ // Change macro delimiters in the order of `( -> { -> [ -> (`. // // ``` -// macro_rules! sth (); +// macro_rules! sth { +// () => {}; +// } +// // sth! $0( ); // ``` // -> // ``` -// macro_rules! sth! (); +// macro_rules! sth { +// () => {}; +// } +// // sth! { } // ``` pub(crate) fn toggle_macro_delimiter(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { @@ -30,26 +36,13 @@ enum MacroDelims { RCur, } - enum MakroTypes { - MacroRules(ast::MacroRules), - MacroCall(ast::MacroCall), - } - - let makro = if let Some(mc) = ctx.find_node_at_offset_with_descend::() { - MakroTypes::MacroCall(mc) - } else if let Some(mr) = ctx.find_node_at_offset_with_descend::() { - MakroTypes::MacroRules(mr) - } else { - return None; - }; + let makro = ctx.find_node_at_offset_with_descend::()?.clone_for_update(); + let makro_text_range = makro.syntax().text_range(); let cursor_offset = ctx.offset(); - let token_tree = match makro { - MakroTypes::MacroRules(mr) => mr.token_tree()?.clone_for_update(), - MakroTypes::MacroCall(md) => md.token_tree()?.clone_for_update(), - }; + let semicolon = makro.semicolon_token(); + let token_tree = makro.token_tree()?; - let token_tree_text_range = token_tree.syntax().text_range(); let ltoken = token_tree.left_delimiter_token()?; let rtoken = token_tree.right_delimiter_token()?; @@ -84,6 +77,9 @@ enum MakroTypes { 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!['('])); @@ -94,7 +90,7 @@ enum MakroTypes { ted::replace(rtoken, make::token(T![']'])); } } - builder.replace(token_tree_text_range, token_tree.syntax().text()); + builder.replace(makro_text_range, makro.syntax().text()); }, ) } @@ -110,12 +106,18 @@ fn test_par() { check_assist( toggle_macro_delimiter, r#" -macro_rules! sth (); +macro_rules! sth { + () => {}; +} + sth! $0( ); "#, r#" -macro_rules! sth (); -sth! { }; +macro_rules! sth { + () => {}; +} + +sth! { } "#, ) } @@ -125,11 +127,17 @@ fn test_braclets() { check_assist( toggle_macro_delimiter, r#" -macro_rules! sth (); +macro_rules! sth { + () => {}; +} + sth! $0{ }; "#, r#" -macro_rules! sth (); +macro_rules! sth { + () => {}; +} + sth! [ ]; "#, ) @@ -140,11 +148,17 @@ fn test_brackets() { check_assist( toggle_macro_delimiter, r#" -macro_rules! sth (); +macro_rules! sth { + () => {}; +} + sth! $0[ ]; "#, r#" -macro_rules! sth (); +macro_rules! sth { + () => {}; +} + sth! ( ); "#, ) @@ -156,72 +170,87 @@ fn test_indent() { toggle_macro_delimiter, r#" mod abc { - macro_rules! sth (); + macro_rules! sth { + () => {}; + } + sth! $0{ }; } "#, r#" mod abc { - macro_rules! sth (); + macro_rules! sth { + () => {}; + } + sth! [ ]; } "#, ) } - #[test] - fn test_rules_par() { - check_assist( - toggle_macro_delimiter, - r#" -macro_rules! sth $0(); -sth! ( ); - "#, - r#" -macro_rules! sth {}; -sth! ( ); - "#, - ) - } - - #[test] - fn test_rules_braclets() { - check_assist( - toggle_macro_delimiter, - r#" -macro_rules! sth $0{}; -sth! ( ); - "#, - r#" -macro_rules! sth []; -sth! ( ); - "#, - ) - } - - #[test] - fn test_rules_brackets() { - check_assist( - toggle_macro_delimiter, - r#" -macro_rules! sth $0[]; -sth! ( ); - "#, - r#" -macro_rules! sth (); -sth! ( ); - "#, - ) - } - #[test] fn test_unrelated_par() { check_assist_not_applicable( toggle_macro_delimiter, r#" -macro_rules! sth [def$0()]; -sth! ( ); +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/tests/generated.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs index a2287b2977d..05e1aff5f9f 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 @@ -3091,6 +3091,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( From c9a3b022818fb61b7af1e2bcdb6b707ea9f6df6f Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 27 Aug 2024 14:23:23 +0200 Subject: [PATCH 3/3] Fix tests --- .../src/handlers/toggle_macro_delimiter.rs | 42 +++++++++---------- .../crates/ide-assists/src/tests/generated.rs | 4 +- 2 files changed, 23 insertions(+), 23 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 index 6fa5ff761f6..eedb2ea3b9a 100644 --- 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 @@ -15,7 +15,7 @@ // () => {}; // } // -// sth! $0( ); +// sth!$0( ); // ``` // -> // ``` @@ -23,7 +23,7 @@ // () => {}; // } // -// sth! { } +// sth!{ } // ``` pub(crate) fn toggle_macro_delimiter(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { #[derive(Debug)] @@ -36,7 +36,7 @@ enum MacroDelims { RCur, } - let makro = ctx.find_node_at_offset_with_descend::()?.clone_for_update(); + let makro = ctx.find_node_at_offset::()?.clone_for_update(); let makro_text_range = makro.syntax().text_range(); let cursor_offset = ctx.offset(); @@ -62,7 +62,7 @@ enum MacroDelims { }; acc.add( - AssistId("add_braces", AssistKind::Refactor), + AssistId("toggle_macro_delimiter", AssistKind::Refactor), match token { MacroDelims::LPar => "Replace delimiters with braces", MacroDelims::RPar => "Replace delimiters with braces", @@ -110,20 +110,20 @@ macro_rules! sth { () => {}; } -sth! $0( ); +sth!$0( ); "#, r#" macro_rules! sth { () => {}; } -sth! { } +sth!{ } "#, ) } #[test] - fn test_braclets() { + fn test_braces() { check_assist( toggle_macro_delimiter, r#" @@ -131,14 +131,14 @@ macro_rules! sth { () => {}; } -sth! $0{ }; +sth!$0{ }; "#, r#" macro_rules! sth { () => {}; } -sth! [ ]; +sth![ ]; "#, ) } @@ -152,14 +152,14 @@ macro_rules! sth { () => {}; } -sth! $0[ ]; +sth!$0[ ]; "#, r#" macro_rules! sth { () => {}; } -sth! ( ); +sth!( ); "#, ) } @@ -174,7 +174,7 @@ macro_rules! sth { () => {}; } - sth! $0{ }; + sth!$0{ }; } "#, r#" @@ -183,7 +183,7 @@ macro_rules! sth { () => {}; } - sth! [ ]; + sth![ ]; } "#, ) @@ -196,7 +196,7 @@ fn test_unrelated_par() { r#" macro_rules! prt { ($e:expr) => {{ - println!("{}", stringify! {$e}); + println!("{}", stringify!{$e}); }}; } @@ -213,20 +213,20 @@ fn test_longer_macros() { r#" macro_rules! prt { ($e:expr) => {{ - println!("{}", stringify! {$e}); + println!("{}", stringify!{$e}); }}; } -prt! $0((3 + 5)); +prt!$0((3 + 5)); "#, r#" macro_rules! prt { ($e:expr) => {{ - println!("{}", stringify! {$e}); + println!("{}", stringify!{$e}); }}; } -prt! {(3 + 5)} +prt!{(3 + 5)} "#, ) } @@ -239,17 +239,17 @@ fn test_nested_macros() { r#" macro_rules! prt { ($e:expr) => {{ - println!("{}", stringify! {$e}); + println!("{}", stringify!{$e}); }}; } macro_rules! abc { ($e:expr) => {{ - println!("{}", stringify! {$e}); + println!("{}", stringify!{$e}); }}; } -prt! {abc!($03 + 5)}; +prt!{abc!($03 + 5)}; "#, ) } 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 05e1aff5f9f..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 @@ -3100,14 +3100,14 @@ macro_rules! sth { () => {}; } -sth! $0( ); +sth!$0( ); "#####, r#####" macro_rules! sth { () => {}; } -sth! { } +sth!{ } "#####, ) }