0

Background

  • Hi all, I'm wokring on a VScode extension for snippets. I highlighted all $name TextMate style variables like $CURRENT_YEAR and $TM_FILENAME_BASE.

    name in $name can be a integer, or a static variable.

  • I would also like to highlight variables like ${<INTEGER>:<DEFAULT>}, ${<INTEGER>:<DEFAULT>|<OPTIONAL_OPTIONS>} e.g. ${2:placeholder} and ${1:true|false}

  • Moreover, highlight transformed variables ${<STATIC_VAR>\<MATCH_REGEX>\<TRANSFORM_TARGET>\}. Example: ${TM_FILENAME/[\\.]/_/ replaces the first . with _.

  • All these example can be found in VScode documentation

  • I played Regex Golf a little, but I couldn't solve the "Balance" Chapter

Question

Is there a NEAT way to match all TextMate variables(see definition in chapter 7.2) with a Regular Expression (or other technique)?

In detail, I would want my Regex to match all $<NAME>, ${<INTEGER>:<DEFAULT>|<OPTION>}, and ${<STATIC_VAR>\<MATCH_REGEX>\<TRANSFORM_TARGET>\}

where

  • <NAME> can be digits and some specific letters like LINE_COMMENT;
  • <DEFAULT> and can be any text.
  • <STATIC_VAR> is some specific letters like LINE_COMMENT
  • <MATCH_REGEX> A regular expression, I'm not going to check if it is legal. <TRANSFORM_TARGET> The regular expression substitution output, not going to check.

My idea was to detect if there is a pair of brackets (curly parentheses). And the first word after parentheses opening is a <NAME>.

TextMate uses Oniguruma regular expression library by K. Kosako

What I've done

  • Match variable without {} with
match:"\\$(?:[0-9]+|TM_SELECTED_TEXT|<TYPED_ALL_POSSIBLE_NAMES>|TM_CURRENT_WORD|LINE_COMMENT)"
\\$(?= (?=<ALL_NAMES>)|{(?=<ALL_NAMES>):.+} )

Where <ALL_NAMES> represents all <NAME>s joined with pipe char |

2
  • It is not quite clear what the issue is with your "dirty" regex. What about [$](\{)?\w+(?(1)(?:\/.*})?) (demo)? Commented Sep 13, 2021 at 6:56
  • Yes! I just test it and it works beautifully. Before I worked with [regexr](regexr.com) and I knew nothing about "group conditional". By the way, your code did match the transformation but not the default value like ${1:OPT1|OPT2}, please consider add a : like this [$](\{)?\w+(?(1)(?:[\/:].+})?) (new demo)and answer the question so we can close it. Commented Sep 13, 2021 at 7:46

2 Answers 2

1

You can use a conditional construct here:

[$](\{)?\w+(?(1)(?:[\/:].*})?)

See the regex demo.

Details:

  • [$] - a $ char
  • (\{)? - an optional capturing group with ID = 1 that matches a { char
  • \w+ - one or more word chars
  • (?(1)(?:[\/:].*})?) - a conditional construct: if Group 1 matched, matches an optional sequence of a / or : and then any zero or more chars other than line break chars as many as possible up to the rightmost occurrence of a } char.
Sign up to request clarification or add additional context in comments.

4 Comments

Sorry that I made a mistake in the code (?(1)(?:[\/:].*})?) because there should be at least 1 char after the : or /. I'm accepting this answer but I made a HUGE mistake while describing the question ... So I'm editing this question now. Please consider edit the answer accordingly. I'll finish it in <10min.
The conditional group used here did solve most of my question and it works correctly in .tmLanguage.json for VScode.
@Pablion Yes, your question is a bit hectic.So, one char must be there after / or :? Then replace .* with .+.
Feels like I squeezed too many questions in one question. So I rewrite the question to make it clearer. Huge appreciation again.
0

Credit to Wiktor Stribiżew

The regular expression

Test demo with explanation

[$]([{])?([0-9]+)?(?(2)|(?:TM_FILENAME))(?(1)(?(2)[:].+|[\/].+[\/].*[\/])})

What does this regex do:

  • Match all these (legal vscode snippet variables):
$1
$21
${1:default}
${1:default|option}
$TM_FILENAME
${TM_FILENAME/[\.]/_/}
${TM_FILENAME/a//}
  • And match NONE of these:
${1:}
${TM_FILENAME:a|b}
${TM_FILENAME/}
${TM_FILENAME/a/}
${TM_FILENAME//abc/}
${TM_FILENAME/a//a}

full .tmLanguage.json fomat code

"match": "[$]({)?([0-9]+)?(?(2)|(?:TM_SELECTED_TEXT|TM_CURRENT_LINE|TM_CURRENT_WORD|TM_LINE_INDEX|TM_LINE_NUMBER|TM_FILENAME_BASE|TM_FILENAME|TM_DIRECTORY|TM_FILEPATH|RELATIVE_FILEPATH|CLIPBOARD|WORKSPACE_NAME|WORKSPACE_FOLDER|CURRENT_YEAR_SHORT|CURRENT_YEAR|CURRENT_MONTH_NAME_SHORT|CURRENT_MONTH_NAME|CURRENT_MONTH|CURRENT_DATE|CURRENT_DAY_NAME_SHORT|CURRENT_DAY_NAME|CURRENT_HOUR|CURRENT_MINUTE|CURRENT_SECONDS_UNIX|CURRENT_SECOND|RANDOM|RANDOM_HEX|UUID|BLOCK_COMMENT_START|BLOCK_COMMENT_END|LINE_COMMENT))(?(1)(?(2)[:].+|[/].+[/].*[/])})",

Test in VSCode

enter image description here

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.