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

Implement updateValue() method for PreferenceService #9178

Merged

Conversation

colin-grant-work
Copy link
Contributor

@colin-grant-work colin-grant-work commented Mar 10, 2021

What it does

Fixes #9152 by implementing an updateValue method parallel to that available in VSCode

In addition, an error was previously thrown if set was called with a sectionName (tasks, launch) in User scope, but that is no longer appropriate because some section configurations are available in user scope, so now that check is delegated to PreferenceSchema.isValidInScope(). I have removed any check for scope validity, because some tests specifically relied on being able to set a preference that was not (yet) valid. It could be argued that a check should happen early, but a warning will be shown later during the processing of a preference change - and the change won't take effect - if a preference is set that is not valid.

Here is one of the tests relying on setting a preference that is only made valid later:

it('get #0', () => {
const { preferences, schema } = prepareServices();
preferences.set('[json].editor.tabSize', 2, PreferenceScope.User);
expect(preferences.get('editor.tabSize')).to.equal(4);
expect(preferences.get('[json].editor.tabSize')).to.equal(undefined);
schema.registerOverrideIdentifier('json');
expect(preferences.get('editor.tabSize')).to.equal(4);
expect(preferences.get('[json].editor.tabSize')).to.equal(2);
});

How to test

  1. Run the File > Auto Save menu item.
  2. Observe that the setting is changed in user scope.
  3. Create a command that calls e.g. PreferenceService.set('tasks', {version: '2.0.0', tasks: []});. E.g. add this to PreferencesContribution.registerCommands():
        commands.registerCommand({id: 'test-setting-preferences', label: 'Set a preference using PreferenceService.set'}, {
            execute: () => this.preferenceService.set('tasks', {version: '2.0.0', tasks: []}),
        });
  1. Observe that it that setting takes effect in user scope and no error is logged.

Review checklist

Reminder for reviewers

Signed-off-by: Colin Grant colin.grant@ericsson.com

@colin-grant-work colin-grant-work added the preferences issues related to preferences label Mar 10, 2021
@kittaakos
Copy link
Contributor

Formerly, if no scope was provided, PreferenceScope.Folder was used if a URI was supplied, PreferenceScope.Workspace otherwise. Now PreferenceScope.User is used instead of PreferenceScope.Workspace.

I like the idea but VS Code uses workspace as the default if I am not mistaken:

otherwise to Workspace settings.

Could you please check the docs, @colin-grant-work. Maybe, I am overlooking something. Thank you!

update(section: string, value: any, configurationTarget?: ConfigurationTarget | boolean, overrideInLanguage?: boolean): Thenable<void>
The configuration target or a boolean value. - If true updates Global settings. - If false updates Workspace settings. - If undefined or null updates to Workspace folder settings if configuration is resource specific, otherwise to Workspace settings.

@colin-grant-work
Copy link
Contributor Author

update(section: string, value: any, configurationTarget?: ConfigurationTarget | boolean, overrideInLanguage?: boolean): Thenable<void>
The configuration target or a boolean value. - If true updates Global settings. - If false updates Workspace settings. - If undefined or null updates to Workspace folder settings if configuration is resource specific, otherwise to Workspace settings.

I agree, looks like workspace is the default for VSCode, though the boolean option is a weird twist (must be for backwards compatibility to an earlier system, I guess).

I'm not committed to changing the default scope. It was my understanding that what was requested in the bug report ticket was a more general change to the behavior of .set, rather than just setting the editor.autoSave preference in user scope. If we only want to fix where the auto-save preference gets set, that's an easy fix, too. I'd still take out the check for whether we're setting a sectionName in user scope, since that check is no longer relevant, but happy to return to the old defaulting.

@colin-grant-work colin-grant-work changed the title Change default scope for PreferenceService.set() Change setting of autosave preference to PreferenceScope.User Mar 11, 2021
@@ -333,6 +333,6 @@ export class EditorCommandContribution implements CommandContribution {
return autoSave === 'on' || autoSave === undefined;
}
private async toggleAutoSave(): Promise<void> {
this.preferencesService.set(EditorCommandContribution.AUTOSAVE_PREFERENCE, this.isAutoSaveOn() ? 'off' : 'on');
this.preferencesService.set(EditorCommandContribution.AUTOSAVE_PREFERENCE, this.isAutoSaveOn() ? 'off' : 'on', PreferenceScope.User);
Copy link
Member

@vince-fugnitto vince-fugnitto Mar 12, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From what I understood, the issue with setting the preference with PreferenceScope.User means that it will not work for the following use-case which is supported in vscode:

  1. editor.autoSave: false in the workspace settings ({workspace}/.theia/settings.json).
  2. attempt to toggle the autoSave with the command.
  3. the preference value ({workspace}/.theia/settings.json) is not updated while in vscode it is (.vscode).

Copy link
Contributor Author

@colin-grant-work colin-grant-work Mar 12, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm... so that clarifies where the problem with the current implementation really is. editor.autoSave should not be available in folder scope - it should only be set in a local settings.json in a single-root workspace, and in a multi-root workspace, only the workspace value should be picked up, not any folder scopes. If we're picking up a folder value in a multi-root workspace, that's a bug, and I'll look into that. Otherwise, it looks like setting it at workspace level is VSCode's behavior, and would avoid any awkward override situations.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@colin-grant-work I might have confused the workspace vs folder scopes, what I mean is the value under {workspace}/.vscode/settings.json is updated when toggling the command which does not happen in Theia if we are to specifically set the scope to User.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, if there is a bug that is making us pick up folder-scoped preferences, that's the fix to do. Then we should not set it in user scope.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From what I understood, the issue with setting the preference with PreferenceScope.User means that it will not work for the following use-case which is supported in vscode:

  1. editor.autoSave: false in the workspace settings ({workspace}/.theia/settings.json).
  2. attempt to toggle the autoSave with the command.
  3. the preference value ({workspace}/.theia/settings.json) is not updated while in vscode it is (.vscode).

First, we can check if the workspace config contains editor.autoSave. If yes, we change the value there. If no, we change it in the user config. Can this work?

  • Users get the Code behavior via the menu or command palette.
  • If users want to modify it manually via the settings.json, they know what they're doing.
  • If you're an extension developer, you either want to trigger the default functionality via the command, so we are good. Or you are doing custom things via the preferences service API.

Thoughts? Am I overlooking something?

Copy link
Contributor Author

@colin-grant-work colin-grant-work Mar 12, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the code that actually performs this update in VSCode is not the update method to which you posted the docs earlier in this thread. It's the updateValue method, for which I don't think we have an equivalent. That code looks pretty similar to what you're describing: it loops through all scopes, finding the lowest one in which the value of the given preference isn't currently undefined (with user scope as default), and sets the value there. If the value is being deleted, it deletes it in all scopes in which it's defined.

https://github.com/microsoft/vscode/blob/257fbae3f34804eeb427c10bceb4c0ed95870552/src/vs/workbench/services/filesConfiguration/common/filesConfigurationService.ts#L185-L196

https://github.com/microsoft/vscode/blob/257fbae3f34804eeb427c10bceb4c0ed95870552/src/vs/workbench/services/configuration/browser/configurationService.ts#L295-L317

https://github.com/microsoft/vscode/blob/257fbae3f34804eeb427c10bceb4c0ed95870552/src/vs/workbench/services/configuration/browser/configurationService.ts#L783-L808

If we want to have that logic available for this command, we can implement methods to mirror that in the PreferenceService, or we can just do it manually for this command.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can implement methods to mirror that in the PreferenceService

Good idea. Let's keep the new API aligned to the updateValue from Code. We can use this new API for auto-save and maybe for others too (theming?).

As an extension developer, I would prefer to use an API that has the same semantics as a VS Code extension API. What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've implemented this. I'll add some tests next week to make sure it's doing what it should.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've implemented this. I'll add some tests next week to make sure it's doing what it should.

@vince-fugnitto, the tests are still planned 😃

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@colin-grant-work sorry about that :)

Copy link
Contributor

@kittaakos kittaakos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried it; it works very well. The code looks great. Thank you so much, @colin-grant-work 👍

Copy link
Member

@vince-fugnitto vince-fugnitto left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@colin-grant-work I believe the tests will need adjusting, they currently fail when testing the preferences.

@colin-grant-work colin-grant-work changed the title Change setting of autosave preference to PreferenceScope.User Implement updateValue() method for PreferenceService Mar 19, 2021
@colin-grant-work colin-grant-work force-pushed the bugfix/default-scope branch 3 times, most recently from ba28e45 to 865e92d Compare March 19, 2021 16:20
@colin-grant-work
Copy link
Contributor Author

@vince-fugnitto, I've implemented some tests here and modified the tests that were failing. If you wouldn't mind taking a look, I think it should be just about good to go.

Copy link
Member

@vince-fugnitto vince-fugnitto left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes look good to me, and I confirmed that autoSave now behaves like expected.

I only have a minor comment about the api-test where the import has an error but does not affect functionality.

@@ -30,7 +30,7 @@ describe('Launch Preferences', function () {

const { assert } = chai;

const { PreferenceService, PreferenceScope } = require('@theia/core/lib/browser/preferences/preference-service');
const { PreferenceService, PreferenceScope, PreferenceInspection } = require('@theia/core/lib/browser/preferences/preference-service');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if there is a way to avoid the error we get by this import:

Property 'PreferenceInspection' does not exist on type 'typeof import("/home/evinfug/workspaces/theia/packages/core/src/browser/preferences/preference-service")

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The behavior there seems to be a bit inconsistent between environments, but I've modified the code in a way that seems to make the IDE happy in all of the environments available to me.

Signed-off-by: Colin Grant <colin.grant@ericsson.com>
@colin-grant-work colin-grant-work merged commit edc346b into eclipse-theia:master Mar 23, 2021
@colin-grant-work colin-grant-work deleted the bugfix/default-scope branch March 23, 2021 15:00
@vince-fugnitto vince-fugnitto added this to the 1.12.0 milestone Mar 25, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
preferences issues related to preferences
Projects
None yet
Development

Successfully merging this pull request may close these issues.

preferences: toggling 'auto-save' should update user settings
3 participants