I have written a VSCode snippet that makes two substitutions to the clipboard content.
For instance, this snippet changes "a" characters into "x" and "e" characters into "y"
"t2": {
"prefix": "t2",
"body": [
"${CLIPBOARD/(a)|(e)/${1:?x:y}/g}"
],
"description": "Makes two substitutions to the clipboard"
},
Using this snippet, if I cut the text "This snippet changes the clipboard" and I execute the snippet, the pasted text is "This snippyt chxngys thy clipboxrd".
My question is: Is it possible to create a snippet that applies three substitutions? For instance, "a" into "x", "e" into "y" and "i" into "z", obtaining "Thzs snzppyt chxngys thy clzpboxrd" in the example above.
Yes, you can change as many as you want. I made this snippet for another answer:
"color conditional": {
"prefix": "_hex",
"body": [
"let color = '${1};",
"let hex = '${1/(white)|(black)|(red)/${1:+#fff}${2:+#000}${3:+#f00}/}';" //works
],
"description": "conditional color"
},
See vscode if/else conditions in user defined snippet.
for one example but in your case try:
"${CLIPBOARD/(a)|(e)|(i)/${1:+x}${2:+y}${3:+z}/g}"
instead of using the if/else conditional, you can use any number of if's.
Related
In Visual Studio Code, in the "settings.json" file, I am editing a color theme, and need a way to describe the property for triple quoted strings seen in functions as comments:
"editor.tokenColorCustomizations": {
"[Starfall Palenight]": {
"comments": "#82bdd1",
"strings": "#75ec9d"
}
},
The attempt to use "comments" fails, as this property only applies to real comments, and "strings" only affects normal strings.
An example of what my desired comment would look like is shown below:
def func():
'''this is the comment explaining how the function works'''
pass
Thank you
My file name: company-news-model.js
I want it to become company_news;
If you must have it in a snippet, try this:
"filePath to snake": {
"prefix": "2Snake",
"body": [
"${TM_FILENAME_BASE/-([^-]*)(?=-)|(-.*)$/${1:+_}$1/gm}"
// gm regex flags are both necessary
// just put a ; at the end (before the closing quote) if you want one there
]
}
It will work on any length fileName, like a-b-c-d.js, etc.
Using your example file: company-news-model.js
TM_FILENAME_BASE : company-news-model
-([^-]*)(?=-) : matches -news only, capture group 1
(-.*)$ : match the end of the name, -model in group 2, which we won't use in the replacement
Note that company is never matched, you don't need to as long as it is acceptable to have it in the final result, which it is.
Replacement transform :
${1:+_} : this means if there is a group 1, insert an _
$1 : insert group 1
So company falls through since it is never matched, followed by an _ and group 1. Then because it is a global regex, add anymore _ and group 1's that are found.
Note that files like company-news-model.component.js will be converted to company_news as I think would be expected.
A more robust approach can convert any case fileName to kebab-case - but it would be a keybinding and not a snippet. And you will need the extension Find and Transform (written by me).
Make this keybinding (in your keybindings.json):
{
"key": "alt+s", // whatever keybinding you want
"command": "findInCurrentFile",
"args": {
// inserted at the cursor(s), if cursor is not in or against a word
"replace": "${fileBasenameNoExtension}",
"postCommands": ["editor.action.transformToKebabcase", "cancelSelection"]
},
}
The fileBasenameNoExtension is inserted, selected, and then the command editor.action.transformToKebabcase is run on it.
I'm trying to make a custom syntax highlighter for my own markup language. All the examples are complicated, missing steps and are very, very hard to understand.
Is there anything that fully documents how to make a syntax highlighter?
(for VSCode, by the way)
For example, this video https://www.youtube.com/watch?v=5msZv-nKebI which has an extremely large skip in the middle and doesn't really explain much.
My current code, made with Yeoman generator is:
{
"$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json",
"name": "BetterMarkupLanguage",
"patterns": [
{
"include": "#keywords"
},
{
"include": "#strings"
}
],
"repository": {
"keywords": {
"patterns": [{
"name": "entity.other.bml",
"match": "\\b({|}|\\\\|//)\\b"
}]
},
"strings": {
"name": "string.quoted.double.bml",
"begin": "`",
"end": "`"
}
},
"scopeName": "source.bml"
}
Synopsis
I'm not sure at what level you're approaching the problem, but there are basically two kinds of syntax-highlighting:
Just identify little nuggets of canonically identifiable tokens (strings, numbers, maybe operators, reserved words, comments) and highlight those, OR
Do the former, and also add in context awareness.
tmLanguage engines basically have two jobs:
Assign scopes.
Maintain a stack of contexts.
Samples
Lets say you make a definition for integers with this pattern:
"integers": {
"patterns": [{
"name": "constant.numeric.integer.bml",
"match": "[+-]\\d+"
}]
},
When the engine matches an integer like that, it will match to the end of the regex, assign the scope from "name", and then continue matching things in this same context.
Compare that to your "strings" definition:
"strings": {
"name": "string.quoted.double.bml", // should be string.quoted.backtick.bml
"begin": "`",
"end": "`"
},
Those "begin" and "end" markers denote a change in the tmLanguage stack. You have pushed into a new context inside of a string.
Right now, there are no matches configured in this context, but you could do that by adding a "patterns" key with some "match"es or "include"s. "include"s are other sets of matches like "integers" that you've defined elsewhere. You can add it to the "strings" patterns to match integers inside strings. Matching integers might be silly, but think about escaped backticks: You want to scope those and stay in the same context within "strings". You don't want those popping back out prematurely.
Order of operations
You'll eventually notice that the first pattern encountered is matched. Remember the integers set? What happens when you have 45.125? It will decide to match the 45 and the 125 as integers and ignore the . entirely. If you have a "floats" pattern, you want to include that before your naïve integer pattern. Both these "numbers" definitions below are equivalent, but one lets you re-use floats and integers independently (if that's useful for your language):
"numbers": {
"patterns": [
{"include": "#floats"},
{"include": "#integers"}
]
},
"integers": {
"patterns": [{
"name": "constant.numeric.integer.bml",
"match": "[+-]\\d+"
}]
},
"floats": {
"patterns": [{
"name": "constant.numeric.float.bml",
"match": "[+-]\\d+\\.\\d*"
}]
},
"numbers": {
"patterns": [{
"name": "constant.numeric.float.bml",
"match": "[+-]\\d+\\.\\d*"
}, {
"name": "constant.numeric.integer.bml",
"match": "[+-]\\d+"
}]
},
Doing it right
The "numbers"/"integers"/"floats" thing was trivial, but well-designed syntax definitions will define utility groups that "include" equivalent things together for re-usability:
A normal programming language will have things like
A "statements" group of all things that can be directly executed. This then may or may not (language-dependent) include...
An "expressions" group of things you can put on the right-hand-side of an assignment, which will definitely include...
An "atoms" group of strings, numbers, chars, etc. that might also be valid statements, but that also depends on your language.
"function-definitions" probably won't be in "expressions" (unless they are lambdas) but probably would be in "statements." Function definitions might push into a context that lets you return and so on.
A markup language like yours might have
An "inline" group to keep track of all the markup one can have within a block.
A "block" group to hold lists, quotes, paragraphs, headers.
...
Though there is more you could learn (capture groups, injections, scope conventions, etc.), this is hopefully a practical overview for getting started.
Conclusion
When you write your syntax highlighting, think to yourself: Does matching this token put me in a place where things like it can be matched again? Or does it put me in a different place where different things (more or fewer) ought to be matched? If the latter, what returns me to the original set of matches?
I'm trying to implement support for a new language in VS Code, using a tmGrammar json file. In this language variables start with !, and there is a special reserved variable called !this in this language.
I want to apply one class to all common variables and other for the !this variable. I'm doing this in my json file:
"repository": {
"keywords": {
"patterns": [
{
"name": "constant.character",
"match": "(?i)\\b(!this)\\b"
},
{
"name": "variable.other",
"match": "(?i)\\![a-z0-9]+"
},
}
}
But this is coloring both !this and !someVar to the same color.
If I change the first rule to (?i)\\b(this)\\b, without the ! the word this get colored correctly.
I also tried do change the order of the rules, but now matter what I do makes !this the same color as common variables.
Is there a problem with the first regular expression?
I am trying to match errors of this format generated by an IAR ARM compiler for the VSCode ProblemMatcher...
"d:\test\helloWorld.c",646 Warning[Pe223]:
function "printf" declared implicitly
With regex101.com I am able to match the first line message with this regex...
^"(.*)",(\d+)\s+((Warning|Error)\[Pe\d+\]):$
Alas, when put into my tasks.json file with the correct escape slashes. The vscode prompts that error in task.json. error in task.json
"problemMatcher": {
"owner": "cpp",
"fileLocation": "absolute",
"pattern": [
// The regular expression for IAR ARM compiler. Example to match:
// "d:\test\helloWorld.c",646 Warning[Pe223]:
// function "printf" declared implicitly
{
"regexp": "^"(.*)",(\\d+)\\s+((Warning|Error)\\[Pe\\d+\\]):$",
// The first match group matches the file name which is relative.
"file" : 1,
// The second match group matches the line on which the problem occurred.
"location": 2,
// The third match group matches the message
"message" : 3,
// The fourth match group matches the problem's severity. Can
// be ignored. Then all problems are captured as errors.
"severity": 4
},
{
// The next line matches the message.
"regexp": "^([^\\s].*)$",
"message": 1
}
]
}
Then, I removed the "", and it became,
^(.*),(\\d+)\\s+((Warning|Error)\\[Pe\\d+\\]):$
At last, I receive output in the Problems tab after running the task that will generate these errors in the terminal of VSCode. The warning message and line number are correct. But the file does not match, and can't jump to file.
OK, I found the answer from https://learn.microsoft.com/en-us/visualstudio/ide/using-regular-expressions-in-visual-studio
\" Match a double quotes
So the correct regexp is,
"regexp": "^\"(.+?)\",(\\d+)\\s+((Warning|Error)\\[Pe\\d+\\]):$",