I'm trying to create a snippet that creates a class name based on the file path. If the file is named index.js, I'd like the class name to take the folder name. Otherwise, use the file name.
I've got a transform (shown below) that is currently working if the file is named index.js (it correctly inserts the folder name).
How would I expand on this (assuming it's even possible) to also work for the second case?
I did notice from the VSCode documentation that there are some basic if/else formats that you can use, which will only insert the given text if a capture group exists. I have been able to get those working with some simple examples. But not sure if these can be used in some way to accomplish what I'm trying to do.
Current snippet:
{
"mySnippet": {
"prefix": "cls",
"body": [
"class ${TM_FILEPATH/[\\/\\w$]+\\/(?!index)|\\/index.js//g} {}",
"export default ${TM_FILEPATH/[\\/\\w$]+\\/(?!index)|\\/index.js//g};"
]
},
}
3 Answers 3
I suggest using
${TM_FILEPATH/.*[\\/\\\\]([^\\/\\\\]+)[\\/\\\\]index\\.js$|.*[\\/\\\\](.*)/1ドル2ドル/}
If you do not want to include the file extension to the output use
${TM_FILEPATH/.*[\\/\\\\]([^\\/\\\\]+)[\\/\\\\]index\\.js$|.*[\\/\\\\](.*?)(?:\\.[^.]*)$/1ドル2ドル/}
The regex #1 will work as shown here or regex #2 here, see its graph:
The point here is to use two alternatives separated with | alternation operator that will match the whole string while capturing the parts you need, making sure the more specific (with the known file name) alternative comes first, and the more generic one (that will match any file name, will come last. The replacement pattern will be two backreferences, 1ドル2ドル, since only one will actually contain some text after a match has been found.
Regex details
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.
.*[\/\\]([^\/\\]+)[\/\\]index\.js$:.*- any 0+ chars other than line break chars, as many as possible[\/\\]- a/or\([^\/\\]+)- Capturing group 1: one or more (+) chars other than/and\([^...]is a negated character class)[\/\\]- a/or\index\.js- anindex.jssubstring$- end of string
|- or.*[\/\\](.*):.*- any 0+ chars other than line break chars, as many as possible[\/\\]- a/or\(.*)- Capturing group 2: any 0+ chars other than line break chars, as many as possible(.*?)(?:\.[^.]*)?$- will capture into Group 2 any 0 or more chars other than line break chars, as few as possible, and then will try to match an optional sequence of.and 0+ non-dot chars up to the end of the string ($).
So, the full code snippet will look like
{
"mySnippet": {
"prefix": "cls",
"body": [
"class ${TM_FILEPATH/.*[\\/\\\\]([^\\/\\\\]+)[\\/\\\\]index\\.js$|.*[\\/\\\\](.*?)(?:\\.[^.]*)$/1ドル2ドル/} {}",
"export default ${TM_FILEPATH/.*[\\/\\\\]([^\\/\\\\]+)[\\/\\\\]index\\.js$|.*[\\/\\\\](.*?)(?:\\.[^.]*)$/1ドル2ドル/};"
]
}
}
Feel free to adjust it as you want.
Comments
@Wiktor will add the correct answer later but I wanted to say something about those conditionals in vscode's variable transforms that is too long for a comment.
It would be very nice is if you could do something like this:
"${TM_FILEPATH/.*\\(.+)\\((index\\.js)|(.*))/${3:?1ドル:2ドル}}/g}",
a conditional if group 3 isn't empty insert group 1 (the parent directory) else insert group 2 (the filename). But that doesn't work although the regex is fine (albeit simplified re: path separators and the file extension here).
Unfortunately, while a "plain" conditional does work very nicely:
${3:?There is an index.js file:There is not an index.js file}
it appears that using regex groups within the conditional text replacement is not supported. This would seem to follow from the grammar link (see snippet grammar]1. Looking at this part about conditionals:
'${' int ':?' if ':' else '}'
I would say captured groups within the conditional if/else portions are not supported. It does not explicitly seem to allow capture groups - only if/else plain text.
Comments
With Wiktor's regex mastery in the comments, combined with the documentation, further insights from Mark, and a few additional adjustments (in the way that regex capture groups are replaced/transformed, because of VSCode transform limitations), I was finally able to put together a working solution.
{
"mySnippet": {
"prefix": "cls",
"body": [
"class ${TM_FILEPATH/(.*[\\/\\\\])([^\\/\\\\]+)([\\/\\\\]index\\.[jt]s$)|(.*[\\/\\\\])(.*)(\\.[jt]s)/${2}${5}/} {}",
"export default ${TM_FILEPATH/(.*[\\/\\\\])([^\\/\\\\]+)([\\/\\\\]index\\.[jt]s$)|(.*[\\/\\\\])(.*)(\\.[jt]s)/${2}${5}/};"
]
}
}
1 Comment
Explore related questions
See similar questions with these tags.
index.jsis inc:\Users\wiktor\Documents\index.jsthe class should beDocuments? What if it isC:\index.js?${TM_FILEPATH/.*[\\/\\\\]([^\\/\\\\]+)[\\/\\\\]index\\.js$|.*[\\/\\\\](.*)/1ドル2ドル/}. Note I added both/and\path separators.