3

I tried to create a snippet in VSCode to quickly include C++ header guards. For example with a file path is C:\workspace\src\chrome\browser\ui\webui\settings\about_handler.h

The snippet is expected to generate like this:

#ifndef CHROME_BROWSER_UI_WEBUI_SETTINGS_ABOUT_HANDLER_H_
#define CHROME_BROWSER_UI_WEBUI_SETTINGS_ABOUT_HANDLER_H_

#endif // CHROME_BROWSER_UI_WEBUI_SETTINGS_ABOUT_HANDLER_H_

From VScode snippet syntax guide, I tried to use TM_FILEPATH variable but cannot find a solution to transform the filepath into the macros above. I tried some way below:

  • with the transform ${TM_FILEPATH/([^a-zA-Z0-9])|([a-zA-Z0-9])/${1:+_}${2:/upcase}/g}_ I can generate the filepath into C__WORKSPACE_SRC_CHROME_BROWSER_UI_WEBUI_SETTINGS_ABOUT_HANDLER_H_. This regex will convert all non-digit and non-alphabetic characters to _ and change all alphabetic characters to upper case.
  • with the transform ${TM_FILEPATH/.*src[\\\\\\/](.*)/${1:/upcase}/} I can generate into CHROME\BROWSER\UI\WEBUI\SETTINGS\ABOUT_HANDLER.H. This regex remove the path from begining to src since my current workspace is in src folder so I want my header macro to be related to that.

The problem is I cannot combine these two transform to get the macro I want. Is there any ideas to make it works?

JHBonarius
  • 10,824
  • 3
  • 22
  • 41
Justin
  • 149
  • 1
  • 11

2 Answers2

8

You can use

"CppGuard": {
        "prefix": "cppgrd",
        "body": [
          "#ifndef ${TM_FILEPATH/(?:^.*\\\\src\\\\)?(\\w+)(?!\\w*$)|(\\W)|(\\w+)$/${1:/upcase}${2:+_}${3:/upcase}${3:+_}/g}",
          "#define ${TM_FILEPATH/(?:^.*\\\\src\\\\)?(\\w+)(?!\\w*$)|(\\W)|(\\w+)$/${1:/upcase}${2:+_}${3:/upcase}${3:+_}/g}",
          "\n#endif // ${TM_FILEPATH/(?:^.*\\\\src\\\\)?(\\w+)(?!\\w*$)|(\\W)|(\\w+)$/${1:/upcase}${2:+_}${3:/upcase}${3:+_}/g}"
        ]
      }

The command is

${TM_FILEPATH/(?:^.*\\\\src\\\\)?(\\w+)(?!\\w*$)|(\\W)|(\\w+)$/${1:/upcase}${2:+_}${3:/upcase}${3:+_}/g}"

enter image description here See the regex demo.

Details

  • (?:^.*\\src\\)?(\w+)(?!\w*$) - an optional occurrence of any zero or more chars other than line break chars as many as possible from the start of string (^.*), up to the \src\ substring (\\src\\), then one or more word chars captured into Group 1 ((\w+)), that are not followed with end of string ((?!\w*$))
  • | - or
  • (\W) - Group 2: any non-word char
  • | - or
  • (\w+)$ - Group 3: one or more word chars at the end of string.

The replacement means:

  • ${1:/upcase} - inserts Group 1 value turned to uppercase
  • ${2:+_} - if Group 2 was matched, insert a _
  • ${3:/upcase} - inserts Group 3 value in upper case
  • ${3:+_} - if Group 3 matched, inserts a _.
Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563
1

Try this:

"cppHeaderGuard": {
  "prefix": "g1",
  "body": [
    "#ifndef ${TM_FILEPATH/(?:^.*\\\\src\\\\)?(\\w+)\\W?/${1:/upcase}_/g}",
    "#define ${TM_FILEPATH/(?:^.*\\\\src\\\\)?(\\w+)\\W?/${1:/upcase}_/g}",
    "",
    "#endif // ${TM_FILEPATH/(?:^.*\\\\src\\\\)?(\\w+)\\W?/${1:/upcase}_/g}"
  ]
}

cppGuard snippet demo

The trick is to get everything you are interested in, the text between the path separators and the final ., into one capture group if you can. That is pretty easy in your case using a non-capturing group and a final bit that isn't captured:

(?:^.*\\\\src\\\\)?(\\w+)\\W?

But you do want all that matched so that vscode's snippet engine will replace it. In this case, the replacement is dead simple:

${1:/upcase}_

Every full match, like chrome\ will be replaced by capture group 1, e.g., chrome, capitalized and an underscore.

Since you actually want an underscore at the end that makes it easy too - you don't need any conditional logic to determine whether there is a capture group at the very end that shouldn't be followed by an underscore.

Mark
  • 143,421
  • 24
  • 428
  • 436
  • I did not use `(?:^.*\\src\\)?(\w+)\W?` pattern on purpose (I certainly tested it, too). This pattern assumes there are no consecutive special characters which is usually true for this kind of input, but still we cannot be too sure of it. I decided to keep my pattern as generic as possible. – Wiktor Stribiżew Dec 05 '20 at 21:36
  • Ahh, then as usual the nature of the input, in this case a file path, will determine what special cases need to be considered. – Mark Dec 05 '20 at 22:19