Nested regex replacement in VS Code Snippet

728 views Asked by At

I've made a mistake in making a lot of bold readings in restructured text (rst) files where I should've used a different heading style.

I need to replace:

**some heading**

with:

some heading
............

I'm wanting to do this with VS Code snippets, where I highlight the text in question, and then run the snippet to make the replacement.

To do this, I think I need to make two replacements:

  1. Take selected text, strip leading and trailing **
  2. Take the result of 1, and then essentially replace anything (.) with literal dot (.): s/././g

I cannot figure out how to make nested replacements in VS Code snippets -- is this even possible?

This is what I have right now:

    "BoldToSubHeading": {
        "prefix": ["boldtosubheading"],
        "body": [
            "${TM_SELECTED_TEXT/\\*\\*(.*)\\*\\*/${1}/}",
            "${TM_SELECTED_TEXT/././g}",
        ],
        "description": "Change bold text into subheading."
    }

If the input text is:

**foobar**

I get four too many dots -- because the asterisks are included in the last replacement.

foobar
..........

Textmate docs, which the Snippet code seems to be based on, indicates:

For nested replacements, use named captures as variables are inherited.

However, I've tried the "${TM_SELECTED_TEXT/(?<guts>.*)/${guts}/g}" with no luck.

Any suggestions to solve my replacement problem? Are nested replacements possible with snippets?

Requirements are:

  1. Highlighted text will contain double asterisk at front and back
  2. Text between the double asterisks (let's call it 'guts') can contain anything -- spaces, numbers, quotes, etc
  3. The result should be 'guts', plus a new line, plus a number of dots equal to length of guts.
1

There are 1 answers

1
Mark On BEST ANSWER

I thought this would be easier with one snippet - perhaps with a conditional replacement - but I couldn't figure it out in a reasonable time. But it is pretty easy to do in steps.

Using a macro extension like multi-command, put this into your settings:

"multiCommand.commands": [

  {
    "command": "multiCommand.refactorHeadings",
    "interval": 250,   // remove this line and will be instantaneous
    "sequence": [

      {
        "command": "editor.action.insertSnippet",
        "args": {
          "snippet": "${TM_SELECTED_TEXT/\\*\\*(.*)\\*\\*/$1/}",
        }
      },
       "editor.action.copyLinesDownAction",
        "cursorLineStartSelect",
      {
        "command": "editor.action.insertSnippet",
        "args": {
          "snippet": "${TM_SELECTED_TEXT/././g}",
        }
      } 
    ]
  }
],

and a keybinding (in keybindings.json) to trigger it:

{
  "key": "alt+c",    // whatever keybinding you like
  "command": "extension.multiCommand.execute",
  "args": { "command": "multiCommand.refactorHeadings" },

        // replace markdown with your langId
  // "when": "editorTextFocus && editorHasSelection && editorLangId == markdown"
},

refactor headings with a macro

The demo shows selecting all such occurrences of your simple find regex,Ctrl+Shift+L will do that, and triggering the macro. It is showed slowed down just for demonstration purposes.