1

I'm writing a snippet in VS Code using variable transforms. I want to replace a pattern that occurs in some text (in this case text copied on the clipboard) with a variable that inserts the name of the file without extensions (for example: CurrentFileNameWithoutExtensions). What happens is the pattern gets replaced with the variable name as a string, and not the value of the variable.

Here's the snippet:

"${CLIPBOARD/pattern/$TM_FILENAME_BASE/}"

The output is: "pattern" becomes "$TM_FILENAME_BASE".
The correct output would be: "pattern" becomes "CurrentFileNameWithoutExtensions".

A possible solution to this could be outputting all the clipboard text before the pattern, then the variable, and finally all the clipboard text after the pattern. How would this be done?

Example clipboard text:

Text that is before pattern in clipboard.
pattern
Text that is after pattern in clipboard.

The snippet could capture all text until the pattern and output it:

Text that is before pattern in clipboard.

Then it would output the variable $TM_FILENAME_BASE:

CurrentFileNameWithoutExtensions

Finally it would output the text after the pattern:

Text that is after pattern in clipboard.

The output would look like this put together:

Text that is before pattern in clipboard.
CurrentFileNameWithoutExtensions
Text that is after pattern in clipboard.
Joe
  • 345
  • 1
  • 14
  • 1
    You cannot do that in a snippet in vscode. The snippet grammar, see https://code.visualstudio.com/docs/editor/userdefinedsnippets#_grammar, does not support variables in the `pattern` or `replacement` parts of a transform (other than the case modifiers and conditionals). There may be an extension that can do that though. – Mark Jan 28 '22 at 03:43
  • @Mark Thanks for the clarification! I was actually able to solve my problem in a roundabout way because the pattern I wanted to replace was almost at the beginning of the clipboard text. What I did was insert the words that came before the pattern (which happened to be the same every time in my case), insert the variable outside of the transform so it worked properly, and finally insert the clipboard text in a transform that replaced the pattern, and everything before it, with an empty string. – Joe Jan 28 '22 at 04:26
  • Would there be a way to do this method with a pattern in the middle of the clipboard text, and using regex to somehow capture all text before the pattern, and all text after the pattern, and then insert them in the proper order? – Joe Jan 28 '22 at 04:29
  • 1
    I think you need to give a example in your question of what you are trying to do. Your original question, of comparing some pattern to the Clipboard and outputting something if there is a match, would be relatively easy to do in an extension. – Mark Jan 28 '22 at 04:35
  • @Mark I added an example in my question. I'm not sure if it's possible though. – Joe Jan 28 '22 at 04:45

2 Answers2

1

Capture the different parts in groups and only output the group you want

It works also if pattern is not part of the CLIPBOARD

"${CLIPBOARD/^((.*?)(pattern.*)|(.*))$/$2$4/}$TM_FILENAME_BASE${CLIPBOARD/^((.*?pattern)(.*)|(.*))$/$3/}"
rioV8
  • 24,506
  • 3
  • 32
  • 49
  • This almost works perfectly, however this outputs the text after the pattern twice, once in between the text before the pattern and the pattern (unwanted), and also again after the pattern (wanted). How would this be fixed? Also could you please explain what (.*?) and (.*) are used for? Thanks so much! – Joe Jan 28 '22 at 13:47
  • Also this was outputting the file name like this "${CurrentFileNameWithoutExtensions}", so I removed the extra dollar sign. `"${CLIPBOARD/(.*?)(pattern.*)/$1/}${TM_FILENAME_BASE}${CLIPBOARD/(.*?pattern)(.*)/$2/}"` – Joe Jan 28 '22 at 13:50
  • 1
    @DB I had not tested it, you see it twice if CLIPBOARD does not contain `pattern`, I have modified it so it also works (tested) if `pattern` is not in CLIPBOARD, for explanation read up on regular expressions – rioV8 Jan 28 '22 at 15:21
  • 1
    @DB This always prints out the fileNameBase whether pattern matches or not? If no match with pattern the fileNameBase is printed at the end - is that what you wanted? What do you want if pattern does not match? – Mark Jan 28 '22 at 16:03
  • @rioV8 This is the output I'm getting currently: `Text that is before pattern in clipboard. pattern Text that is after pattern in clipboard.CurrentFileNameWithoutExtensionsText that is before pattern in clipboard. pattern Text that is after pattern in clipboard.` – Joe Jan 28 '22 at 16:39
  • @Mark In my case there will always be a matching pattern. I guess if for some reason there was no match, then I would want it to just output the clipboard, and not modify it at all. – Joe Jan 28 '22 at 16:41
  • 1
    @DB In your example there are 3 places with the text `pattern`, modify the example to match a real case, 3 times the same text messes with the case that you want the middle one replaced – rioV8 Jan 28 '22 at 17:49
1

If there is always a matching pattern, then this works:

"pattern": {
    "prefix": "_pt",
    "body": [
      "${CLIPBOARD/(.*[\r\n]*)((pattern)([\r\n]*))(.*)/$1/}$TM_FILENAME_BASE${CLIPBOARD/(.*[\r\n]*)((pattern)([\r\n]*))(.*)/$4$5/}"

    ],
    "description": "clipboard pattern"
}

This handles any number of newlines as in

first text
pattern
second text

or

first text

pattern


second text

or

first textpatternsecond text

See regex101 demo

Of course, as rioV8 points out, if pattern also matches in the text somewhere in addition to the middle that is a problem.

Mark
  • 143,421
  • 24
  • 428
  • 436