UNPKG

@codingame/monaco-vscode-extensions-service-override

Version:

VSCode public API plugged on the monaco editor - extensions service-override

356 lines (352 loc) 16 kB
import { __decorate, __param } from '@codingame/monaco-vscode-api/external/tslib/tslib.es6'; import { localize, localize2 } from '@codingame/monaco-vscode-api/vscode/vs/nls'; import { IExtensionManagementService, IGlobalExtensionEnablementService } from '@codingame/monaco-vscode-api/vscode/vs/platform/extensionManagement/common/extensionManagement.service'; import { StorageScope, StorageTarget } from '@codingame/monaco-vscode-api/vscode/vs/platform/storage/common/storage'; import { IStorageService } from '@codingame/monaco-vscode-api/vscode/vs/platform/storage/common/storage.service'; import { isResolverExtension, ExtensionType } from '@codingame/monaco-vscode-api/vscode/vs/platform/extensions/common/extensions'; import '@codingame/monaco-vscode-api/vscode/vs/platform/instantiation/common/extensions'; import { NotificationPriority } from '@codingame/monaco-vscode-api/vscode/vs/platform/notification/common/notification'; import { INotificationService } from '@codingame/monaco-vscode-api/vscode/vs/platform/notification/common/notification.service'; import { IHostService } from '@codingame/monaco-vscode-api/vscode/vs/workbench/services/host/browser/host.service'; import { registerAction2, Action2, MenuId } from '@codingame/monaco-vscode-api/vscode/vs/platform/actions/common/actions'; import { RawContextKey, ContextKeyExpr } from '@codingame/monaco-vscode-api/vscode/vs/platform/contextkey/common/contextkey'; import { IContextKeyService } from '@codingame/monaco-vscode-api/vscode/vs/platform/contextkey/common/contextkey.service'; import { IDialogService } from '@codingame/monaco-vscode-api/vscode/vs/platform/dialogs/common/dialogs.service'; import { LifecyclePhase } from '@codingame/monaco-vscode-api/vscode/vs/workbench/services/lifecycle/common/lifecycle'; import { Registry } from '@codingame/monaco-vscode-api/vscode/vs/platform/registry/common/platform'; import { Extensions } from '@codingame/monaco-vscode-api/vscode/vs/workbench/common/contributions'; import { ICommandService } from '@codingame/monaco-vscode-api/vscode/vs/platform/commands/common/commands.service'; import { ILogService } from '@codingame/monaco-vscode-api/vscode/vs/platform/log/common/log.service'; import { IProductService } from '@codingame/monaco-vscode-api/vscode/vs/platform/product/common/productService.service'; import { IWorkbenchEnvironmentService } from '@codingame/monaco-vscode-api/vscode/vs/workbench/services/environment/common/environmentService.service'; import { areSameExtensions } from '@codingame/monaco-vscode-api/vscode/vs/platform/extensionManagement/common/extensionManagementUtil'; import { Categories } from '@codingame/monaco-vscode-api/vscode/vs/platform/action/common/actionCommonCategories'; import { IWorkbenchExtensionEnablementService } from '@codingame/monaco-vscode-api/vscode/vs/workbench/services/extensionManagement/common/extensionManagement.service'; import { IExtensionBisectService } from '@codingame/monaco-vscode-api/vscode/vs/workbench/services/extensionManagement/browser/extensionBisect.service'; import Severity from '@codingame/monaco-vscode-api/vscode/vs/base/common/severity'; var ExtensionBisectService_1, ExtensionBisectUi_1; class BisectState { static fromJSON(raw) { if (!raw) { return undefined; } try { const data = JSON.parse(raw); return ( new BisectState(data.extensions, data.low, data.high, data.mid)); } catch { return undefined; } } constructor(extensions, low, high, mid = ((low + high) / 2) | 0) { this.extensions = extensions; this.low = low; this.high = high; this.mid = mid; } } let ExtensionBisectService = class ExtensionBisectService { static { ExtensionBisectService_1 = this; } static { this._storageKey = "extensionBisectState"; } constructor(logService, _storageService, _envService) { this._storageService = _storageService; this._envService = _envService; this._disabled = ( new Map()); const raw = _storageService.get(ExtensionBisectService_1._storageKey, StorageScope.APPLICATION); this._state = BisectState.fromJSON(raw); if (this._state) { const { mid, high } = this._state; for (let i = 0; i < this._state.extensions.length; i++) { const isDisabled = i >= mid && i < high; this._disabled.set(this._state.extensions[i], isDisabled); } logService.warn("extension BISECT active", [...this._disabled]); } } get isActive() { return !!this._state; } get disabledCount() { return this._state ? this._state.high - this._state.mid : -1; } isDisabledByBisect(extension) { if (!this._state) { return false; } if (isResolverExtension(extension.manifest, this._envService.remoteAuthority)) { return false; } if (this._isEnabledInEnv(extension)) { return false; } const disabled = this._disabled.get(extension.identifier.id); return disabled ?? false; } _isEnabledInEnv(extension) { return Array.isArray(this._envService.enableExtensions) && ( this._envService.enableExtensions.some(id => areSameExtensions({ id }, extension.identifier))); } async start(extensions) { if (this._state) { throw ( new Error("invalid state")); } const extensionIds = ( extensions.map(ext => ext.identifier.id)); const newState = ( new BisectState(extensionIds, 0, extensionIds.length, 0)); this._storageService.store( ExtensionBisectService_1._storageKey, JSON.stringify(newState), StorageScope.APPLICATION, StorageTarget.MACHINE ); await this._storageService.flush(); } async next(seeingBad) { if (!this._state) { throw ( new Error("invalid state")); } if (seeingBad && this._state.mid === 0 && this._state.high === this._state.extensions.length) { return { bad: true, id: "" }; } if (this._state.low === this._state.high - 1) { await this.reset(); return { id: this._state.extensions[this._state.low], bad: seeingBad }; } const nextState = ( new BisectState( this._state.extensions, seeingBad ? this._state.low : this._state.mid, seeingBad ? this._state.mid : this._state.high )); this._storageService.store( ExtensionBisectService_1._storageKey, JSON.stringify(nextState), StorageScope.APPLICATION, StorageTarget.MACHINE ); await this._storageService.flush(); return undefined; } async reset() { this._storageService.remove(ExtensionBisectService_1._storageKey, StorageScope.APPLICATION); await this._storageService.flush(); } }; ExtensionBisectService = ExtensionBisectService_1 = ( __decorate([( __param(0, ILogService)), ( __param(1, IStorageService)), ( __param(2, IWorkbenchEnvironmentService))], ExtensionBisectService)); let ExtensionBisectUi = class ExtensionBisectUi { static { ExtensionBisectUi_1 = this; } static { this.ctxIsBisectActive = ( new RawContextKey("isExtensionBisectActive", false)); } constructor( contextKeyService, _extensionBisectService, _notificationService, _commandService ) { this._extensionBisectService = _extensionBisectService; this._notificationService = _notificationService; this._commandService = _commandService; if (_extensionBisectService.isActive) { ExtensionBisectUi_1.ctxIsBisectActive.bindTo(contextKeyService).set(true); this._showBisectPrompt(); } } _showBisectPrompt() { const goodPrompt = { label: ( localize(16529, "I can't reproduce")), run: () => this._commandService.executeCommand("extension.bisect.next", false) }; const badPrompt = { label: ( localize(16530, "I can reproduce")), run: () => this._commandService.executeCommand("extension.bisect.next", true) }; const stop = { label: "Stop Bisect", run: () => this._commandService.executeCommand("extension.bisect.stop") }; const message = this._extensionBisectService.disabledCount === 1 ? ( localize( 16531, "Extension Bisect is active and has disabled 1 extension. Check if you can still reproduce the problem and proceed by selecting from these options." )) : ( localize( 16532, "Extension Bisect is active and has disabled {0} extensions. Check if you can still reproduce the problem and proceed by selecting from these options.", this._extensionBisectService.disabledCount )); this._notificationService.prompt(Severity.Info, message, [goodPrompt, badPrompt, stop], { sticky: true, priority: NotificationPriority.URGENT }); } }; ExtensionBisectUi = ExtensionBisectUi_1 = ( __decorate([( __param(0, IContextKeyService)), ( __param(1, IExtensionBisectService)), ( __param(2, INotificationService)), ( __param(3, ICommandService))], ExtensionBisectUi)); ( Registry.as(Extensions.Workbench)).registerWorkbenchContribution(ExtensionBisectUi, LifecyclePhase.Restored); registerAction2(class extends Action2 { constructor() { super({ id: "extension.bisect.start", title: ( localize2(16533, "Start Extension Bisect")), category: Categories.Help, f1: true, precondition: ( ExtensionBisectUi.ctxIsBisectActive.negate()), menu: { id: MenuId.ViewContainerTitle, when: ( ContextKeyExpr.equals("viewContainer", "workbench.view.extensions")), group: "2_enablement", order: 4 } }); } async run(accessor) { const dialogService = accessor.get(IDialogService); const hostService = accessor.get(IHostService); const extensionManagement = accessor.get(IExtensionManagementService); const extensionEnablementService = accessor.get(IWorkbenchExtensionEnablementService); const extensionsBisect = accessor.get(IExtensionBisectService); const extensions = (await extensionManagement.getInstalled(ExtensionType.User)).filter(ext => extensionEnablementService.isEnabled(ext)); const res = await dialogService.confirm({ message: ( localize(16534, "Extension Bisect")), detail: ( localize( 16535, "Extension Bisect will use binary search to find an extension that causes a problem. During the process the window reloads repeatedly (~{0} times). Each time you must confirm if you are still seeing problems.", 2 + Math.log2(extensions.length) | 0 )), primaryButton: ( localize(16536, "&&Start Extension Bisect")) }); if (res.confirmed) { await extensionsBisect.start(extensions); hostService.reload(); } } }); registerAction2(class extends Action2 { constructor() { super({ id: "extension.bisect.next", title: ( localize2(16537, "Continue Extension Bisect")), category: Categories.Help, f1: true, precondition: ExtensionBisectUi.ctxIsBisectActive }); } async run(accessor, seeingBad) { const dialogService = accessor.get(IDialogService); const hostService = accessor.get(IHostService); const bisectService = accessor.get(IExtensionBisectService); const productService = accessor.get(IProductService); const extensionEnablementService = accessor.get(IGlobalExtensionEnablementService); const commandService = accessor.get(ICommandService); if (!bisectService.isActive) { return; } if (seeingBad === undefined) { const goodBadStopCancel = await this._checkForBad(dialogService, bisectService); if (goodBadStopCancel === null) { return; } seeingBad = goodBadStopCancel; } if (seeingBad === undefined) { await bisectService.reset(); hostService.reload(); return; } const done = await bisectService.next(seeingBad); if (!done) { hostService.reload(); return; } if (done.bad) { await dialogService.info(( localize(16538, "Extension Bisect")), ( localize( 16539, "Extension Bisect is done but no extension has been identified. This might be a problem with {0}.", productService.nameShort ))); } else { const res = await dialogService.confirm({ type: Severity.Info, message: ( localize(16538, "Extension Bisect")), primaryButton: ( localize(16540, "&&Report Issue & Continue")), cancelButton: ( localize(16541, "Continue")), detail: ( localize( 16542, "Extension Bisect is done and has identified {0} as the extension causing the problem.", done.id )), checkbox: { label: ( localize(16543, "Keep this extension disabled")), checked: true } }); if (res.checkboxChecked) { await extensionEnablementService.disableExtension({ id: done.id }, undefined); } if (res.confirmed) { await commandService.executeCommand("workbench.action.openIssueReporter", done.id); } } await bisectService.reset(); hostService.reload(); } async _checkForBad(dialogService, bisectService) { const { result } = await dialogService.prompt({ type: Severity.Info, message: ( localize(16544, "Extension Bisect")), detail: ( localize( 16545, "Extension Bisect is active and has disabled {0} extensions. Check if you can still reproduce the problem and proceed by selecting from these options.", bisectService.disabledCount )), buttons: [{ label: ( localize(16546, "I ca&&n't reproduce")), run: () => false }, { label: ( localize(16547, "I can &&reproduce")), run: () => true }, { label: ( localize(16548, "&&Stop Bisect")), run: () => undefined }], cancelButton: { label: ( localize(16549, "&&Cancel Bisect")), run: () => null } }); return result; } }); registerAction2(class extends Action2 { constructor() { super({ id: "extension.bisect.stop", title: ( localize2(16550, "Stop Extension Bisect")), category: Categories.Help, f1: true, precondition: ExtensionBisectUi.ctxIsBisectActive }); } async run(accessor) { const extensionsBisect = accessor.get(IExtensionBisectService); const hostService = accessor.get(IHostService); await extensionsBisect.reset(); hostService.reload(); } }); export { ExtensionBisectService };