In our project we have a number of files where tabs are strictly required (a format we do not control). However, we want to normalize tabs to spaces throughout the rest of the project.
For now, I just ask that people don't edit those files in VSCode. I even considered adding them to the ignore list for VSCode itself. But it's not uncommon to have file-specific settings, so I thought it would be nice if VSCode allowed for more complex patterns - much like files.exclude, perhaps something like:
"editor.insertSpaces": true,
"diffEditor.ignoreTrimWhitespace": true,
"files.settings": {
"**/*.idt": {
"editor.insertSpaces": false,
"diffEditor.ignoreTrimWhitespace": false
}
}
:+1:
It's a nice idea but maybe It's a better idea to use an array instead of a map of globbing patterns. The order in which you specify the rules matter because what should be done in this case?
"files.settings": {
"**/*.idt": {
"editor.insertSpaces": false,
"diffEditor.ignoreTrimWhitespace": false
},
"**/file.idt": {
"editor.insertSpaces": true,
"diffEditor.ignoreTrimWhitespace": true
},
}
Maps don't keep their order so the result in this case is not known untill you test it. If **/*.idt is executed after **/file.idt, there is no way to specify other rules for file.idt.
When using an array, the order is kept and you know the outcome of the following settings.
"files.settings": [
{
"files": ["**/*.idt", "**/*.json"],
"editor.insertSpaces": false,
"diffEditor.ignoreTrimWhitespace": false
},
{
"files": "**/index.idt",
"editor.insertSpaces": true,
"diffEditor.ignoreTrimWhitespace": true
}
]
This way, you know for sure that index.idt will have the setting editor.insertSpaces: true.
We had a similar discussion in the XO linter for overridable configs. More information can be found here https://github.com/sindresorhus/xo/pull/58
adding to @SamVerschueren's idea, the pattern should conform to a DocumentSelector, and the entries should be ranked by languages.match
This would also help with editing patch files. Gets tiring accidentally bricking them because of the trailing space on empty lines :(
Also nice for word wrapping in markdown or HTML files, but not code. A great improvement for developers who write a lot.
Following is the proposal for introducing file (glob pattern) / language based editor settings.
Defining a new setting called workbench.editor.overrideSettings or workbench.overrideEditorSettings and its schema is as follows:
{
"workbench.editor.showTabs": true
"workbench.editor.overrideSettings": [
{
"files": [
"**/*.idt",
"**/*.json"
],
"editor.insertSpaces": false,
"diffEditor.ignoreTrimWhitespace": false
},
{
"files": "**/index.idt",
"editor.insertSpaces": true,
"diffEditor.ignoreTrimWhitespace": true
},
{
"language": "markdown",
"editor.wordWrap": 0
}
]
}
@Microsoft/vscode Please provide your feedback and suggestions.
Thanks
Looks good to me.
As a sidenote to everyone reading this topic, much of this already can be done with the EditorConfig plugin which in my opinion is a better alternative when working in teams. I agree, not everything is possible with EditorConfig, but if it's possible, then I suggest using that instead.
Here is a little bit different suggestion (variant of yours):
{
"workbench.editor.showTabs": true,
"editor.overrides": [
{
"files": [
"**/*.idt",
"**/*.json"
],
"settings": {
"editor.insertSpaces": false,
"diffEditor.ignoreTrimWhitespace": false
}
}
{
"files": "**/index.idt",
"settings": {
"editor.insertSpaces": true,
"diffEditor.ignoreTrimWhitespace": true
}
},
{
"language": "markdown",
"settings": {
"editor.wordWrap": 0
}
}
]
}
Difference:
editor.overrides because in most situations the settings would only apply when you open an editor with a specific file or language mode set and would not apply in other contextssettings node to be able to distinguish the actual context the setting applies to (files or language) from the actual settings. I call it editor.overrides because in most situations the settings would only apply when you open an editor with a specific file or language mode set and would not apply in other contexts
Yeah agreed that override settings are for editor only. But I think this editor.overrides is not an editor setting, instead it is a setting from workbench to override editor settings based on file or language mode. Hence, I called it workbench.editor.overrides.
I introduce an extra settings node to be able to distinguish the actual context the setting applies to (files or language) from the actual settings. 👍
The design of our settings is that they are all key-value where the value if preferable a literal or an object. That way settings defined in the user settings can be selectively replaced and overwritten by workspace settings. With the suggested form this won't be possible, one always have to replace the full array of overrides.
The second problem is that the suggested format will not allow the user to group the settings for the same file extension together, e.g. all overrides for *.ts.
I'd favour the following form:
"editor.overrides": {
"*.ts": {
"editor.insertSpaces": false,
"diffEditor.ignoreTrimWhitespace": false
},
"*.json": {
}
}
Said that, I also think given that EditorConfig is already very popular, I think we should maybe not build our own story but try to build on EditorConfig and extend it with our own settings.
Using an object would not work as per my comment at the top https://github.com/Microsoft/vscode/issues/1587#issuecomment-169942924. This is because a map does not keep its order which in this case is very important.
We have the same problem with the file.exclude settings. Not sure what approach we chose there, @bpasero ?
It is random. What we should maybe rather do is leverage the fact that we have a custom JSON parser and preserve the order. If we can keep the order, I am fine with the less verbose form 👍
It would also be possible to merge user settings and workspace settings by the files or language property in each object in the array.
{
"workbench.editor.showTabs": true,
"editor.overrides": [
{
"files": [
"**/*.idt",
"**/*.json"
],
"settings": {
"editor.insertSpaces": false,
"diffEditor.ignoreTrimWhitespace": false
}
},
{
"files": "**/index.idt",
"settings": {
"editor.insertSpaces": true,
"diffEditor.ignoreTrimWhitespace": true
}
},
{
"language": "markdown",
"settings": {
"editor.wordWrap": 0
}
}
]
}
{
"editor.overrides": [
{
"files": "**/index.idt",
"settings": {
"editor.insertSpaces": false
}
}
]
}
Which would result in the following
{
"workbench.editor.showTabs": true,
"editor.overrides": [
{
"files": [
"**/*.idt",
"**/*.json"
],
"settings": {
"editor.insertSpaces": false,
"diffEditor.ignoreTrimWhitespace": false
}
},
{
"files": "**/index.idt",
"settings": {
"editor.insertSpaces": false,
"diffEditor.ignoreTrimWhitespace": true
}
},
{
"language": "markdown",
"settings": {
"editor.wordWrap": 0
}
}
]
}
I'm just throwing ideas here :).
@SamVerschueren Agreed that it is possible to merge overridden settings with the array structure. At the same time, we would also want a simple structure. Since we have a custom json parsing from which we can always make the order consistent, the short forms makes sense to me. Also this is not just to override editor settings but also other workbench settings like files.autoSave, files.encoding etc. So the property should be generic enough. Taking all above suggestions, I would propose following
{
"workbench.editor.showTabs": true,
"settings.override": {
"file:*.ts": {
"editor.insertSpaces": false,
"diffEditor.ignoreTrimWhitespace": false
},
"file:*.js": {
"files.autoSave": false
},
"language:markdown": {
"editor.wordWrapping": 0
}
}
}
With this approach any setting can be overridden and can also be leveraged by extension authors.
@aeschli With respect to Editor Config, I think it is mainly for limited editor settings and syntax is not JSON and might not fit well with our settings story. Given that this already popular, building on top of that might bring confusion between overriding all settings vs editor config.
You're right, was just throwing some ideas to make sure we considered everything. Seems solid if we could preserve order!
Said that, I also think given that EditorConfig is already very popular, I think we should maybe not build our own story but try to build on EditorConfig and extend it with our own settings.
I'm a contributor to the EditorConfig extension. We will probably not accept custom settings as it has a fixed set of properties, see the website. The idea behind it is that it works across all editors.
We will probably not accept custom settings as it has a fixed set of properties
What about domain-specific-properties? https://github.com/editorconfig/editorconfig/wiki/EditorConfig-Properties#ideas-for-domain-specific-properties
Not sure. If you guys think it's a valid path we can always discuss this further.
// @jedmao
I do not understand how we want to extend EditorConfig here? I only see the possibility of re-using the syntax. Please elaborate it.
I think what they suggest is that more settings are added to the EditorConfig plugin in order to achieve the exact same result. So this features isn't being implemented in the core of VS Code and if you want to override settings, you could use EditorConfig.
Probably if EditorConfig plugin supports more and custom settings, we can use EditorConfig to override user / workspace settings. But this looks to me a decision to be taken from EditorConfig.
Instead, I would prefer our own independent story since this can be extended to all VS Code settings
Using globs/language as keys has the disadvantage of duplicating settings for different globs or languages which is bad. Thinking this, we have to go with array approach even though it is verbose, given that we can merge user/workspace entries as in comment.
Merging of these can be abstracted to outside.
@heaths I think telling people not to edit the files in vscode is not the solution here. You could fix this problem right now by using the EditorConfig plugin with the following .editorconfig file at your project root:
root = true;
[*]
indent_style = space
indent_size = 4
trim_trailing_whitespace = true
[*.idt]
indent_style = tab
This way, people can edit any file they want in vscode or any other editor that supports EditorConfig or has a plugin for it.
I think this would be the best approach. Would this work for you?
@jedmao I chimed you in specifically for the comments on extending EditorConfig. Not sure if we want to support domain specific settings.
For me, using EditorConfig isn't a viable solution as it's entirely dependant on end-users also installing it & setting it up along with my grammar extension (several of the languages included require specific settings). Plus would cause potential conflict for users who use Sublime.
I prefer Sublime's solution to syntax-specific settings, as the ideas above have made it far more complicated than it needs to be. It also allows far easier usage for language grammar extensions, as you only need a json file with all the settings. Example for AGC Assembly.
@SamVerschueren I realize why you chimed me in and I would advise against domain-specific settings if we can prevent it. That would definitely be a last resort. In this case, I think the OP's issue can be resolved w/o domain-specific settings, so I would advise against going down that path.
@wopian is your team all using the exact same editor (Sublime)? If not, your solution wouldn't work for every developer. If so, why are you on this vscode issue? Also, are you pushing these Sublime settings to your repo? If so, that's generally advised against, because you're forcing everyone to use the same editor.
EditorConfig allows you to solve the same problem in a way that doesn't force people to all use the same editor. Yes, that would mean if you have any colliding settings in your Sublime settings that you would need to remove those settings from Sublime, but I see that as a good thing, because now those settings are handled in an editor agnostic way. People can feel free to use whatever editor they want.
Before this all gets resolved by using EditorConfig, I still would like to be able to have Python use 4 spaces per level of indentation and use 2 spaces for C files without adding extra configuration per work space or installing EditorConfig.
Is it really unreasonable to support this natively?
EditorConfig was a really great idea, it means you only need to configure common project editing settings once and check it in.
@wopian not sure I'm getting how is distributing language-specific sublime settings to your team members is better than an extension that handles it for you, in addition it doesn't mess with other configurations for other projects since .editorconfig is scoped to the repo.
I'm not sure if it's been mentioned but maybe we should consider bundling the EditorConfig extension as we do with Emmet support, I believe that would cover the use cases mentioned so far and remove the need to install the extension at all.
@sandy081 re https://github.com/Microsoft/vscode/issues/1587#issuecomment-272233645 Not sure if I understand that. I can write glob:{**/*.ts,**/foo,**/ff.*} to select different files at least for glob and I am sure we can up with the same for language ids and also mix both
is your team all using the exact same editor (Sublime)? If not, your solution wouldn't work for every developer. If so, why are you on this vscode issue?
I use VS Code. I was using Sublime as an example (with the Sublime version of my VS Code extension).
Also, are you pushing these Sublime settings to your repo? If so, that's generally advised against
Nope, the sublime extension includes syntax-specific settings which overrides the default settings for the specific language. You can turn them off in Sublime in the same way you can change colour scheme.
EditorConfig allows you to solve the same problem in a way that doesn't force people to all use the same editor
EditorConfig exposes barely any settings needed for the VS Code or Sublime extension, and again requires end-users to install and setup EditorConfig for all of their repos, when the languages require specific settings to compile.
in addition it doesn't mess with other configurations for other projects since .editorconfig is scoped to the repo.
I need settings scoped to the language, not the repo.
not sure I'm getting how is distributing language-specific sublime settings to your team members is better than an extension that handles it for you
The language-specific settings are bundled with the extension that provides the grammar for the languages. So it's 1 extension and 0 configuration required by the end-user instead of having to use 2 extensions + config files the end-user has to properly setup.
EditorConfig exposes barely any settings needed for the VS Code or Sublime extension, and again requires end-users to install and setup EditorConfig, when the languages require specific settings to compile.
I need settings scoped to the language, not the repo.
Thank you @wopian for articulating these important concerns. In particular, language scope was very useful to me when I used sublime, and I have been missing it since adopting vscode.
@wopian thanks for the clarification. It sounds like you've already written an extension for Sublime, so you could do the exact same thing for vscode by reading custom settings, which brings me to your comment:
EditorConfig exposes barely any settings needed for the VS Code or Sublime extension
Not actually true. EditorConfig will allow you to configure custom settings as well. You can name them whatever you want and write a non-EditorConfig extension that supports those custom settings, scoped to file extension (not language). The language scope is definitely cool, but that can be solved in other ways, like making sure all your Markdown files have the .md extension. We might even be able to patch the EditorConfig extension to look for the editor's selected language for files w/o an extension, in a way, tricking editorconfig-core-js into thinking there's an .md extension when, in fact, you only have Markdown selected as your language. That'd be a cool feature.
Anyway, just throwing out options. It'd be cool if vscode supported this feature, but that would only solve the problem for developers using vscode. I'm trying to solve it in such a way that works for everyone, regardless of editor.
VS Code settings story is different from EditorConfig story as mentioned by @wopian. I do not think its a good idea to merge both of them. Problem we are trying to fix here is how we can let users to override any setting based on files / languages. Introducing a new syntax and new files might not help all users. Solution should be inline with our current settings story. Hence, I would go with a override setting option in user/workspace settings. This will be easy for users and can leverage existing settings functionality. One of the things missing here is, extensions contributing language based settings which I think can be supported by enhancing above solution more.
@jrieken
I can write glob:{/.ts,/foo,/ff.} to select different files at least for glob and I am sure we can up with the same for language ids and also mix both
I was not aware that we can give , separated expressions to globs. Good to know. But the issue I see with this approach is
settings where extensions also have to access (as a JSON object) to do, they are expected to agree with same hidden agreement that order is important. Or we can add APIs in WorkspaceConfiguration in vscode.d.ts to access overridden settings.Some other less verbose syntax proposals that encode the language ID within the setting key itself which the configuration service would understand:
"setting[languageId]": value
"setting['languageId']": value
"languageId|setting": value
"setting|languageId": value
For example:
"workbench.editor.showTabs": true,
"editor.insertSpaces[typescript]": false,
"diffEditor.ignoreTrimWhitespace[typescript]": false
"files.autoSave[javascript]": false
"editor.wordWrapping[markdown]": 0
This could be extended to support glob patterns:
"workbench.editor.showTabs": true,
"editor.insertSpaces[file:*.ts]": false,
"diffEditor.ignoreTrimWhitespace[file:*.ts]": false
"files.autoSave[file:*.js]": false
"editor.wordWrapping[language:markdown]": 0
Just to add another way I used in my extension.
I use @Tyriar style for the extension's configurations but instead of brackets I use language ID as an optional key itself.
For example:
// Apply to all
"editor.wordWrapping": 0
// Apply to only markdown
"editor.wordWrapping.markdown": 0
FYI, some language providers (syntax highlight) named their language ID with spaces. Such as API blueprint, they use "API Blueprint" as their language ID which works when wrapped inside quotes but it's not consistent with the conventions.
After long discussions, in this milestone we would start supporting only language based settings with the following syntax
{
"workbench.editor.showTabs": true,
"settings.override": {
"markdown,json": {
"editor.wordWrapping": 0
}
}
}
There were quiet many arguments to either support globs/file based or folder based settings. Glob patterns make it much complex to understand for user to derive what settings are applied for given editor. Folder based settings will fall in-line with workspace settings which overrides the global settings.
Regarding syntax, sticking to the above format.
Format setting.id[...languages] suggested by @Tyriar is cool and easy to write, but I think we first select a language and override settings rather than take a setting and override it for a language. Hence, I think grouping by language is expected by users. And, it is easier and helpful for building some helper/discoverability UIs, say configure settings for mode/language/folder (if we support). Also, it might not scale if we have more settings to override for more than one language.
How does that work if the file type doesn't have a defined language? I highly doubt anyone is willing (as an MSI expert that has used the IDT format, I don't want to spend the time either) to write handler support. Does the file extension become the language, then?
@heaths I am not saying that language based settings will solve all issues but it will cover majority of requirements. As you see, there were so many ideas rolled in and discussions went it. There is also EditorConfig extension to support settings for files using globs. We will collect more feedback and brainstorm more to come up with the right solution.
In case of file extension, why not associating it to a language mode using language mode picker and override settings?
Updated the languages key format to be simple and less verbose. See comment
@sandy081 what if an override should be able to be based on not only a language?
For example, I'd love to see settings be overridden by operating system:
{
"settings.override": {
"windows": {
"window.zoomLevel": -0.001
}
}
}
Would it not be better to define what kind of override you're setting?
Example:
{
"settings.override": {
"lang": {
"python": {
"editor.rulers": [
72,
79
]
}
},
"os": {
"windows": {
"window.zoomLevel": -0.001
}
}
}
}
Not sure if this becomes off-topic, but also it would be awesome if this behavior would work automatically for user settings, workspace settings (including extensions settings).
@sandy081 can you elaborate? I realize this is a long thread, but the proposed solution doesn't actually solve the original bug. If what you describe could work (sounds like you're saying I could map *.idt to something else, but it would have to be the default for any user in a workspace to matter), I would consider that a viable workaround / partial solution.
@heaths You can configure the setting files.associations at global/workspace level and associate them to languages. These have precedence over the default associations of the languages installed.
Example:
"files.associations": {
"*.idt": "markdown"
}
@fredrikaverpil Sure, we can extend this further to os based settings. We are also discussing about folder based settings. Since, IMO, language based settings are most common, default (without any prefix) goes to languages and others can be prefixed with proper identifier say "os:windows" etc.
This overriding setting is a new setting and hence can be used in user/workspace settings. Re extension contributions to this, we thought about this and still need to come with a proper solution in future.
Sure, we can extend this further to os based settings.
❤️
"os:windows"
@sandy081 This sounds excellent to me. Having OS-based settings would make it a lot easier to create workspaces within a cross-platform project as well as sharing the same user settings on different operating systems.
Re extension contributions to this, we thought about this and still need to come with a proper solution in future.
You mean extensions settings won't automatically work with your proposed os:windows?
I'm looking to be able to set the Python interpreter based on OS: https://github.com/DonJayamanne/pythonVSCode/issues/644
Also related: https://github.com/Microsoft/vscode/issues/17619
For
launch.jsonwe already support OS-specific configurations. Any configuration can be nested inside an OS qualifier, e.g."linux": { "foo": "bar" }.
– @weinand https://github.com/Microsoft/vscode/issues/17619#issuecomment-273424889
There was further simplification of format of language based settings. Here is the latest
"editor.wrappingColumn": 300,
"editor.lineNumbers": "off",
"[json]": {
"editor.lineNumbers": "on"
},
"[json,markdown]": {
"editor.wrappingColumn": 0
}
Set of overriding identifier (languages) are now top level keys whose values are settings to be overridden. This format is very much aligned to editor config.
@sandy081 what would the override for platform look like, I quickly glanced the commit and it seems this is it?
"editor.wrappingColumn": 300,
"editor.lineNumbers": "off",
"[windows]": {
"editor.lineNumbers": "on"
},
"[osx]": {
"editor.lineNumbers": "off"
}
Overall, this is all awesome stuff - but... don't you think it would be safer to require a prefix such as os:, lang: etc, simply based on the assumption that sooner or later an override keyword could apply to more than just one category?
@fredrikaverpil Overriding for platforms are not yet supported. As said earlier they are up for discussion.
This milestone we scope this only for languages and language based settings are much common than others. Hence languages do not have any prefixes. If we have to support for platforms/folders we need to come up with a specific overriding pattern. But this is up for discussion.
@sandy081 Allright, I see. Thanks.
With respect to configurable tab size and being able to specify filetype extension. I would suggest the following, it's pretty compact and flexible.
// Don't need to specify the '.' before extension name.
// Specify multiple extensions with '|' or separator.
tabFileExtensions: {
"cpp": "h|hpp|c|cpp|cc",
"web": "js|html|css|ts"
}
"editor.tabSize": {
"default": 4,
"web": 2,
"cpp": 3
}
The current implementation looks more compact and doesn't sacrifice readability & ease of use. Users can simply copy & paste syntax settings straight into their settings.json.
"editor.tabSize": 4,
"[js,html,css,ts]": {
"editor.tabSize": "2"
},
"[h,hpp,c,cpp,cc]": {
"editor.tabSize": 3
}
Your implementation would require users to add the syntax settings into multiple areas of their settings.json
Just to make sure that, as beginning and to be simple, we only support one language per entry. Multiple languages as a single key is not supported. So, one can write only as follows
"[js]": {
"editor.tabSize": "2"
},
"[html]": {
"editor.tabSize": "2"
}
Closing - the plan item is done.
@egamma, in which version this functionality available?



@IgorNovozhilov Language based settings are available in current insiders. With respect to the issue you mentioned, I will take a look
@sandy081 any idea when the 1.9 insider might hit stable?
@wopian here are the iteration plans: https://github.com/Microsoft/vscode/wiki/Iteration-Plans
It says early February.
@IgorNovozhilov There is a bug in the feature that following settings are not respected by language
editor.tabSize
editor.insertSpaces
editor.detectIndentation
editor.trimAutoWhitespace
Thanks for catching this scenario and reporting. I will be filing a separate issue to track this - #19511
@sandy081 it looks like it is not possible to set extension properties within a language-specific configuration block? For example, the following does not work:
"[rust]": {
"vim.textwidth": 100
},
I also get the green underlining, with a warning saying "Unknown Identifier. Use language identifiers". I suspect this might be related to #19511, and perhaps also #4891?
@jonhoo I don't think extensions can contribute language specific settings at the moment. I've opened #26707 to track this
@jonhoo Yes only core editor settings are supported in language-specific configuration block. Regarding warning, it is shown if there is no such language defined (in this case rust).
So how does this work in the end? I want to set word-wrapping for some filetypes. What do I do? Is this documented?
https://code.visualstudio.com/docs/getstarted/settings#_language-specific-editor-settings
as beginning and to be simple, we only support one language per entry. Multiple languages as a single key is not supported.
So is later support of multiple langauges per key/entry something planned for the future?
Is there a seperate issue to track that?
@myfairsyer Its not yet planned.. Feel free to file an issue for that. Thanks.
Most helpful comment
https://code.visualstudio.com/docs/getstarted/settings#_language-specific-editor-settings