about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAli Bektas <bektasali@protonmail.com>2024-08-01 02:36:31 +0200
committerAli Bektas <bektasali@protonmail.com>2024-08-01 02:38:33 +0200
commitc1245e16df93ffc583234063265afce8dbd7b43e (patch)
tree912919f5b0cce503a0ecc25f813c65ff7d95b960
parente12408bf1145a0339e37d73259c36999e078eb44 (diff)
downloadrust-c1245e16df93ffc583234063265afce8dbd7b43e.tar.gz
rust-c1245e16df93ffc583234063265afce8dbd7b43e.zip
Add new assist toggle_macro_delimiter
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_macro_delimiter.rs227
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/lib.rs2
2 files changed, 229 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..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::<ast::MacroCall>() {
+        MakroTypes::MacroCall(mc)
+    } else if let Some(mr) = ctx.find_node_at_offset_with_descend::<ast::MacroRules>() {
+        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 @@ 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,