1

I am trying to create a snippet that names a namespace in C# using the name of the last directory in the file path, but it returns everything that comes before it instead.

Here is a demo of the regex, The VSCode snippet, with the replacement values looks like this:

${1:${TM_DIRECTORY/(?<=[\\/\\\\])([a-zA-Z\\-_]+$)/${2:/pascalcase}/}}

because of VS Code quirks and special options.
The output is always the first group, but in the end I am calling the second one. What is causing this?

JΛYDΞV
  • 8,532
  • 3
  • 51
  • 77
Perry
  • 21
  • 1
  • 6
  • This is a typo, and has no debugging details. You can't wrap a replacement value in another replacement value: `${1:${TM_DIRECTORY`. It looks like the whole expression is wrapped in that. – JΛYDΞV May 13 '22 at 15:50
  • 1
    @jD3V It is a variable transform being used as a placeholder, which is perfectly allowable. See https://code.visualstudio.com/docs/editor/userdefinedsnippets#_placeholdertransform. Weren't you wondering why the answer worked? – Mark May 13 '22 at 16:28

1 Answers1

3

You have at least a couple of issues.

First, the first part of the path is being "returned" because you don't actually match it. A lookbehind doesn't include that text as part of the match, as you can see in your demo link.

So unmatched text will not be transformed at all in the snippet, it will just appear where it was.

So you want to match that part of the path even though you will not use it ultimately.

Perhaps you want this regex: (.*[\\/\\\\])([-\w]+$) note no lookbehind

See regex demo

and then:

${1:${TM_DIRECTORY/(.*[\\/\\\\])([-\\w]+$)/${2:/pascalcase}/}}"

Note that it is capture group 2 that is being pascal-cased and that capture group 1 (everything before and including the final path separator) is not used, so it is effectively removed - i.e., it is not in the replacement.

Note the backslashes are doubled because the pattern is passed as a string literal, and / chars must be escaped because the string literal contains a "stringified" regex literal.

\\\\ is escaping each backslash once, it is \\ and another \\ to result in \\ after it is de-stringified. The backslash still operates as an escape character in the [], so if you want a literal \ it must be escaped. And in order to end up with two backslashes in a row like \\, each backslash must itself be escaped in a vscode snippet string.

Mark
  • 143,421
  • 24
  • 428
  • 436
  • Why do you need the last 4 "\" on the first group? – Perry May 11 '22 at 18:23
  • @rioV8 If you try it, you see ` [\\/\\\\]` is all required. See comments in the answer. @Perry also see the comments about `\\\\` which is a pain but is required here. Short answer is that gets evaluated (de-stringified) before it gets evaluated again for the actual operation of the resulting regex. – Mark May 11 '22 at 21:03
  • That is a really big bounty – rioV8 May 12 '22 at 06:21
  • It occurs to me that a big reason requiring forward slashes to be escaped in snippet regex's is simply that snippet transforms use forward slashes to separate the different areas of the tranform: `${1:/regex/replace}`. If you a forward slash in the replcement it must be double-escaped too. Things like `$1:/upcase}` are pretty easily detected so those are okay. But it would be very difficult to parse the regex from the replacement if non-escaped forward slashes were allowed. And then once you require `\/` then due to JSON the backslash itself must be escaped, resulting in `\\/`. – Mark May 12 '22 at 18:12