From a206590681f0c0d8d6352180c7ab171180636836 Mon Sep 17 00:00:00 2001 From: Oleksii Kurinnyi Date: Tue, 26 Mar 2019 13:59:12 +0200 Subject: [PATCH] Handle changing of 'launch' property in order to re-build preference schema `UserLaunchProvider`, `WorkspaceLaunchProvider` and `FoldersLaunchProvider` handle changing of 'launch' section of preferences without paying attention whether configuration is valid or not. Once it happens a new preference schema for launch configurations builds. Signed-off-by: Oleksii Kurinnyi --- .../preferences/preference-contribution.ts | 24 ++- .../abstract-launch-preference-provider.ts | 157 ++++++++++++++++++ .../src/browser/debug-frontend-module.ts | 12 +- .../debug/src/browser/debug-preferences.ts | 4 +- .../debug/src/browser/debug-schema-updater.ts | 96 ++++++++++- .../src/browser/folders-launch-provider.ts | 128 ++++++++++++++ .../debug/src/browser/user-launch-provider.ts | 27 +++ .../src/browser/workspace-launch-provider.ts | 27 +++ 8 files changed, 463 insertions(+), 12 deletions(-) create mode 100644 packages/debug/src/browser/abstract-launch-preference-provider.ts create mode 100644 packages/debug/src/browser/folders-launch-provider.ts create mode 100644 packages/debug/src/browser/user-launch-provider.ts create mode 100644 packages/debug/src/browser/workspace-launch-provider.ts diff --git a/packages/core/src/browser/preferences/preference-contribution.ts b/packages/core/src/browser/preferences/preference-contribution.ts index bb2d587b3193f..3626847a75ed4 100644 --- a/packages/core/src/browser/preferences/preference-contribution.ts +++ b/packages/core/src/browser/preferences/preference-contribution.ts @@ -19,6 +19,7 @@ import { inject, injectable, interfaces, named, postConstruct } from 'inversify' import { ContributionProvider, bindContributionProvider, escapeRegExpCharacters, Emitter, Event } from '../../common'; import { PreferenceScope } from './preference-scope'; import { PreferenceProvider, PreferenceProviderPriority, PreferenceProviderDataChange } from './preference-provider'; +import { IJSONSchema } from '../../common/json-schema'; import { PreferenceSchema, PreferenceSchemaProperties, PreferenceDataSchema, PreferenceItem, PreferenceSchemaProperty, PreferenceDataProperty, JsonType @@ -53,6 +54,7 @@ export class PreferenceSchemaProvider extends PreferenceProvider { protected readonly preferences: { [name: string]: any } = {}; protected readonly combinedSchema: PreferenceDataSchema = { properties: {}, patternProperties: {} }; + private remoteSchemas: IJSONSchema[] = []; @inject(ContributionProvider) @named(PreferenceContribution) protected readonly preferenceContributions: ContributionProvider; @@ -182,7 +184,7 @@ export class PreferenceSchemaProvider extends PreferenceProvider { } protected updateValidate(): void { - this.validateFunction = new Ajv().compile(this.combinedSchema); + this.validateFunction = new Ajv({ schemas: this.remoteSchemas }).compile(this.combinedSchema); } validate(name: string, value: any): boolean { @@ -193,12 +195,30 @@ export class PreferenceSchemaProvider extends PreferenceProvider { return this.combinedSchema; } - setSchema(schema: PreferenceSchema): void { + setSchema(schema: PreferenceSchema, remoteSchema?: IJSONSchema): void { const changes = this.doSetSchema(schema); + if (remoteSchema) { + this.doSetRemoteSchema(remoteSchema); + } this.fireDidPreferenceSchemaChanged(); this.emitPreferencesChangedEvent(changes); } + protected doSetRemoteSchema(schema: IJSONSchema): void { + // remove existing remote schema if any + const existingSchemaIndex = this.remoteSchemas.findIndex(s => !!s.$id && !!s.$id && s.$id !== s.$id); + if (existingSchemaIndex) { + this.remoteSchemas.splice(existingSchemaIndex, 1); + } + + this.remoteSchemas.push(schema); + } + + setRemoteSchema(schema: IJSONSchema): void { + this.doSetRemoteSchema(schema); + this.fireDidPreferenceSchemaChanged(); + } + getPreferences(): { [name: string]: any } { return this.preferences; } diff --git a/packages/debug/src/browser/abstract-launch-preference-provider.ts b/packages/debug/src/browser/abstract-launch-preference-provider.ts new file mode 100644 index 0000000000000..d3c5ec0a79ef4 --- /dev/null +++ b/packages/debug/src/browser/abstract-launch-preference-provider.ts @@ -0,0 +1,157 @@ +/******************************************************************************** + * Copyright (C) 2019 Red Hat, Inc. 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 + ********************************************************************************/ + +import { injectable, postConstruct } from 'inversify'; +import { PreferenceScope, PreferenceProvider } from '@theia/core/lib/browser'; +import { Emitter, Event } from '@theia/core'; +import { Deferred } from '@theia/core/lib/common/promise-util'; +import { DisposableCollection } from '@theia/core'; +import { Disposable } from '@theia/core'; + +export interface GlobalLaunchConfig { + version: string; + compounds?: LaunchCompound[]; + configurations: LaunchConfig[]; +} + +export namespace GlobalLaunchConfig { + /* tslint:disable-next-line:no-any */ + export function is(data: any): data is GlobalLaunchConfig { + return !data || (!!data.version && (!data.compounds || Array.isArray(data.compounds)) && Array.isArray(data.configurations)); + } +} + +export interface LaunchConfig { + type: string; + request: string; + name: string; + + /* tslint:disable-next-line:no-any */ + [field: string]: any; +} + +export interface LaunchCompound { + name: string; + configurations: (string | { name: string, folder: string })[]; +} + +export const LaunchPreferenceProvider = Symbol('LaunchConfigurationProvider'); +export interface LaunchPreferenceProvider { + + readonly onDidLaunchChanged: Event; + + ready: Promise; + + getConfigurationNames(withCompounds: boolean, resourceUri?: string): string[]; + +} + +export const FolderLaunchProviderOptions = Symbol('FolderLaunchProviderOptions'); +export interface FolderLaunchProviderOptions { + folderUri: string; +} + +export const LaunchProviderProvider = Symbol('LaunchProviderProvider'); +export type LaunchProviderProvider = (scope: PreferenceScope) => LaunchPreferenceProvider; + +@injectable() +export abstract class AbstractLaunchPreferenceProvider implements LaunchPreferenceProvider, Disposable { + + protected readonly onDidLaunchChangedEmitter = new Emitter(); + readonly onDidLaunchChanged: Event = this.onDidLaunchChangedEmitter.event; + + protected preferences: GlobalLaunchConfig | undefined; + + protected _ready: Deferred = new Deferred(); + + protected readonly toDispose = new DisposableCollection(); + + protected readonly preferenceProvider: PreferenceProvider; + + @postConstruct() + protected init(): void { + this.preferenceProvider.ready + .then(() => this._ready.resolve()) + .catch(() => this._ready.resolve()); + + this.updatePreferences(); + if (this.preferences !== undefined) { + this.emitLaunchChangedEvent(); + } + + this.toDispose.push(this.onDidLaunchChangedEmitter); + this.toDispose.push( + this.preferenceProvider.onDidNotValidPreferencesRead(prefs => { + if (!prefs || !GlobalLaunchConfig.is(prefs.launch)) { + return; + } + if (!prefs.launch && !this.preferences) { + return; + } + this.preferences = prefs.launch; + this.emitLaunchChangedEvent(); + }) + ); + this.toDispose.push( + this.preferenceProvider.onDidPreferencesChanged(prefs => { + if (!prefs || !prefs.launch) { + return; + } + this.updatePreferences(); + this.emitLaunchChangedEvent(); + }) + ); + } + + protected updatePreferences(): void { + const prefs = this.preferenceProvider.getPreferences(); + if (GlobalLaunchConfig.is(prefs.launch)) { + this.preferences = prefs.launch; + } + } + + protected emitLaunchChangedEvent(): void { + this.onDidLaunchChangedEmitter.fire(undefined); + } + + get ready(): Promise { + return this._ready.promise; + } + + dispose(): void { + this.toDispose.dispose(); + } + + getConfigurationNames(withCompounds = true, resourceUri?: string): string[] { + const config = this.preferences; + if (!config) { + return []; + } + + const names = config.configurations + .filter(launchConfig => launchConfig && typeof launchConfig.name === 'string') + .map(launchConfig => launchConfig.name); + if (withCompounds && config.compounds) { + const compoundNames = config.compounds + .filter(compoundConfig => typeof compoundConfig.name === 'string' && compoundConfig.configurations && compoundConfig.configurations.length) + .map(compoundConfig => compoundConfig.name); + names.push(...compoundNames); + } + + return names; + } + +} diff --git a/packages/debug/src/browser/debug-frontend-module.ts b/packages/debug/src/browser/debug-frontend-module.ts index dadb05d52bd72..45ed214a6b355 100644 --- a/packages/debug/src/browser/debug-frontend-module.ts +++ b/packages/debug/src/browser/debug-frontend-module.ts @@ -20,7 +20,7 @@ import { ContainerModule, interfaces } from 'inversify'; import { DebugConfigurationManager } from './debug-configuration-manager'; import { DebugWidget } from './view/debug-widget'; import { DebugPath, DebugService } from '../common/debug-service'; -import { WidgetFactory, WebSocketConnectionProvider, FrontendApplicationContribution, bindViewContribution, KeybindingContext } from '@theia/core/lib/browser'; +import { WidgetFactory, WebSocketConnectionProvider, FrontendApplicationContribution, bindViewContribution, KeybindingContext, PreferenceScope } from '@theia/core/lib/browser'; import { DebugSessionManager } from './debug-session-manager'; import { DebugResourceResolver } from './debug-resource'; import { @@ -44,6 +44,10 @@ import './debug-monaco-contribution'; import { bindDebugPreferences } from './debug-preferences'; import { DebugSchemaUpdater } from './debug-schema-updater'; import { DebugCallStackItemTypeKey } from './debug-call-stack-item-type-key'; +import { LaunchProviderProvider, LaunchPreferenceProvider } from './abstract-launch-preference-provider'; +import { WorkspaceLaunchProvider } from './workspace-launch-provider'; +import { UserLaunchProvider } from './user-launch-provider'; +import { FoldersLaunchProvider } from './folders-launch-provider'; export default new ContainerModule((bind: interfaces.Bind) => { bind(DebugCallStackItemTypeKey).toDynamicValue(({ container }) => @@ -85,5 +89,11 @@ export default new ContainerModule((bind: interfaces.Bind) => { bind(DebugSessionContributionRegistryImpl).toSelf().inSingletonScope(); bind(DebugSessionContributionRegistry).toService(DebugSessionContributionRegistryImpl); + bind(LaunchPreferenceProvider).to(UserLaunchProvider).inSingletonScope().whenTargetNamed(PreferenceScope.User); + bind(LaunchPreferenceProvider).to(WorkspaceLaunchProvider).inSingletonScope().whenTargetNamed(PreferenceScope.Workspace); + bind(LaunchPreferenceProvider).to(FoldersLaunchProvider).inSingletonScope().whenTargetNamed(PreferenceScope.Folder); + bind(LaunchProviderProvider).toFactory(ctx => (scope: PreferenceScope) => + ctx.container.getNamed(LaunchPreferenceProvider, scope)); + bindDebugPreferences(bind); }); diff --git a/packages/debug/src/browser/debug-preferences.ts b/packages/debug/src/browser/debug-preferences.ts index 94e40814c5125..13c7ccf712ad4 100644 --- a/packages/debug/src/browser/debug-preferences.ts +++ b/packages/debug/src/browser/debug-preferences.ts @@ -53,14 +53,14 @@ export class DebugConfiguration { export const DebugPreferences = Symbol('DebugPreferences'); export type DebugPreferences = PreferenceProxy; -export function createDebugreferences(preferences: PreferenceService): DebugPreferences { +export function createDebugPreferences(preferences: PreferenceService): DebugPreferences { return createPreferenceProxy(preferences, debugPreferencesSchema); } export function bindDebugPreferences(bind: interfaces.Bind): void { bind(DebugPreferences).toDynamicValue(ctx => { const preferences = ctx.container.get(PreferenceService); - return createDebugreferences(preferences); + return createDebugPreferences(preferences); }).inSingletonScope(); bind(PreferenceContribution).toConstantValue({ schema: debugPreferencesSchema }); diff --git a/packages/debug/src/browser/debug-schema-updater.ts b/packages/debug/src/browser/debug-schema-updater.ts index 03e4417718173..5969891801cba 100644 --- a/packages/debug/src/browser/debug-schema-updater.ts +++ b/packages/debug/src/browser/debug-schema-updater.ts @@ -14,13 +14,16 @@ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 ********************************************************************************/ -import { injectable, inject } from 'inversify'; +import { injectable, inject, postConstruct } from 'inversify'; import { JsonSchemaStore } from '@theia/core/lib/browser/json-schema-store'; import { InMemoryResources, deepClone } from '@theia/core/lib/common'; import { IJSONSchema } from '@theia/core/lib/common/json-schema'; import URI from '@theia/core/lib/common/uri'; import { DebugService } from '../common/debug-service'; import { debugPreferencesSchema } from './debug-preferences'; +import { WorkspaceService } from '@theia/workspace/lib/browser'; +import { LaunchPreferenceProvider, LaunchProviderProvider } from './abstract-launch-preference-provider'; +import { PreferenceSchema, PreferenceSchemaProvider, PreferenceScope } from '@theia/core/lib/browser'; @injectable() export class DebugSchemaUpdater { @@ -28,10 +31,67 @@ export class DebugSchemaUpdater { @inject(JsonSchemaStore) protected readonly jsonSchemaStore: JsonSchemaStore; @inject(InMemoryResources) protected readonly inmemoryResources: InMemoryResources; @inject(DebugService) protected readonly debug: DebugService; + @inject(WorkspaceService) protected readonly workspaceService: WorkspaceService; + @inject(PreferenceSchemaProvider) protected readonly preferenceSchemaProvider: PreferenceSchemaProvider; + @inject(LaunchProviderProvider) protected readonly launchProviderProvider: LaunchProviderProvider; - async update(): Promise { + private launchProviders: LaunchPreferenceProvider[] = []; + + private debugLaunchSchemaId = 'vscode://debug/launch.json'; + + private schemaIsSet = false; + + @postConstruct() + protected init(): void { + this.initializeLaunchProviders(); + } + + protected initializeLaunchProviders(): void { + PreferenceScope.getScopes().forEach(scope => { + if (scope === PreferenceScope.Default) { + return; + } + const provider = this.launchProviderProvider(scope); + this.launchProviders.push(provider); + }); + this.launchProviders.map(p => + p.onDidLaunchChanged(() => { + this.updateDebugLaunchSchema(); + }) + ); + } + + protected async updateDebugLaunchSchema(): Promise { + const schema = await this.update(); + this.setDebugLaunchSchema(schema); + } + + protected setDebugLaunchSchema(remoteSchema: IJSONSchema) { + if (this.schemaIsSet) { + this.preferenceSchemaProvider.setRemoteSchema(remoteSchema); + return; + } + + this.schemaIsSet = true; + + const debugLaunchPreferencesSchema: PreferenceSchema = { + type: 'object', + scope: 'resource', + properties: { + 'launch': { + type: 'object', + description: "Global debug launch configuration. Should be used as an alternative to 'launch.json' that is shared across workspaces", + default: { configurations: [], compounds: [] }, + $ref: launchSchemaId + } + } + }; + this.preferenceSchemaProvider.setSchema(debugLaunchPreferencesSchema, remoteSchema); + } + + async update(): Promise { const types = await this.debug.debugTypes(); - const launchSchemaUrl = new URI('vscode://debug/launch.json'); + const launchSchemaUrl = new URI(this.debugLaunchSchemaId); const schema = { ...deepClone(launchSchema) }; const items = (schema!.properties!['configurations'].items); @@ -48,6 +108,26 @@ export class DebugSchemaUpdater { } items.defaultSnippets!.push(...await this.debug.getConfigurationSnippets()); + await Promise.all(this.launchProviders.map(l => l.ready)); + + const compoundConfigurationSchema = (schema.properties!.compounds.items as IJSONSchema).properties!.configurations; + const launchNames = this.launchProviders + .map(launch => launch.getConfigurationNames(false)) + .reduce((allNames: string[], names: string[]) => { + names.forEach(name => { + if (allNames.indexOf(name) === -1) { + allNames.push(name); + } + }); + return allNames; + }, []); + (compoundConfigurationSchema.items as IJSONSchema).oneOf![0].enum = launchNames; + (compoundConfigurationSchema.items as IJSONSchema).oneOf![1].properties!.name.enum = launchNames; + + const roots = await this.workspaceService.roots; + const folderNames = roots.map(root => root.uri); + (compoundConfigurationSchema.items as IJSONSchema).oneOf![1].properties!.folder.enum = folderNames; + const contents = JSON.stringify(schema); try { await this.inmemoryResources.update(launchSchemaUrl, contents); @@ -58,15 +138,17 @@ export class DebugSchemaUpdater { url: launchSchemaUrl.toString() }); } + + return schema; } } // debug general schema -const defaultCompound = { name: 'Compound', configurations: [] }; +export const defaultCompound = { name: 'Compound', configurations: [] }; -const launchSchemaId = 'vscode://schemas/launch'; -const launchSchema: IJSONSchema = { - id: launchSchemaId, +export const launchSchemaId = 'vscode://schemas/launch'; +export const launchSchema: IJSONSchema = { + $id: launchSchemaId, type: 'object', title: 'Launch', required: [], diff --git a/packages/debug/src/browser/folders-launch-provider.ts b/packages/debug/src/browser/folders-launch-provider.ts new file mode 100644 index 0000000000000..c602a2fad6c15 --- /dev/null +++ b/packages/debug/src/browser/folders-launch-provider.ts @@ -0,0 +1,128 @@ +/******************************************************************************** + * Copyright (C) 2019 Red Hat, Inc. 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 + ********************************************************************************/ + +import { injectable, inject, postConstruct, named } from 'inversify'; +import { Disposable, DisposableCollection } from '@theia/core'; +import { Emitter, Event } from '@theia/core'; +import { WorkspaceService } from '@theia/workspace/lib/browser'; +import { LaunchPreferenceProvider, GlobalLaunchConfig } from './abstract-launch-preference-provider'; +import { PreferenceScope, PreferenceProvider } from '@theia/core/lib/browser'; +import { Deferred } from '@theia/core/lib/common/promise-util'; + +@injectable() +export class FoldersLaunchProvider implements LaunchPreferenceProvider, Disposable { + + @inject(WorkspaceService) + protected readonly workspaceService: WorkspaceService; + @inject(PreferenceProvider) @named(PreferenceScope.Folder) + protected readonly preferenceProvider: PreferenceProvider; + + protected readonly onDidLaunchChangedEmitter = new Emitter(); + readonly onDidLaunchChanged: Event = this.onDidLaunchChangedEmitter.event; + + protected preferencesNotValid: GlobalLaunchConfig | undefined; + protected preferencesByFolder: Map = new Map(); + + protected _ready: Deferred = new Deferred(); + + protected readonly toDispose = new DisposableCollection(); + + @postConstruct() + protected init(): void { + this.preferenceProvider.ready + .then(() => this._ready.resolve()) + .catch(() => this._ready.resolve()); + + this.updatePreferences(); + if (this.preferencesByFolder.size !== 0) { + this.emitLaunchChangedEvent(); + } + + this.toDispose.push(this.onDidLaunchChangedEmitter); + this.toDispose.push( + this.preferenceProvider.onDidNotValidPreferencesRead(prefs => { + if (!prefs || !GlobalLaunchConfig.is(prefs.launch)) { + return; + } + if (!prefs.launch && !this.preferencesNotValid) { + return; + } + this.preferencesNotValid = prefs.launch; + this.emitLaunchChangedEvent(); + }) + ); + this.toDispose.push( + this.preferenceProvider.onDidPreferencesChanged(prefs => { + if (!prefs || !prefs.launch) { + return; + } + this.updatePreferences(); + this.emitLaunchChangedEvent(); + }) + ); + } + + protected updatePreferences(): void { + this.preferencesByFolder.clear(); + this.preferencesNotValid = undefined; + for (const root of this.workspaceService.tryGetRoots()) { + const preferences = this.preferenceProvider.getPreferences(root.uri); + if (GlobalLaunchConfig.is(preferences.launch)) { + this.preferencesByFolder.set(root.uri, preferences.launch); + } + } + } + + protected emitLaunchChangedEvent(): void { + this.onDidLaunchChangedEmitter.fire(undefined); + } + + get ready(): Promise { + return this._ready.promise; + } + + dispose(): void { + this.toDispose.dispose(); + } + + getConfigurationNames(withCompounds: boolean, resourceUri: string): string[] { + let names: string[] = []; + + const launchConfigurations = Array.from(this.preferencesByFolder.values()); + launchConfigurations.push(this.preferencesNotValid); + + for (const config of launchConfigurations) { + if (!config) { + continue; + } + + const configNames = config.configurations + .filter(launchConfig => launchConfig && typeof launchConfig.name === 'string') + .map(launchConfig => launchConfig.name); + if (withCompounds && config.compounds) { + const compoundNames = config.compounds + .filter(compoundConfig => typeof compoundConfig.name === 'string' && compoundConfig.configurations && compoundConfig.configurations.length) + .map(compoundConfig => compoundConfig.name); + configNames.push(...compoundNames); + } + + names = names.concat(configNames); + } + + return names; + } + +} diff --git a/packages/debug/src/browser/user-launch-provider.ts b/packages/debug/src/browser/user-launch-provider.ts new file mode 100644 index 0000000000000..8beeabfb75cc9 --- /dev/null +++ b/packages/debug/src/browser/user-launch-provider.ts @@ -0,0 +1,27 @@ +/******************************************************************************** + * Copyright (C) 2019 Red Hat, Inc. 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 + ********************************************************************************/ + +import { injectable, inject, named } from 'inversify'; +import { PreferenceProvider, PreferenceScope } from '@theia/core/lib/browser'; +import { AbstractLaunchPreferenceProvider } from './abstract-launch-preference-provider'; + +@injectable() +export class UserLaunchProvider extends AbstractLaunchPreferenceProvider { + + @inject(PreferenceProvider) @named(PreferenceScope.User) + protected readonly preferenceProvider: PreferenceProvider; + +} diff --git a/packages/debug/src/browser/workspace-launch-provider.ts b/packages/debug/src/browser/workspace-launch-provider.ts new file mode 100644 index 0000000000000..312ffbc7f633e --- /dev/null +++ b/packages/debug/src/browser/workspace-launch-provider.ts @@ -0,0 +1,27 @@ +/******************************************************************************** + * Copyright (C) 2019 Red Hat, Inc. 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 + ********************************************************************************/ + +import { injectable, inject, named } from 'inversify'; +import { PreferenceProvider, PreferenceScope } from '@theia/core/lib/browser'; +import { AbstractLaunchPreferenceProvider } from './abstract-launch-preference-provider'; + +@injectable() +export class WorkspaceLaunchProvider extends AbstractLaunchPreferenceProvider { + + @inject(PreferenceProvider) @named(PreferenceScope.Workspace) + protected readonly preferenceProvider: PreferenceProvider; + +}