|
| 1 | +## Rewrite `indoc!` macro <Badge type="tip" text="Has Fix" /> |
| 2 | + |
| 3 | + |
| 4 | +* [Playground Link](/playground.html#eyJtb2RlIjoiUGF0Y2giLCJsYW5nIjoicnVzdCIsInF1ZXJ5IjoiaW5kb2MhIHsgciNcIiQkJEFcIiMgfSIsInJld3JpdGUiOiJgJCQkQWAiLCJzdHJpY3RuZXNzIjoicmVsYXhlZCIsInNlbGVjdG9yIjoiIiwiY29uZmlnIjoicnVsZTogXG4gYW55OlxuIC0gcGF0dGVybjogJFYgPT09ICRTRU5TRVRJVkVXT1JEXG4gLSBwYXR0ZXJuOiAkU0VOU0VUSVZFV09SRCA9PT0gJFZcbmNvbnN0cmFpbnRzOlxuICBTRU5TRVRJVkVXT1JEOlxuICAgIHJlZ2V4OiBwYXNzd29yZCIsInNvdXJjZSI6ImZuIG1haW4oKSB7XG4gICAgaW5kb2MhIHtyI1wiXG4gICAgICAgIC5mb28ge1xuICAgICAgICAgICAgb3JkZXI6IDE7XG4gICAgICAgIH1cbiAgICBcIiN9O1xufSJ9) |
| 5 | + |
| 6 | +### Description |
| 7 | + |
| 8 | +This example, created from [a Tweet](https://x.com/zack_overflow/status/1885065128590401551), shows a refactoring operation being performed on Rust source code. The changes involve removing `indoc!` macro declarations while preserving the CSS-like content within them. |
| 9 | + |
| 10 | +Previously, the same refactor is implemented by a _unreadable monster regex_ in vim syntax. |
| 11 | + |
| 12 | +:::details Click to see the original regex (neovim, btw) |
| 13 | + |
| 14 | +```vimscript |
| 15 | +:%s/\v(indoc!|)(| )([|\{)r#"(([^#]+|\n+)+)"#/\4 |
| 16 | +``` |
| 17 | +I have to confess that I don't understand this regex even if I use neovim, btw. |
| 18 | + |
| 19 | +Let Claude break it down piece by piece: |
| 20 | + |
| 21 | +- `:%s/` - This is a vim/sed substitution command |
| 22 | +- `\v` - Very magic mode in vim, making special characters active by default |
| 23 | +- `(indoc!|)` - Matches either "indoc!" or nothing (optional indoc!) |
| 24 | +- `(| )([\{)` - Matches any spaces, parentheses, or curly braces |
| 25 | +- `r#"` - Matches the literal raw string prefix in Rust |
| 26 | +- `(([^#]+|\n+)+)` - This is the capture group that matches: |
| 27 | + - `[^#]+` - Any characters that aren't '#' |
| 28 | + - `|\n+` - Or one or more newlines |
| 29 | + - The outer `()+` makes it match one or more of these sequences |
| 30 | +- `"#` - Matches the raw string suffix |
| 31 | +- `/\4` - Replaces the entire match with the contents of the 4th capture group |
| 32 | + |
| 33 | +This regex appears to be designed to extract the content from within Rust raw string literals that may or may not be wrapped in the `indoc!` macro. |
| 34 | + |
| 35 | +::: |
| 36 | + |
| 37 | +<!-- Use pattern in the example. Delete this section if use YAML. --> |
| 38 | +### Pattern |
| 39 | + |
| 40 | +```shell |
| 41 | +ast-grep --pattern 'indoc! { r#"$$$A"# }' --rewrite '$$$A' sgtest.rs |
| 42 | +``` |
| 43 | + |
| 44 | +### Example |
| 45 | + |
| 46 | +<!-- highlight matched code in curly-brace {lineNum} --> |
| 47 | +```rs {2-6} |
| 48 | +fn main() { |
| 49 | + indoc! {r#" |
| 50 | + .foo { |
| 51 | + order: 1; |
| 52 | + } |
| 53 | + "#}; |
| 54 | +} |
| 55 | +``` |
| 56 | + |
| 57 | +### Diff |
| 58 | +<!-- use // [!code --] and // [!code ++] to annotate diff --> |
| 59 | +```rs |
| 60 | +fn main() { |
| 61 | + indoc! {r#" // [!code --] |
| 62 | + `.foo { // [!code ++] |
| 63 | + order: 1; |
| 64 | + } |
| 65 | + "#}; // [!code --] |
| 66 | + `; // [!code ++] |
| 67 | +} |
| 68 | +``` |
| 69 | + |
| 70 | +### Contributed by |
| 71 | +[Zack in SF](https://x.com/zack_overflow) |
0 commit comments