diff --git a/src/extension.ts b/src/extension.ts index b929cc2d..f5bc0180 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -22,6 +22,7 @@ import { CUSTOM_SCHEMA_REQUEST, CUSTOM_CONTENT_REQUEST, SchemaExtensionAPI } fro import { joinPath } from './paths'; import { getJsonSchemaContent, JSONSchemaDocumentContentProvider } from './json-schema-content-provider'; import { JSONSchemaCache } from './json-schema-cache'; +import { getConflictingExtensions, showUninstallConflictsNotification } from './extensionConflicts'; export interface ISchemaAssociations { [pattern: string]: string[]; @@ -104,6 +105,7 @@ export function activate(context: ExtensionContext): SchemaExtensionAPI { workspace.registerTextDocumentContentProvider('json-schema', new JSONSchemaDocumentContentProvider(schemaCache)) ); + findConflicts(); client.onReady().then(() => { // Send a notification to the server with any YAML schema associations in all extensions client.sendNotification(SchemaAssociationNotification.type, getSchemaAssociations()); @@ -111,6 +113,7 @@ export function activate(context: ExtensionContext): SchemaExtensionAPI { // If the extensions change, fire this notification again to pick up on any association changes extensions.onDidChange(() => { client.sendNotification(SchemaAssociationNotification.type, getSchemaAssociations()); + findConflicts(); }); // Tell the server that the client is ready to provide custom schema content client.sendNotification(DynamicCustomSchemaRequestRegistration.type); @@ -131,6 +134,18 @@ export function activate(context: ExtensionContext): SchemaExtensionAPI { return schemaExtensionAPI; } +/** + * Finds extensions that conflict with VSCode-YAML. + * If one or more conflicts are found then show an uninstall notification + * If no conflicts are found then do nothing + */ +function findConflicts(): void { + const conflictingExtensions = getConflictingExtensions(); + if (conflictingExtensions.length > 0) { + showUninstallConflictsNotification(conflictingExtensions); + } +} + function getSchemaAssociations(): ISchemaAssociation[] { const associations: ISchemaAssociation[] = []; extensions.all.forEach((extension) => { diff --git a/src/extensionConflicts.ts b/src/extensionConflicts.ts new file mode 100644 index 00000000..c9a7e5fa --- /dev/null +++ b/src/extensionConflicts.ts @@ -0,0 +1,70 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Red Hat, Inc. All rights reserved.. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +import { commands, Extension, extensions, window } from 'vscode'; + +// A set of VSCode extension ID's that conflict with VSCode-YAML +const azureDeploy = 'ms-vscode-deploy-azure.azure-deploy'; +const conflictingIDs = new Set(['vscoss.vscode-ansible', azureDeploy, 'sysninja.vscode-ansible-mod', 'haaaad.ansible']); + +// A set of VSCode extension ID's that are currently uninstalling +const uninstallingIDs = new Set(); + +/** + * Get all of the installed extensions that currently conflict with VSCode-YAML + */ +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export function getConflictingExtensions(): Extension[] { + const conflictingExtensions = []; + conflictingIDs.forEach((extension) => { + const ext = extensions.getExtension(extension); + if (ext && !uninstallingIDs.has(ext.id)) { + conflictingExtensions.push(ext); + } + }); + return conflictingExtensions; +} + +/** + * Display the uninstall conflicting extension notification if there are any conflicting extensions currently installed + */ +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export function showUninstallConflictsNotification(conflictingExts: Extension[]): void { + // Add all available conflicting extensions to the uninstalling IDs map + for (const extIndex in conflictingExts) { + const ext = conflictingExts[extIndex]; + uninstallingIDs.add(ext.id); + } + + const uninstallMsg = 'Uninstall'; + + // Gather all the conflicting display names + let conflictMsg = ''; + if (conflictingExts.length === 1) { + conflictMsg = `${conflictingExts[0].packageJSON.displayName} extension is incompatible with VSCode-YAML. Please uninstall it.`; + } else { + const extNames = []; + conflictingExts.forEach((ext) => { + extNames.push(ext.packageJSON.displayName); + }); + conflictMsg = `The ${extNames.join(', ')} extensions are incompatible with VSCode-YAML. Please uninstall them.`; + } + + if (conflictingExts.length > 0) { + window.showInformationMessage(conflictMsg, uninstallMsg).then((clickedMsg) => { + if (clickedMsg === uninstallMsg) { + conflictingExts.forEach((ext) => { + commands.executeCommand('workbench.extensions.uninstallExtension', ext.id); + uninstallingIDs.delete(ext.id); + }); + + // The azure deploy extension must be reloaded in order to be completely uninstalled + // eslint-disable-next-line @typescript-eslint/no-explicit-any + if (conflictingExts.findIndex((ext: any) => ext.id === azureDeploy) !== -1) { + commands.executeCommand('workbench.action.reloadWindow'); + } + } + }); + } +}