Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Profiles: Extend from Default Profile #156144

Closed
sandy081 opened this issue Jul 25, 2022 · 46 comments
Closed

Profiles: Extend from Default Profile #156144

sandy081 opened this issue Jul 25, 2022 · 46 comments
Assignees
Labels
feature-request Request for new features or functionality on-testplan user-profiles User profile management
Milestone

Comments

@sandy081
Copy link
Member

sandy081 commented Jul 25, 2022

Allow to configure settings across profiles.

One idea we are considering is to allow users to choose between following options while creating a profile:

  1. Extend from Default Profile
  2. Diverge from Default Profile

When chosen to extend, settings from default profile are applied unless user overrides them in the profile.

@sandy081 sandy081 added feature-request Request for new features or functionality user-profiles User profile management labels Jul 25, 2022
@sandy081 sandy081 added this to the Backlog milestone Jul 25, 2022
@sandy081 sandy081 self-assigned this Jul 25, 2022
@GongT
Copy link

GongT commented Oct 19, 2022

need something like:

{
	"setting.item": { "$linkWith": "default" }
}

or

{
	"profile.link": [
		{"source": "default", "keys": ["item", "item2"]}
	]
}

I also need keybindings never change between profiles. or this feature is not usable for me.

@sandy081 sandy081 changed the title Allow to configure settings across profiles Profiles: Extend from existing profiles Dec 13, 2022
@sandy081 sandy081 changed the title Profiles: Extend from existing profiles Profiles: Extend from Default Profile Dec 13, 2022
@dimateos
Copy link

dimateos commented Dec 14, 2022

Exaclty, I was expecting settings profiles to allow specifying what is to be replaced from default, something like what is done in settings sync:
image

Basically I need keybinds and settings persistent across profiles. Otherwise when I add new ones/update in the default profile I have to recreate profiles or edit the exported file with a diff and reimport... Also note how there are conditional clauses for hotkeys (e.g. editorTextFocus && editorLangId == 'markdown') that you can use to differentiate per language. So there is no need for profiles per language here, which is one of the main uses of setting profiles. I believe there are also similar options for settings per language, but I think that this is less used.

Anyway I only plan to use setting profiles for enabling extensions per language/work-place, and I think am not alone (multiple extensions target this specific case). The fact that it enforces persistent settings and keybinds prevents me from using it.

Your proposed features to just extend/diverge from default could work, although then maybe e.g. there is no way to add new extensions while disabling others?

@Lamarcke
Copy link

Lamarcke commented Jan 4, 2023

This would indeed be a really great option.

Often, when i need to change a setting for something native or for a extension i use in all profiles (like GItlens) i need to copy and paste in every profile. (Although knowing where the profiles' settings.json are stored make this easier).
This would also apply to keybinds.

@kozer7
Copy link

kozer7 commented Jan 11, 2023

This is the idea of my profile settings. I use many tech stack and I like to try new things so I change my extensions very much. But I would love to have layered or stacked profiles not just extending from one. Let me give you a example.

One of the programming languages I mainly use is Java. I use diffrent tools(extensions) and let me group these like these:
+Java:
++ Editor Settings, Key Bindings & Java related extensions like Spring Framework, Maven, Gradle, Test Extension and more.
++ (Optional) Container Extensions
++ (Optional) Kubernetes Extensions
++ (Optional) Git related extensions
++ (Optional) Xml, Yaml, Json etc. related extensions.
++ (Optional) NoSQL data management extensions
++ (Optional) SQL data management extensions

and goes on. The other language I mainly use is python and this is the tools I generally use.

+Python:
++ Editor settings, formatter, virtual env. manager and test extensions
++ (Optional) Container Extensions
++ (Optional) Kubernetes Extensions
++ (Optional) Git related extensions
++ (Optional) Xml, Yaml, Json etc. related extensions.
++ (Optional) NoSQL data management extensions
++ (Optional) SQL data management extensions

Apart from these I try to play with Flutter, Angular or React frontend tech stacks:) Ok, I dont use them mainly but wanted to have an opinon about them. but still use them every now and then.

So what I wanted to do is, activating each required profile for the project. I mean one python application is running on containers and I have to activate related extension but one project is not using any container mechanism. I dont want to deactivate them manually and re-open. Same as using sql or nosql related extensions.

This way I can update a profile like adding GitLens to git profile. And all projects in which git profile active will have the Gitlens.

@cweagans
Copy link

For me, this is really the only thing that's missing from the settings profile functionality as it exists currently. I was using https://marketplace.visualstudio.com/items?itemName=cyberbiont.vscode-profiles for a while. My base profile has only a couple of plugins (vscodevim, editorconfig, markdown preview mermaid support, and the Nord theme) and a fair amount of configuration that's standard across every tech stack I work on (font, UI, window settings, etc).

In the secondary profiles that extend from the base profile, I intend to add language-specific extensions and configuration. I would love to not have all of my base configuration duplicated in the secondary profiles. I would like to not update my font in a bunch of different places if avoidable.

@cweagans
Copy link

cweagans commented Jan 22, 2023

Alternatively, instead of having separate config files for different profiles, having profile-specific sections in the main config would work well:

{
    "editor.fontSize": 15,
    "editor.lineHeight": 1.9,
    "[profile:screencast]": {
        "editor.fontSize": 20
    }
}

@frypf
Copy link

frypf commented Feb 15, 2023

It would definitely be useful to have the option some sort of inheritance from other profile(s) - or even better a way of specifying profile-specific overrides similar to the "[someLanguageName]": {...} syntax already available for language-specific settings.

Basically I need keybinds and settings persistent across profiles.

Anyway I only plan to use setting profiles for enabling extensions per language/work-place, and I think am not alone (multiple extensions target this specific case). The fact that it enforces persistent settings and keybinds prevents me from using it.

This is my main use case as well - I already have any language-specific keybindings set up as I want them using "when": editorLangId == 'someLanguageName', and most of my language-specific settings are written directly into the global settings.json, but profiles seem the only way to specify which extensions I want to enable or disable for a given project without relying on clicking the UI.

Where my current approach falls down for me is that sometimes I might be momentarily working on a different language within eg. a Python or Swift project or whatever. This is where I tend to use workspace-scoped settings, so I had hoped profiles would make the process of applying the same settings overrides across a bunch of different workspaces redundant. However, frustratingly, instead I now have to remember to update new keybindings or altered global settings across a bunch of different profile-scoped keybindings.json and settings.json. Admittedly there's far fewer profiles than workspaces on my machine, but unfortunately it's not even obvious at a glance which of these files apply to which specific profile.

(Although knowing where the profiles' settings.json are stored make this easier).

I was only able to discern this by using revealFileInOS for the settings or keybindings json from within a profile. Is there any possibility of giving the individual profile directories within ~/Library/Application Support/Code/User/profiles more intuitive / discernible names?

For now I'm experimenting with hardlinking my keybindings.json and settings.json files into each individual profile when I set it up. I did originally try with symlinks - but any updates I made from within my Default profile where only reflected in other profiles after resaving the json from within that profile, whereas updating a setting or keybinding from within a profile was instantly reflected back in Default.

@eccentricOrange
Copy link

Coming from #175427, I really need some core settings like files.autoSave to be consistent.

@frypf
Copy link

frypf commented Feb 28, 2023

In addition to my previous points, I've found that currently when within a profile's settings.json, any settings marked as 'application-scoped' are dimmed and show the following message when hovered:
This setting has an application scope and can be set only in the user settings file.
These settings still seem to take effect, but it's confusing to say the least.

The UI could definitely be improved for this, and more generally for setting up profiles overall. The checkboxes are intuitive when it comes to specifying which extensions are enabled / disabled. However, with everything else (settings, keybindings etc) it's not obvious what the differences between checked / unchecked might be. I had assumed that leaving something unchecked would inherit whatever I was using within my default profile, and it was only after finding this thread that my expectations were actually clarified.

As we've come to realise, checked means that the entire file is copied wholesale to the new profile and any changes made subsequently to that file diverge from the base, while unchecked means that VSCode generates an empty / default file for those sections. I've also since realised that user tasks and snippets need to be part of the proposed inheritance model as well as settings and keybindings.

The checkbox-based 'Show Contents' view in the sidebar which allows us to tailor and export a new profile should be presented whenever I invoke 'Create profile'. This view would be of far more use if it actually took effect on a profile in real-time rather than just the generated exported profile.

From my POV at least, the default assumption on on VSCode's part should be that unless I've checked something, I just to want the new profile to use whatever I've already set up and am using successfully. There needs to be better indication of what the checkboxes mean (for everything other than extensions), possibly using a drop-down or similar with the options stated within the OP:

Extend from Default Profile
Diverge from Default Profile

(and possibly additional options such as Generate empty for those who do want an entirely separate uninherited version).

If the proposed inheritance model is adopted, will it still be possible to open the pertinent .json files for both global and profile-scoped settings etc. via a command or keybinding, as is currently the case with workspace-scoped settings?

@mircmo
Copy link

mircmo commented Feb 28, 2023

I also think that there needs to be a profile hierarchy of some kind for the profile feature to become really usable. I mean just alone for key bindings, these are rarely profile specific in my experience.

The best approach in my opinion would be something like what's already mentioned in this issue: #173473
This solution would be really flexible and is also a quite widespread approach on how to handle different configs (e.g. tsconfigs, eslint configs or even the user/workspace settings in VS Code).
The behaviour would be just like with workspace settings. The workspace settings get added on top of the user settings or in this case, profile settings get added on top of another profiles settings.
In the user/workspace settings scenario the inheritance is implicit but for profiles it would have to be explicit with like a "extends": "default-profile" key in the json file. I think it would also make sense to allow multiple levels of inheritance. A limit probably wouldn't hurt, but more than one level should be possible. Consider this scenario:

  • Base (includes my key bindings, theme, gitlens extension and stuff like this)
    • JS Web Base (eslint, scss extensions and so on)
      • Nextjs Tailwind (nextjs snippets, tailwind, prisma...)
      • Angular (angular language server, snippets...)
    • Dotnet (C# language support, Azure Tools...)

You could make this work with one level of inheritance, either by having some extensions and configs duplicate across profiles or by "merging" two profiles to have e.g. react and angular extensions in the same profile, but in my opinion its cleaner to just allow this structure to begin with. Also I can think of a couple improvements that could be made in the future that would benefit from having smaller more specific profiles.

Some problems I can see so far with this approach are the UI State and Extensions part of the profile.
While inheriting like described above makes perfect sense for the Settings, Keyboard Shortcuts, Tasks and Snippets its probably a little bit trickier with the other two. I would have to take a closer look at how the ui state json works since I currently haven't got a clue.
The extensions part is also a little bit unclear to me. What do those checkboxes in the profile UI do? Do they disable the extensions? Do they remove them from the profile? Do they simply modify the result of the Export button? Either way would there probably be something to rethink...

Another thing that might me improved with this, is the relation of user settings and profiles. Since no documentation on the profiles feature exists as of yet and I've not bothered to dive into the source code, I'm not sure how this even works at the moment. If profile inheritance would be implemented you could arguably replace the user settings with a default profile. But that would probably be a thing to think through if someone decides, this approach is the way to go.

Anyway, I would love to give this a shot, however there are still some uncertainties.
I would like really like to hear some thoughts on this. Does anyone see some flaws with this approach or has a better one?

If enough people think this approach is a good idea I'll try to implement something :)

@RoyalFoxy
Copy link

@mircmo I think your approach is a good implementation for having multiple profiles and I agree when you say that without some kind of inheritence the profile feature as is is somewhat annoying and frustrating to use. I myself find me deleting and adding config accross multiple profiles and it's always a big pain.

Regarding the extensions, I was also somewhat confused at how the extensions worked and it's weird... The last time I tested it (January build of the normal vscode) the extension tick boxes in the export profile view didn't do anything, even if I unticked all, the profile would still include all profiles... The solution in the end was to uninstall the extensions inside a profile itself which worked.

I can't help with the uistate much as I think it's not something you're supposed to edit yourself as there isn't a command in the palette to open the uistate file. I think it would be a good idea tho to have an option in the settings json kinda like the "extends" option you discussed but for the uistate. I see myself rarely changing the uistate on profiles however there are some cases like when you're using a db extensions for mongodb which you don't use in any other profile and you want it visible and to implement something like that needs some more thinking...

Just to clarify tho when you said "like with workspace settings" you meant that the profile settings json would have property depending on if you're creating an empty profile or an inherited one being the "extends" property and a few more properties which are specific to that profile like a special formatter or language specific settings that you can't include in the default profile and it would result in just a few lines (depending on the use cases) or am I wrong about that?

At least the way I understood your approach is the way to go and it's roughly what I thought about aswell.

sandy081 added a commit that referenced this issue Jul 17, 2023
#156144 Fix gaps in updating the profile
@sandy081 sandy081 mentioned this issue Jul 17, 2023
sandy081 added a commit that referenced this issue Jul 17, 2023
sandy081 added a commit that referenced this issue Jul 17, 2023
@sandy081
Copy link
Member Author

sandy081 commented Jul 18, 2023

You can now create a (partial) Profile, in which you can choose what configurations (Settings, Keyboard Shortcuts, Extensions, Tasks & Snippets) can be done in that profile and use the Default profile for some configurations. For eg:, you can have a Profile with all configurations except for Keyboard Shortcuts, and use Default Profile for it.

image

You can also share/apply a setting/extension to all profiles

image image

These changes are available in insiders. Please try out them and provide us with the feedback.

@mon-jai
Copy link

mon-jai commented Jul 18, 2023

@RoyalFoxy's method would be more intuitive for me.

In the current implementation, it is difficult to copy all settings from a base profile (I have to click "Apply Setting to all Profiles" for each settings, one by one). New settings also won't apply to other profiles too.

Instead of tracking setting keys that apply to all profile, maybe it would be better to also store the value?

// From
{
  "editor.fontFamily": "Fira Code, Consolas, 'Courier New', monospace",
  // 20+ more settings...

  "workbench.settings.applyToAllProfiles": [
    "editor.fontFamily"
    // Key of 20+ more settings...
    // Did I add all settings to the array? Is there something I missed?
  ]
}

// To
{
  "workbench.settings.applyToAllProfiles": {
    "editor.fontFamily": "Fira Code, Consolas, 'Courier New', monospace"
  },
  // Only settings defined outside `applyToAllProfiles` would not be inherited
  "some-local-settings": "value"
}

@carlocardella
Copy link
Member

I used these settings with the first profile I created:

image

My intention was to create a test profile based on Default and I wanted to copy only extensions and User Tasks, but I got the opposite.

Definitely my fault, I didn't pay enough attention to the "Use Default Profile" label, I assumed I needed to check what I wanted to copy from the Default (because of the "Copy from: Default" dropdown I selected above).

I am not sure if/how this can be improved and made more clear: now that I know how the dialog works it seems straightforward and I think I like it, but I can imagine others making my same mistake the first (and maybe second) time.

@tanishqmanuja
Copy link

Totally agree, rephrasing the hints would be great.
Something like:
Settings - Use Default Profile => Using Settings from Default Profile
Keyboard Shortcuts - Use Default Profile => Using Keyboard Shortcuts from Default Profile

@sandy081
Copy link
Member Author

@mon-jai

In the current implementation, it is difficult to copy all settings from a base profile

Copy from Default Profile option should be enough to do this.

@sandy081
Copy link
Member Author

Settings - Use Default Profile => Using Settings from Default Profile

Changed this to Settings - Use Default Profile => Using Default Profile. Having Settings multiple times might be redundant.

@mon-jai
Copy link

mon-jai commented Jul 19, 2023

@sandy081 That was a typo. What I mean is,

In the current implementation, it is difficult to "synchronize" all settings from a base profile

If I understand it right, "Copy from Default Profile" is a one time operation. Subsequent changes to those copied settings won't be synchronized between profiles. Settings added after the copy operation won't apply to other profiles too.

I would like to have a "single source of truth" for all my global settings, instead of having to copy them over occasionally.

@sandy081
Copy link
Member Author

I would like to have a "single source of truth" for all my global settings, instead of having to copy them over occasionally.

You can unselect Settings option when you are creating the profile - This will use Settings from the Default Profile.

@mon-jai
Copy link

mon-jai commented Jul 19, 2023

unselect Settings option when you are creating the profile

@sandy081 But then I won't be able to have "local settings" for the profile.


IMO, a common use case will be having a default profile with common settings for all languages, and a few language/framework specific profiles extended from default profile, with additional settings for the given language.

For example,

// Default profile
{
  // Common settings for all languages
  "editor.fontFamily": "Fira Code, Consolas, 'Courier New', monospace",
  "editor.lineHeight": 1.6,
  "editor.renderWhitespace": "trailing"
  // ...
}
// Python profile
{
  // Everything from default profile...

  // Python and Jupyter notebook specific settings
  "jupyter.askForKernelRestart": false,
  "notebook.output.textLineLimit": 100,
  "python.analysis.typeCheckingMode": "strict",
  "python.analysis.useLibraryCodeForTypes": true,
  "python.formatting.blackArgs": ["--skip-string-normalization"],
  "python.formatting.provider": "black",
  "python.linting.mypyEnabled": true,
  // ...
}

For now, it is impossible to inherit everything from the default profile automatically. We can either,

  • Click "Apply Setting to all Profiles" for each settings, one and one (new settings key won't be synchronized automatically, time consuming, error prone)
  • Unselect Settings option when creating the new profile (not able to define local settings)

It would be better if we could inherit settings from a given profile, with new changes synchronized automatically.

@oldguan
Copy link

oldguan commented Jul 19, 2023

image
i will create a new profile for python like above, but then the default profile is cleared. ahahah......

@tanishqmanuja
Copy link

tanishqmanuja commented Jul 19, 2023

@mon-jai, I am also having the same difficulty setting up my settings.json for individual language specific env (angular, python, golang etc etc).
But i guess that has to do more with the settings.json and less with profiles in general. If extending is not possible to implement with multiple profiles (i.e. multiple settings.json), at least there should be a "fallback to default" approach instead of "follow default" approach.

// fallback would be something like this (we can discuss what merge strategy would be there)
effectiveProfileSettings = { ...defaultSettings, ...profileSettings }  // very useful IMO

// follow is simply this
effectiveProfileSettings = defaultSettings  // why would I even make a new profile to do this?

Like we have certain properties that can only be changed from settings.json (User), maybe some boolean property can be added to settings.json (Profile) to enable fallback to default.

@sandy081
Copy link
Member Author

@tanishqmanuja Please check my comment - #156144 (comment) . Can you please mention the real time use case for having default profile settings overridden in profiles?

@mon-jai It seems your use case does not seem like overriding setting. If you want some settings to be common for all profiles you can use the action to apply each setting or you can directly add the list of common settings to the following setting in settings.json of default profile.

"workbench.settings.applyToAllProfiles": [
    "editor.fontFamily",
    "editor.lineHeight",
    "editor.renderWhitespace"
  ]

In the background, settings common to all profiles are stored in this setting.

@sandy081
Copy link
Member Author

sandy081 commented Jul 19, 2023

@oldguan

i will create a new profile for python like above, but then the default profile is cleared. ahahah......

Do you mean the settings in the default profile are replaced by the settings from the profile template? If so this is a bug and should be fixed. Thanks for letting us know about this.

Edit: Fix is on the way...

@tanishqmanuja
Copy link

tanishqmanuja commented Jul 19, 2023

@sandy081 My real-time use case is beyond the scope of this issue, but that said if overriding is added would make my IDE experience much better. Still here's a simplified version of the use case :)

Default

These settings define my basic vscode styling.
Obviously if I like my vscode to look a certain way, i would keep that for all profiles.

// default user settings
{
  "editor.fontSize": 14,
  "editor.fontFamily": "MonoLisa",
  "editor.fontLigatures": true,
  "editor.minimap.enabled": false,
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "editor.tabSize": 2,
  "editor.codeLens": false,
  "editor.bracketPairColorization.enabled": true,
  "editor.overviewRulerBorder": false,
  "editor.hideCursorInOverviewRuler": true,

  "terminal.integrated.fontSize": 14,
  "terminal.integrated.fontFamily": "MonoLisa Nerd Font Mono",
  "terminal.integrated.gpuAcceleration": "on",

  "workbench.startupEditor": "none",
  "workbench.sideBar.location": "right",
  "workbench.colorTheme": "One Dark Pro Darker",
  "workbench.productIconTheme": "fluent-icons",
  "workbench.iconTheme": "symbols",
  "workbench.colorCustomizations": {
    "editor.lineHighlightBackground": "#00000000",
    "editor.lineHighlightBorder": "#00000000"
  },
}

JS

Here i have to copy my default stuff + add few JS additions
Obviously I don't want these on default profile.

{
  //copy default settings here.
  "[html]": {
    "editor.formatOnSave": true,
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "[javascript]": {
    "editor.formatOnSave": true,
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "[json]": {
    "editor.formatOnSave": true,
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  // other js extensions specific settings
}

JS Presentation

This profile is exactly same as JS but with font size enlarged to 16 to make screen sharing easier.

{
  //copy default settings here (except fontsize). (overriding would help here)
  //copy JS settings here.
  "editor.fontSize": 16,
  "terminal.integrated.fontSize": 16,

 // also disabling stuff like codium, and copilot
}

@mon-jai
Copy link

mon-jai commented Jul 19, 2023

@sandy081 But keeping applyToAllProfiles in sync with every defined setting keys is troublesome and error prone.

Currently I have something like this (yeah It is a long list):

{
  "workbench.settings.applyToAllProfiles": [
    "[css]",
    "[html]",
    "[ipynb]",
    "[javascript]",
    "[javascriptreact]",
    "[json]",
    "[jsonc]",
    "[markdown]",
    "[powershell]",
    "[python]",
    "[scss]",
    "[typescript]",
    "[typescriptreact]",
    "[vue]",
    "apc.font.family",
    "apc.iframe.style",
    "apc.imports",
    "cSpell.userWords",
    "editor.cursorBlinking",
    "editor.fontFamily",
    "editor.fontLigatures",
    "editor.formatOnPaste",
    "editor.formatOnType",
    "editor.guides.bracketPairs",
    "editor.largeFileOptimizations",
    "editor.lineHeight",
    "editor.maxTokenizationLineLength",
    "editor.renderWhitespace",
    "editor.rulers",
    "editor.stickyScroll.enabled",
    "editor.tabSize",
    "editor.unicodeHighlight.ambiguousCharacters",
    "editor.unusualLineTerminators",
    "editor.wordWrap",
    "emmet.includeLanguages",
    "explorer.confirmDelete",
    "explorer.confirmDragAndDrop",
    "files.associations",
    "git.autofetch",
    "git.enableSmartCommit",
    "git.openRepositoryInParentFolders",
    "gitlens.plusFeatures.enabled",
    "gitlens.statusBar.enabled",
    "gitlens.views.formats.commits.label",
    "javascript.updateImportsOnFileMove.enabled",
    "prettier.configPath",
    "security.workspace.trust.untrustedFiles",
    "terminal.integrated.automationProfile.windows",
    "terminal.integrated.copyOnSelection",
    "terminal.integrated.defaultProfile.windows",
    "terminal.integrated.enableMultiLinePasteWarning",
    "terminal.integrated.profiles.windows",
    "typescript.updateImportsOnFileMove.enabled",
    "window.commandCenter",
    "workbench.colorTheme",
    "workbench.editorAssociations",
    "workbench.settings.applyToAllProfiles",
    "workbench.startupEditor"
  ]
}

That's why I suggest having applyToAllProfiles as an object instead.

{
  "workbench.settings.applyToAllProfiles": {
    "editor.fontFamily": "Fira Code, Consolas, 'Courier New', monospace"
    // ...
  }
}

sandy081 added a commit that referenced this issue Jul 19, 2023
…88290)

#156144 fix using defaults when creating from other profiles or templates
@sandy081
Copy link
Member Author

sandy081 commented Jul 23, 2023

I am closing this feature request with the solution that is current implemented.

I have created following issue to discuss about the support for overriding default profile settings in a custom profile. Those who are interested in this feature, please provide your use case / scenario (NOT how you want to use) for this requirement.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
feature-request Request for new features or functionality on-testplan user-profiles User profile management
Projects
None yet
Development

No branches or pull requests