diff --git a/extensions/configuration-editing/src/settingsDocumentHelper.ts b/extensions/configuration-editing/src/settingsDocumentHelper.ts index a21ec18e310..76c5e3d34e3 100644 --- a/extensions/configuration-editing/src/settingsDocumentHelper.ts +++ b/extensions/configuration-editing/src/settingsDocumentHelper.ts @@ -60,15 +60,6 @@ export class SettingsDocument { return provideInstalledExtensionProposals(alreadyConfigured, `: [\n\t"ui"\n]`, range, true); } - // extensions.supportUntrustedWorkspaces - if (location.path[0] === 'extensions.supportUntrustedWorkspaces' && location.path.length === 2 && location.isAtPropertyKey) { - let alreadyConfigured: string[] = []; - try { - alreadyConfigured = Object.keys(parse(this.document.getText())['extensions.supportUntrustedWorkspaces']); - } catch (e) {/* ignore error */ } - return provideWorkspaceTrustExtensionProposals(alreadyConfigured, range); - } - return this.provideLanguageOverridesCompletionItems(location, position); } diff --git a/src/vs/workbench/contrib/extensions/browser/extensionSupportCompletionProvider.ts b/src/vs/workbench/contrib/extensions/browser/extensionSupportCompletionProvider.ts new file mode 100644 index 00000000000..e124dd0be11 --- /dev/null +++ b/src/vs/workbench/contrib/extensions/browser/extensionSupportCompletionProvider.ts @@ -0,0 +1,61 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { localize } from 'vs/nls'; +import { CancellationToken } from 'vs/base/common/cancellation'; +import { getLocation, parse } from 'vs/base/common/json'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { Position } from 'vs/editor/common/core/position'; +import { ITextModel } from 'vs/editor/common/model'; +import { CompletionContext, CompletionList, CompletionProviderRegistry, CompletionItemKind, CompletionItem } from 'vs/editor/common/modes'; +import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; +import { Range } from 'vs/editor/common/core/range'; + + +export class ExtensionSupportCompletionProvider extends Disposable implements IWorkbenchContribution { + constructor( + @IExtensionManagementService extensionManagementService: IExtensionManagementService, + ) { + super(); + + this._register(CompletionProviderRegistry.register({ language: 'jsonc', pattern: '**/settings.json' }, { + provideCompletionItems: async (model: ITextModel, position: Position, _context: CompletionContext, token: CancellationToken): Promise => { + const suggestions: CompletionItem[] = []; + + const getWordRangeAtPosition = (model: ITextModel, position: Position): Range | null => { + const wordAtPosition = model.getWordAtPosition(position); + return wordAtPosition ? new Range(position.lineNumber, wordAtPosition.startColumn, position.lineNumber, wordAtPosition.endColumn) : null; + }; + + const location = getLocation(model.getValue(), model.getOffsetAt(position)); + const range = getWordRangeAtPosition(model, position) ?? Range.fromPositions(position, position); + + // extensions.supportUntrustedWorkspaces + if (location.path[0] === 'extensions.supportUntrustedWorkspaces' && location.path.length === 2 && location.isAtPropertyKey) { + let alreadyConfigured: string[] = []; + try { + alreadyConfigured = Object.keys(parse(model.getValue())['extensions.supportUntrustedWorkspaces']); + } catch (e) {/* ignore error */ } + + const installedExtensions = (await extensionManagementService.getInstalled()).filter(e => e.manifest.main); + const proposedExtensions = installedExtensions.filter(e => alreadyConfigured.indexOf(e.identifier.id) === -1); + + if (proposedExtensions.length) { + suggestions.push(...proposedExtensions.map(e => { + const text = `"${e.identifier.id}": {\n\t"supported": true,\n\t"version": "${e.manifest.version}"\n},`; + return { label: e.identifier.id, kind: CompletionItemKind.Value, insertText: text, filterText: text, range }; + })); + } else { + const text = '"vscode.csharp": {\n\t"supported": true,\n\t"version": "0.0.0"\n},'; + suggestions.push({ label: localize('exampleExtension', "Example"), kind: CompletionItemKind.Value, insertText: text, filterText: text, range }); + } + } + + return { suggestions }; + } + })); + } +} diff --git a/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts b/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts index 7b258529436..3ceca350c6b 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts @@ -72,6 +72,7 @@ import { Query } from 'vs/workbench/contrib/extensions/common/extensionQuery'; import { Promises } from 'vs/base/common/async'; import { EditorExtensions } from 'vs/workbench/common/editor'; import { WORKSPACE_TRUST_EXTENSION_SUPPORT } from 'vs/workbench/services/workspaces/common/workspaceTrust'; +import { ExtensionSupportCompletionProvider } from 'vs/workbench/contrib/extensions/browser/extensionSupportCompletionProvider'; // Singletons registerSingleton(IExtensionsWorkbenchService, ExtensionsWorkbenchService); @@ -1325,6 +1326,7 @@ workbenchRegistry.registerWorkbenchContribution(ExtensionsViewletViewsContributi workbenchRegistry.registerWorkbenchContribution(ExtensionActivationProgress, LifecyclePhase.Eventually); workbenchRegistry.registerWorkbenchContribution(ExtensionDependencyChecker, LifecyclePhase.Eventually); workbenchRegistry.registerWorkbenchContribution(ExtensionEnablementByWorkspaceTrustRequirement, LifecyclePhase.Restored); +workbenchRegistry.registerWorkbenchContribution(ExtensionSupportCompletionProvider, LifecyclePhase.Restored); // Running Extensions const actionRegistry = Registry.as(WorkbenchActionExtensions.WorkbenchActions);