Am I understanding this VS Code API behavior correctly? Non-default *object* settings (when provided) are always merged? - visual-studio-code

I'm working on a VS Code Extension, and I think maybe I'm missing something in the docs, or else the behavior I'm seeing just isn't specified there, and my assumptions are wrong...?
I've defined some default settings for my extension, like so...
package.json
"contributes": {
"configuration": {
"title": "ToggleSettingsChanges",
"properties": {
"toggleSettingsChanges.settingsToToggle": {
"scope": "resource",
"type": "object",
"default": {
"window.zoomLevel": 2,
"editor.fontSize": 22,
"terminal.integrated.fontSize": 16,
"scm.diffDecorations": "none",
"workbench.statusBar.visible": false,
"editor.cursorBlinking": "solid",
"workbench.activityBar.visible": false
},
"description": "[ snip ]"
}
}
}
},
extension.js
// In the "main" method that runs when a command is activated:
const config = vscode.workspace.getConfiguration("toggleSettingsChanges");
const settingsToToggle = config.get("settingsToToggle");
const inspectedSettingsToToggle = config.inspect("settingsToToggle");
console.log("settingsToToggle:", JSON.stringify(settingsToToggle), "\n\n")
console.log("inspected settingsToToggle:", JSON.stringify(inspectedSettingsToToggle), "\n\n")
return;
In the Extension Host instance, I can tweak and adjust the settings, to include this:
User or Workspace Settings JSON
// ...
"toggleSettingsChanges.settingsToToggle": {
"editor.fontSize": 11,
"pumpkins_are_great": true
},
In the console output, I'm seeing the following:
settingsToToggle: {"window.zoomLevel":2,"editor.fontSize":11,"terminal.integrated.fontSize":16,"scm.diffDecorations":"none","workbench.statusBar.visible":false,"editor.cursorBlinking":"solid","workbench.activityBar.visible":false,"pumpkins_are_great":true}
inspected settingsToToggle: {"key":"toggleSettingsChanges.settingsToToggle","defaultValue":{"window.zoomLevel":2,"editor.fontSize":22,"terminal.integrated.fontSize":16,"scm.diffDecorations":"none","workbench.statusBar.visible":false,"editor.cursorBlinking":"solid","workbench.activityBar.visible":false},"globalValue":{"editor.fontSize":11,"pumpkins_are_great":true}}
For the settingsToToggle line, I expected to see only the following settings:
{"editor.fontSize":11,"pumpkins_are_great":true}
It seems that if you provide an object default, any configuration provided is merged with that object, instead of replacing it entirely.
Is that the case? Have I missed this in the documentation?
It seems to me that a value (even an object) would be overwritten, and not simply merged.

The documentation may have been updated since this question was posted. The way it's written now, seems pretty clear to me. I'm writing because I feel I have found a discrepancy in the API, which may help out the OP.
Reference
Note: Only object value types are merged and all other value types are overridden.
-- VS Code API - WorkspaceConfiguration
Additional information
I want my default values to be merged with the user settings, as is described above. I was confused by seeing my defaults overriden. This question helped me understand what is happening. I'll share my approach since OP may be interested. My observations:
Default values provided in package.json are merged with user settings, as described in the documentation (link above).
Default values passed programmatically with WorkspaceConfiguration.get(section, defaultValue) do not exhibit the merging behavior. It's not clear if this is intentional or not. Update: this behavior is working as intended, reference #105598.

Related

How to add a new match/mapping for an existing language?

Thanks to an extension (Caddyfile Syntax, Caddyfile Support) I have highlighting for Caddyfile. Installing the extensions also mapped Caddyfile files with the relevant syntax highlighting rules.
I now would like to also have the same mapping for caddy.conf files.
According to the documentation, I should add an alias for caddy.conf so that it is handled the same way as Caddyfile.
The problem is that I do not know where to add this information in settings.json.
I had a look for anything "caddy" in defaultSettings.json but I do not see any structure that would match th eone in the documentation. Namely, I only see
// Configure settings to be overridden for the caddyfile language.
"[caddyfile]": {
"editor.insertSpaces": false,
"editor.formatOnSave": true
},
What I am looking for should more look like (according to the documentation above)
"languages": [{
"id": "java",
"extensions": [ ".java", ".jav" ],
"aliases": [ "Java", "java" ]
}]
So in practical terms - where in setting.json should I add the alias (or possibly a new mapping)?
Try adding this to your settings.json:
"files.associations": {
"*.conf": "caddyfile"
}
Alternatively, you can invoke the workbench.action.editor.changeLanguageMode command (Ctrl+K M by default, also works by clicking the language label in the status bar) and select the language you want. This is probably preferable if you might have files with the same extension, but different syntax.

VS Code extension: setting custom semantic token colors

Is it possible to modify the styling of semantic token modifiers received from LSP
inside an extension without the need to create custom themes?
I am able to use editor.semanticTokenColorCustomizations in my settings.json file and add the custom rules I want, but this setting is not available for configurationDefaults in the package.json file for a VS Code extension.
So the following snippet does work in settings.json, while the same does not work in package.json for an extension under the configurationDefaults field.
"editor.semanticTokenColorCustomizations": {
"enabled": true,
"rules": {
"*.declaration": {
"bold": true
},
"*.definition": {
"italic": true
},
"*.readonly": "#ff0000"
}
}
Is there another way?
Ideally, I would like to change both token types and token modifiers
for the language I introduce with the extension, but I don't want to create custom themes a user would need to use to get proper highlighting.
Note: I am forced to stick with the token types and modifiers supported by the language-client provided by Microsoft. Those are defined in the LSP specification.
Edit: I use LSP with semantic tokens to get the token types and modifiers of a file. This should be similar to using TextMate grammar.
The problem I have, is applying correct styling/highlighting to those tokens. Since the language client limits the usable tokens, I apply a mapping between tokens of my language and the default LSP ones.
Meaning: token modifier declaration is in fact bold in my markup language
You can introduce all your custom semantic tokens without the need to restrict yourself to the built-in ones. Personally I prefer the way proposed in the official sample file:
semantic-tokens-sample.
As for the styling, you can easily modify an extension incl. semantic token colors via the package.json file as follows.
{
...
"editor.semanticHighlighting.enabled": true, // not necessary, just make sure it is not disabled
"contributes": {
"semanticTokenTypes": [ // not necessary if you use own parsing with "DocumentSemanticTokensProvider"
{
"id": "myToken",
"superType": "myToken",
"description": "myToken"
}
],
"configurationDefaults": {
"editor.semanticTokenColorCustomizations": {
"rules": {
"comment": "#969896",
"string": "#B5BD68",
"myToken": "#323232" // custom
}
}
}
}
}
For that I personally introduced myToken in the legend in an extension.ts file.
To check if your semantic token logic is working, you can use the
[view/Command Palette/>Developer: Inspect Editor Tokens ans Scopes] functionality that will reveal what semantic scope is attached to your keyword, if any.
If the provided code is not working for you, check your package.json and make sure the language settings are all correct:
settings that could be of relevance for you:
{
...
"activationEvents": ["onLanguage:myLanguage"], // make sure your extension is activated
"contributes": {"languages": [{"id": "myLanguage", "extensions": [".myLang"], "configuration": "./language-configuration.json"}]}
}
Furthermore check if your User / Workspace settings are interfering with your package.json settings.

VSCode editor.semanticTokenColorCustomizations setting doesn't apply

No matter what I've tried, nothing is being applied to the color customizations. What am I missing? This really shouldn't be as complicated as it is.
The below snippet is just the latest attempt. I've tried 20 other variations of this, along with various themes, not specifying a theme, this ridiculous enabled property in both scopes or not. I've tried different rule properties, based on the Textmate scopes, ones that aren't defined, others that are.
I've restarted VSCode maybe 50x through this process as well.
These settings are being applied on the user settings.json. There is no other matching definition in the workspace, or the same user settings file.
"editor.semanticHighlighting.enabled": true,
"editor.semanticTokenColorCustomizations": {
"enabled": true,
"[Tomorrow Night]": {
"enabled": true,
"rules": {
"storage.type.class.php": {
"foreground": "#333333"
}
}
}
},

How do I create a custom Semantic Token for VSCode?

I'm creating a color theme and I found out that the only way to target function parameters with italic is by using semantic highlight. The problem is that since semantic highlight overrides some settings, I lost the ability to target support.function.console - the "log" of console.log, for instance.
.log is a member.defaultLibrary, but if I target that by semantic, some other things would also be styled with the same color. That wouldn't be bad if member.defaultLibrary wasn't so inconsistent, some things you would expect to be styled, is not, which leads to inconsistency, which is certainly not desirable.
querySelector() is styled by member.defaultLibrary but not querySelectorAll(), for instance. I also tried to not use anything that can be overridden by semantics but then, it creates too many exceptions and some functions and methods would be let without any style, which is much worse.
I've tried Semantic Token Classification and tried to add a custom semantic token to the package.json file of the extension but I don't know how to "wire" that up:
{
"contributes": {
"semanticTokenTypes": [
{
"id": "consoleSupport",
"description": "console support"
}
],
"semanticTokenScopes": [
{
"scopes": {
"consoleSupport": ["support.function.console"]
}
}
]
}
}
When using development host, it does recognize the "new" consoleSupport when I try to add to "semanticTokenColors", it suggests the auto-complete, so I'm probably half-way there but I don't know how to actually create the new token and how to make it work.

How can I configure multiple formatters to run in a sequence on save in VSCode?

I am working on a Haskell project that must be formatted by both:
stylish-haskell (for import reordering)
brittany (for general formatting)
I can set the single default formatter for a language:
"[haskell]": {
"editor.defaultFormatter": "MaxGabriel.brittany"
}
or I can select one from a list using editor.action.formatDocument.multiple ("Format Document With... in the command palette).
But I need to run both of them, one after the other, on save. As of right now, I can only run the single default formatter on save. The order doesn't matter in this case, but it could in more general cases.
I've tried setting editor.defaultFormatter to a list of formatters (this didn't work, as expected) and built a local extension that calls editor.action.formatDocument.multiple with various arguments, which just brings up a drop-down list of available formatters to choose from.
How can I run both formatters sequentially on save?
I don't think this is really a use case that is officially supported, but you could possibly work around it by having an extension do the following:
disable "editor.formatOnSave" for Haskell
register a callback for vscode.workspace.onDidSaveTextDocument, in which you:
set "editor.defaultFormatter" to the first formatter using the WorkspaceConfiguration API
call "editor.action.formatDocument"
set "editor.defaultFormatter" to the second formatter
call "editor.action.formatDocument" again
Of course, this only covers formatOnSave formatting, not formatOnPaste or formatOnType.
It's a bit late but, for newcomers, you can also use one extension that is already created... and it's thanks to all the answers of this post, by the way.
See Multi Formatter
So you can just add the formatters you want to run in the settings.json or the *.code-workspace settings like this:
{
"[haskell]": {
"editor.defaultFormatter": "Jota0222.multi-formatter",
"editor.formatOnSave": true
"multiFormatter.formatterList": [
"vigoo.stylish-haskell",
"MaxGabriel.brittany"
],
}
}
With that configuration, stylish-haskell will run first and Britanny will run just after once you save the changes.
P.S.: I'm indeed the author of the solution. I'm not aiming to do any promotion, it's just an implementation of the answers above. So I'll like to thank the people that answered before me.
Also, the extension is open sourced, feel free to check the code and contribute on GitHub
Last thoughts: look at Run on Save extension and execute your formatters not as extensions but as scripts.
Previous edit:
If your formatter doesn't contribute a command (see discussion in comments for some that do) as it appears brittany does not, try something like this for its task:
{
"label": "brittany format step",
"type": "shell",
"command": "brittany ${file}",
"problemMatcher": []
}
From Gama11's answer of creating a VSCode extension:
The following code specifies the formatter and then formats the code.
const config = vscode.workspace.getConfiguration('editor', vscode.window.activeTextEditor?.document);
await config.update('defaultFormatter', 'MaxGabriel.brittany');
await vscode.commands.executeCommand('editor.action.formatDocument');
Therefore, the answer is:
const config = vscode.workspace.getConfiguration('editor', vscode.window.activeTextEditor?.document);
const formatters = ['MaxGabriel.brittany', 'ms-python.python'];
formatters.forEach(async formatter => {
await config.update('defaultFormatter', formatter);
await vscode.commands.executeCommand('editor.action.formatDocument');
});