From 120d1a35a04c395bb30a2aeec5da7d6744aaf2de Mon Sep 17 00:00:00 2001 From: Paul Marechal Date: Thu, 9 Feb 2023 02:48:47 -0500 Subject: [PATCH 1/3] preferences: fix duplicated resolution The `WorkspacePreferenceProvider` can do one of two things: It may return preferences from the current workspace folder if the workspace is a single root workspace, or it may return preferences as defined in the workspace file if the workspace is a multi-root workspace. Whenever we want to resolve a preference, the following scopes are queried: `Default`, `User`, `Workspace`, and `Folder`. When a single root workspace is opened the following happens: - Query `Default` scope [...] - Query `User` scope [...] - Query `Workspace` scope: use `WorkspacePreferenceProvider` which delegates to `FolderPreferenceProvider`. - Query `Folder` scope: use `FoldersPreferenceProvider`. Conclusion: The `FoldersPreferenceProvider` is queried twice. In order to fix that issue this commit introduces a new component: `TogglePreferenceProvider` which extends `PreferenceProvider` and wraps another provider so that it can be enabled/disabled. Whenever we are running a single root workspace, we'll enable the `FoldersPreferenceProvider` used by `WorkspacePreferenceProvider` and disable the one bound to the `Folder` scope. Whenever we are running a multi root workspace, we'll disable the `FoldersPreferenceProvider` used by `WorkspacePreferenceProvider` and enable the one bound to the `Folder` scope. --- .../core/src/browser/preferences/index.ts | 1 + .../preferences/toggle-preference-provider.ts | 105 ++++++++++++++++++ .../browser/folders-preferences-provider.ts | 23 ++-- .../src/browser/preference-bindings.ts | 89 +++++++++++---- .../browser/workspace-preference-provider.ts | 20 +--- 5 files changed, 185 insertions(+), 53 deletions(-) create mode 100644 packages/core/src/browser/preferences/toggle-preference-provider.ts diff --git a/packages/core/src/browser/preferences/index.ts b/packages/core/src/browser/preferences/index.ts index 0b17457b420f5..1abd719074c37 100644 --- a/packages/core/src/browser/preferences/index.ts +++ b/packages/core/src/browser/preferences/index.ts @@ -21,3 +21,4 @@ export * from './preference-provider'; export * from './preference-scope'; export * from './preference-language-override-service'; export * from './preference-validation-service'; +export { TogglePreferenceProvider } from './toggle-preference-provider'; diff --git a/packages/core/src/browser/preferences/toggle-preference-provider.ts b/packages/core/src/browser/preferences/toggle-preference-provider.ts new file mode 100644 index 0000000000000..adc34df7db090 --- /dev/null +++ b/packages/core/src/browser/preferences/toggle-preference-provider.ts @@ -0,0 +1,105 @@ +// ***************************************************************************** +// Copyright (C) 2023 Ericsson and others. +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License v. 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0. +// +// This Source Code may also be made available under the following Secondary +// Licenses when the conditions for such availability set forth in the Eclipse +// Public License v. 2.0 are satisfied: GNU General Public License, version 2 +// with the GNU Classpath Exception which is available at +// https://www.gnu.org/software/classpath/license.html. +// +// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 +// ***************************************************************************** + +/* eslint-disable @typescript-eslint/no-explicit-any */ + +import { URI } from '../../common'; +import { PreferenceProvider, PreferenceProviderDataChanges, PreferenceResolveResult } from './preference-provider'; + +/** + * Allows enabling/disabling a {@link PreferenceProvider} by wrapping it. + */ +export class TogglePreferenceProvider extends PreferenceProvider { + + #enabled: boolean; + + constructor( + enabled: boolean, + protected provider: PreferenceProvider + ) { + super(); + this.#enabled = enabled; + this.provider.ready.then(() => this._ready.resolve()); + this.provider.onDidPreferencesChanged(this.handleDidPreferencesChanged, this, this.toDispose); + } + + get enabled(): boolean { + return this.#enabled; + } + + set enabled(value: boolean) { + if (this.#enabled !== value) { + this.#enabled = value; + this.onDidPreferencesChangedEmitter.fire({}); + } + } + + getPreferences(resourceUri?: string): { [p: string]: any; } { + if (this.enabled) { + return this.provider.getPreferences(resourceUri); + } + return {}; + } + + async setPreference(key: string, value: any, resourceUri?: string): Promise { + if (this.enabled) { + return this.provider.setPreference(key, value, resourceUri); + } + return false; + } + + override get(preferenceName: string, resourceUri?: string): T | undefined { + if (this.enabled) { + return this.provider.get(preferenceName, resourceUri); + } + } + + override resolve(preferenceName: string, resourceUri?: string): PreferenceResolveResult { + if (this.enabled) { + return this.provider.resolve(preferenceName, resourceUri); + } + return {}; + } + + override getDomain(): string[] | undefined { + if (this.enabled) { + return this.provider.getDomain(); + } + } + + override getConfigUri(resourceUri?: string, sectionName?: string): URI | undefined { + if (this.enabled) { + return this.provider.getConfigUri(resourceUri, sectionName); + } + } + + override getContainingConfigUri?(resourceUri?: string, sectionName?: string): URI | undefined { + if (this.enabled) { + return this.provider.getContainingConfigUri?.(resourceUri, sectionName); + } + } + + override dispose(): void { + super.dispose(); + this.provider.dispose(); + } + + protected handleDidPreferencesChanged(event: PreferenceProviderDataChanges): void { + if (this.enabled) { + this.onDidPreferencesChangedEmitter.fire(event); + } + } +} diff --git a/packages/preferences/src/browser/folders-preferences-provider.ts b/packages/preferences/src/browser/folders-preferences-provider.ts index 650091de8ac06..68433e1f10035 100644 --- a/packages/preferences/src/browser/folders-preferences-provider.ts +++ b/packages/preferences/src/browser/folders-preferences-provider.ts @@ -39,21 +39,16 @@ export class FoldersPreferencesProvider extends PreferenceProvider { protected readonly providers = new Map(); @postConstruct() - protected async init(): Promise { - await this.workspaceService.roots; - - this.updateProviders(); - this.workspaceService.onWorkspaceChanged(() => this.updateProviders()); - - const readyPromises: Promise[] = []; - for (const provider of this.providers.values()) { - readyPromises.push(provider.ready.catch(e => console.error(e))); - } - Promise.all(readyPromises).then(() => this._ready.resolve()); + protected init(): void { + this.workspaceService.roots.then(roots => { + this.updateProviders(roots); + this.workspaceService.onWorkspaceChanged(newRoots => this.updateProviders(newRoots)); + const allReady = Array.from(this.providers.values(), provider => provider.ready); + Promise.allSettled(allReady).then(() => this._ready.resolve()); + }); } - protected updateProviders(): void { - const roots = this.workspaceService.tryGetRoots(); + protected updateProviders(roots: FileStat[]): void { const toDelete = new Set(this.providers.keys()); for (const folder of roots) { for (const configPath of this.configurations.getPaths()) { @@ -94,7 +89,6 @@ export class FoldersPreferencesProvider extends PreferenceProvider { return configUri; } } - return undefined; } override getDomain(): string[] { @@ -232,5 +226,4 @@ export class FoldersPreferencesProvider extends PreferenceProvider { this.toDispose.push(provider.onDidPreferencesChanged(change => this.onDidPreferencesChangedEmitter.fire(change))); return provider; } - } diff --git a/packages/preferences/src/browser/preference-bindings.ts b/packages/preferences/src/browser/preference-bindings.ts index f565c594c3f21..42d4e91e7a8ac 100644 --- a/packages/preferences/src/browser/preference-bindings.ts +++ b/packages/preferences/src/browser/preference-bindings.ts @@ -14,8 +14,8 @@ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 // ***************************************************************************** -import { Container, interfaces } from '@theia/core/shared/inversify'; -import { PreferenceProvider, PreferenceScope } from '@theia/core/lib/browser/preferences'; +import { interfaces } from '@theia/core/shared/inversify'; +import { PreferenceProvider, PreferenceScope, TogglePreferenceProvider } from '@theia/core/lib/browser/preferences'; import { UserPreferenceProvider, UserPreferenceProviderFactory } from './user-preference-provider'; import { WorkspacePreferenceProvider } from './workspace-preference-provider'; import { WorkspaceFilePreferenceProvider, WorkspaceFilePreferenceProviderFactory, WorkspaceFilePreferenceProviderOptions } from './workspace-file-preference-provider'; @@ -23,42 +23,83 @@ import { FoldersPreferencesProvider } from './folders-preferences-provider'; import { FolderPreferenceProvider, FolderPreferenceProviderFactory, FolderPreferenceProviderFolder } from './folder-preference-provider'; import { UserConfigsPreferenceProvider } from './user-configs-preference-provider'; import { SectionPreferenceProviderUri, SectionPreferenceProviderSection } from './section-preference-provider'; +import { WorkspaceService } from '@theia/workspace/lib/browser'; export function bindWorkspaceFilePreferenceProvider(bind: interfaces.Bind): void { bind(WorkspaceFilePreferenceProviderFactory).toFactory(ctx => (options: WorkspaceFilePreferenceProviderOptions) => { - const child = new Container({ defaultScope: 'Singleton' }); - child.parent = ctx.container; - child.bind(WorkspaceFilePreferenceProvider).toSelf(); + const child = ctx.container.createChild(); + child.bind(WorkspaceFilePreferenceProvider).toSelf().inSingletonScope(); child.bind(WorkspaceFilePreferenceProviderOptions).toConstantValue(options); return child.get(WorkspaceFilePreferenceProvider); }); } -export function bindFactory(bind: interfaces.Bind, +export function bindFactory( + bind: interfaces.Bind, factoryId: interfaces.ServiceIdentifier, constructor: interfaces.Newable, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - ...parameterBindings: interfaces.ServiceIdentifier[]): void { - bind(factoryId).toFactory(ctx => - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (...args: any[]) => { - const child = new Container({ defaultScope: 'Singleton' }); - child.parent = ctx.container; - for (let i = 0; i < parameterBindings.length; i++) { - child.bind(parameterBindings[i]).toConstantValue(args[i]); - } - child.bind(constructor).to(constructor); - return child.get(constructor); - } - ); + ...parameterBindings: interfaces.ServiceIdentifier[] +): void { + bind(factoryId).toFactory(ctx => (...args: unknown[]) => { + const child = ctx.container.createChild(); + parameterBindings.forEach((parameterBinding, i) => { + child.bind(parameterBinding).toConstantValue(args[i]); + }); + child.bind(constructor).to(constructor).inSingletonScope(); + return child.get(constructor); + }); } export function bindPreferenceProviders(bind: interfaces.Bind, unbind: interfaces.Unbind): void { unbind(PreferenceProvider); - - bind(PreferenceProvider).to(UserConfigsPreferenceProvider).inSingletonScope().whenTargetNamed(PreferenceScope.User); - bind(PreferenceProvider).to(WorkspacePreferenceProvider).inSingletonScope().whenTargetNamed(PreferenceScope.Workspace); - bind(PreferenceProvider).to(FoldersPreferencesProvider).inSingletonScope().whenTargetNamed(PreferenceScope.Folder); + // #region bind FoldersPreferencesProvider based on the status of the workspace: + bind(FoldersPreferencesProvider) + .toSelf() + .inSingletonScope() + .whenTargetIsDefault(); + // Bind a FoldersPreferencesProvider that's only enabled if the workspace + // is a single root workspace: + bind(FoldersPreferencesProvider) + .toDynamicValue(ctx => { + const workspaceService = ctx.container.get(WorkspaceService); + const foldersPreferencesProvider = ctx.container.get(FoldersPreferencesProvider); + const preferenceProvider = new TogglePreferenceProvider(!workspaceService.isMultiRootWorkspaceOpened, foldersPreferencesProvider); + workspaceService.onWorkspaceChanged(() => { + preferenceProvider.enabled = !workspaceService.isMultiRootWorkspaceOpened; + }); + return preferenceProvider; + }) + .inSingletonScope() + .whenTargetNamed(PreferenceScope.Workspace); + // Bind a FoldersPreferencesProvider that's only enabled if the workspace + // is a multi root workspace: + bind(FoldersPreferencesProvider) + .toDynamicValue(ctx => { + const workspaceService = ctx.container.get(WorkspaceService); + const foldersPreferencesProvider = ctx.container.get(FoldersPreferencesProvider); + const preferenceProvider = new TogglePreferenceProvider(workspaceService.isMultiRootWorkspaceOpened, foldersPreferencesProvider); + workspaceService.onWorkspaceChanged(() => { + preferenceProvider.enabled = workspaceService.isMultiRootWorkspaceOpened; + }); + return preferenceProvider; + }) + .inSingletonScope() + .whenTargetNamed(PreferenceScope.Folder); + // #endregion + // #region bind PreferenceProvider by PreferenceScope: + bind(PreferenceProvider) + .to(UserConfigsPreferenceProvider) + .inSingletonScope() + .whenTargetNamed(PreferenceScope.User); + bind(PreferenceProvider) + .to(WorkspacePreferenceProvider) + .inSingletonScope() + .whenTargetNamed(PreferenceScope.Workspace); + bind(PreferenceProvider) + .toDynamicValue(ctx => ctx.container.getNamed(FoldersPreferencesProvider, PreferenceScope.Folder)) + .inSingletonScope() + .whenTargetNamed(PreferenceScope.Folder); + // #endregion bindWorkspaceFilePreferenceProvider(bind); bindFactory(bind, UserPreferenceProviderFactory, UserPreferenceProvider, SectionPreferenceProviderUri, SectionPreferenceProviderSection); bindFactory(bind, FolderPreferenceProviderFactory, FolderPreferenceProvider, SectionPreferenceProviderUri, SectionPreferenceProviderSection, FolderPreferenceProviderFolder); diff --git a/packages/preferences/src/browser/workspace-preference-provider.ts b/packages/preferences/src/browser/workspace-preference-provider.ts index 9959ebccd5c4c..716ceb8d06e3b 100644 --- a/packages/preferences/src/browser/workspace-preference-provider.ts +++ b/packages/preferences/src/browser/workspace-preference-provider.ts @@ -22,6 +22,7 @@ import { DisposableCollection } from '@theia/core/lib/common/disposable'; import { PreferenceScope, PreferenceProvider } from '@theia/core/lib/browser/preferences'; import { WorkspaceService } from '@theia/workspace/lib/browser/workspace-service'; import { WorkspaceFilePreferenceProviderFactory, WorkspaceFilePreferenceProvider } from './workspace-file-preference-provider'; +import { FoldersPreferencesProvider } from './folders-preferences-provider'; @injectable() export class WorkspacePreferenceProvider extends PreferenceProvider { @@ -32,7 +33,7 @@ export class WorkspacePreferenceProvider extends PreferenceProvider { @inject(WorkspaceFilePreferenceProviderFactory) protected readonly workspaceFileProviderFactory: WorkspaceFilePreferenceProviderFactory; - @inject(PreferenceProvider) @named(PreferenceScope.Folder) + @inject(FoldersPreferencesProvider) @named(PreferenceScope.Workspace) protected readonly folderPreferenceProvider: PreferenceProvider; protected readonly toDisposeOnEnsureDelegateUpToDate = new DisposableCollection(); @@ -102,33 +103,24 @@ export class WorkspacePreferenceProvider extends PreferenceProvider { } override get(preferenceName: string, resourceUri: string | undefined = this.ensureResourceUri()): T | undefined { - const delegate = this.delegate; - return delegate ? delegate.get(preferenceName, resourceUri) : undefined; + return this.delegate?.get(preferenceName, resourceUri); } override resolve(preferenceName: string, resourceUri: string | undefined = this.ensureResourceUri()): { value?: T, configUri?: URI } { - const delegate = this.delegate; - return delegate ? delegate.resolve(preferenceName, resourceUri) : {}; + return this.delegate?.resolve(preferenceName, resourceUri) ?? {}; } getPreferences(resourceUri: string | undefined = this.ensureResourceUri()): { [p: string]: any } { - const delegate = this.delegate; - return delegate ? delegate.getPreferences(resourceUri) : {}; + return this.delegate?.getPreferences(resourceUri) ?? {}; } async setPreference(preferenceName: string, value: any, resourceUri: string | undefined = this.ensureResourceUri()): Promise { - const delegate = this.delegate; - if (delegate) { - return delegate.setPreference(preferenceName, value, resourceUri); - } - return false; + return this.delegate?.setPreference(preferenceName, value, resourceUri) ?? false; } protected ensureResourceUri(): string | undefined { if (this.workspaceService.workspace && !this.workspaceService.isMultiRootWorkspaceOpened) { return this.workspaceService.workspace.resource.toString(); } - return undefined; } - } From f25a6925a4107b83c7bc6bac66fe86b9e3f46a7d Mon Sep 17 00:00:00 2001 From: Paul Marechal Date: Fri, 10 Feb 2023 10:32:55 -0500 Subject: [PATCH 2/3] fix preferences clients Since the `PreferenceProvider` for the `Folder` is now completely disabled when in a single root workspace, we need to update clients that were relying on it. --- examples/api-tests/src/preferences.spec.js | 4 +-- .../browser/preferences/preference-service.ts | 27 ++++++++++++++----- .../src/browser/task-configuration-manager.ts | 14 +++++++--- 3 files changed, 33 insertions(+), 12 deletions(-) diff --git a/examples/api-tests/src/preferences.spec.js b/examples/api-tests/src/preferences.spec.js index ab87643e96de1..e039126762b01 100644 --- a/examples/api-tests/src/preferences.spec.js +++ b/examples/api-tests/src/preferences.spec.js @@ -19,12 +19,12 @@ describe('Preferences', function () { this.timeout(5_000); const { assert } = chai; - const { PreferenceProvider } = require('@theia/core/lib/browser/preferences/preference-provider'); const { PreferenceService, PreferenceScope } = require('@theia/core/lib/browser/preferences/preference-service'); const { FileService } = require('@theia/filesystem/lib/browser/file-service'); const { PreferenceLanguageOverrideService } = require('@theia/core/lib/browser/preferences/preference-language-override-service'); const { MonacoTextModelService } = require('@theia/monaco/lib/browser/monaco-text-model-service'); const { PreferenceSchemaProvider } = require('@theia/core/lib/browser/preferences/preference-contribution') + const { FoldersPreferencesProvider } = require('@theia/preferences/lib/browser/folders-preferences-provider'); const { container } = window.theia; /** @type {import ('@theia/core/lib/browser/preferences/preference-service').PreferenceService} */ const preferenceService = container.get(PreferenceService); @@ -34,7 +34,7 @@ describe('Preferences', function () { /** @type {import ('@theia/core/lib/common/uri').default} */ const uri = preferenceService.getConfigUri(PreferenceScope.Workspace); /** @type {import('@theia/preferences/lib/browser/folders-preferences-provider').FoldersPreferencesProvider} */ - const folderPreferences = container.getNamed(PreferenceProvider, PreferenceScope.Folder); + const folderPreferences = container.get(FoldersPreferencesProvider); /** @type PreferenceSchemaProvider */ const schemaProvider = container.get(PreferenceSchemaProvider); const modelService = container.get(MonacoTextModelService); diff --git a/packages/core/src/browser/preferences/preference-service.ts b/packages/core/src/browser/preferences/preference-service.ts index 87252057bfc13..e04dca1985867 100644 --- a/packages/core/src/browser/preferences/preference-service.ts +++ b/packages/core/src/browser/preferences/preference-service.ts @@ -429,16 +429,29 @@ export class PreferenceServiceImpl implements PreferenceService { return { value, configUri }; } - async set(preferenceName: string, value: any, scope: PreferenceScope | undefined, resourceUri?: string): Promise { - const resolvedScope = scope ?? (!resourceUri ? PreferenceScope.Workspace : PreferenceScope.Folder); - if (resolvedScope === PreferenceScope.Folder && !resourceUri) { + async set(preferenceName: string, value: any, scope?: PreferenceScope, resourceUri?: string): Promise { + if (scope === PreferenceScope.Folder && !resourceUri) { throw new Error('Unable to write to Folder Settings because no resource is provided.'); } - const provider = this.getProvider(resolvedScope); - if (provider && await provider.setPreference(preferenceName, value, resourceUri)) { - return; + let scopes: PreferenceScope[]; + if (scope === undefined) { + // Pick default scopes to query: + if (resourceUri) { + // If we don't specify an explicit scope, then try both Folder + // and Workspace scopes with resourceUri: + scopes = [PreferenceScope.Folder, PreferenceScope.Workspace]; + } else { + scopes = [PreferenceScope.Workspace]; + } + } else { + scopes = [scope]; + } + for (scope of scopes) { + if (await this.getProvider(scope)?.setPreference(preferenceName, value, resourceUri)) { + return; + } } - throw new Error(`Unable to write to ${PreferenceScope[resolvedScope]} Settings.`); + throw new Error(`Unable to write to ${PreferenceScope[scope!]} Settings.`); } getBoolean(preferenceName: string): boolean | undefined; diff --git a/packages/task/src/browser/task-configuration-manager.ts b/packages/task/src/browser/task-configuration-manager.ts index 0366cdd197dad..b87a1b8a05384 100644 --- a/packages/task/src/browser/task-configuration-manager.ts +++ b/packages/task/src/browser/task-configuration-manager.ts @@ -89,6 +89,11 @@ export class TaskConfigurationManager { @postConstruct() protected async init(): Promise { this.createModels(); + this.workspacePreferences.onDidPreferencesChanged(e => { + if (e['tasks']) { + this.updateModels(); + } + }); this.folderPreferences.onDidPreferencesChanged(e => { if (e['tasks']) { this.updateModels(); @@ -117,11 +122,13 @@ export class TaskConfigurationManager { .filter(key => key !== TaskScope.Global && key !== TaskScope.Workspace) ); this.updateWorkspaceModel(); + const isFolderWorkspace = this.workspaceService.opened && !this.workspaceService.saved; + const preferenceProvider = isFolderWorkspace ? this.folderPreferences : this.workspacePreferences; for (const rootStat of roots) { const key = rootStat.resource.toString(); toDelete.delete(key); if (!this.models.has(key)) { - const model = new TaskConfigurationModel(key, this.folderPreferences); + const model = new TaskConfigurationModel(key, preferenceProvider); model.onDidChange(() => this.onDidChangeTaskConfigEmitter.fire({ scope: key, type: FileChangeType.UPDATED })); model.onDispose(() => this.models.delete(key)); this.models.set(key, model); @@ -210,7 +217,9 @@ export class TaskConfigurationManager { case TaskScope.Workspace: return PreferenceScope.Workspace; default: - return PreferenceScope.Folder; + return this.workspaceService.isMultiRootWorkspaceOpened + ? PreferenceScope.Folder + : PreferenceScope.Workspace; } } @@ -231,7 +240,6 @@ export class TaskConfigurationManager { if (newDelegate !== this.workspaceDelegate) { this.workspaceDelegate = newDelegate; this.toDisposeOnDelegateChange.dispose(); - const workspaceModel = new TaskConfigurationModel(effectiveScope, newDelegate); this.toDisposeOnDelegateChange.push(workspaceModel); // If the delegate is the folder preference provider, its events will be relayed via the folder scope models. From aad8807fad6fc598bb0da4aa8e00c92b5c173ccf Mon Sep 17 00:00:00 2001 From: Paul Marechal Date: Fri, 10 Feb 2023 11:16:53 -0500 Subject: [PATCH 3/3] update binding --- examples/api-tests/src/launch-preferences.spec.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/api-tests/src/launch-preferences.spec.js b/examples/api-tests/src/launch-preferences.spec.js index 7d0ed25785b95..3371bcf36d24f 100644 --- a/examples/api-tests/src/launch-preferences.spec.js +++ b/examples/api-tests/src/launch-preferences.spec.js @@ -37,6 +37,7 @@ describe('Launch Preferences', function () { const { FileResourceResolver } = require('@theia/filesystem/lib/browser/file-resource'); const { AbstractResourcePreferenceProvider } = require('@theia/preferences/lib/browser/abstract-resource-preference-provider'); const { waitForEvent } = require('@theia/core/lib/common/promise-util'); + const { FoldersPreferencesProvider } = require('@theia/preferences/lib/browser/folders-preferences-provider'); const container = window.theia.container; /** @type {import('@theia/core/lib/browser/preferences/preference-service').PreferenceService} */ @@ -46,7 +47,7 @@ describe('Launch Preferences', function () { /** @type {import('@theia/preferences/lib/browser/workspace-preference-provider').WorkspacePreferenceProvider} */ const workspacePreferences = container.getNamed(PreferenceProvider, PreferenceScope.Workspace); /** @type {import('@theia/preferences/lib/browser/folders-preferences-provider').FoldersPreferencesProvider} */ - const folderPreferences = container.getNamed(PreferenceProvider, PreferenceScope.Folder); + const folderPreferences = container.get(FoldersPreferencesProvider); const workspaceService = container.get(WorkspaceService); const fileService = container.get(FileService); const fileResourceResolver = container.get(FileResourceResolver);