@codingame/monaco-vscode-extensions-service-override
Version:
VSCode public API plugged on the monaco editor - extensions service-override
330 lines (327 loc) • 15.2 kB
JavaScript
import { __decorate, __param } from 'vscode/external/tslib/tslib.es6.js';
import { localize, localize2 } from 'vscode/vscode/vs/nls';
import { IExtensionManagementService, IGlobalExtensionEnablementService } from 'vscode/vscode/vs/platform/extensionManagement/common/extensionManagement.service';
import { StorageScope, StorageTarget } from 'vscode/vscode/vs/platform/storage/common/storage';
import { IStorageService } from 'vscode/vscode/vs/platform/storage/common/storage.service';
import { isResolverExtension, ExtensionType } from 'vscode/vscode/vs/platform/extensions/common/extensions';
import 'vscode/vscode/vs/platform/instantiation/common/extensions';
import { NotificationPriority } from 'vscode/vscode/vs/platform/notification/common/notification';
import { INotificationService } from 'vscode/vscode/vs/platform/notification/common/notification.service';
import { IHostService } from 'vscode/vscode/vs/workbench/services/host/browser/host.service';
import { registerAction2, Action2, MenuId } from 'vscode/vscode/vs/platform/actions/common/actions';
import { RawContextKey, ContextKeyExpr } from 'vscode/vscode/vs/platform/contextkey/common/contextkey';
import { IContextKeyService } from 'vscode/vscode/vs/platform/contextkey/common/contextkey.service';
import { IDialogService } from 'vscode/vscode/vs/platform/dialogs/common/dialogs.service';
import { LifecyclePhase } from 'vscode/vscode/vs/workbench/services/lifecycle/common/lifecycle';
import { Registry } from 'vscode/vscode/vs/platform/registry/common/platform';
import { Extensions } from 'vscode/vscode/vs/workbench/common/contributions';
import { ICommandService } from 'vscode/vscode/vs/platform/commands/common/commands.service';
import { ILogService } from 'vscode/vscode/vs/platform/log/common/log.service';
import { IProductService } from 'vscode/vscode/vs/platform/product/common/productService.service';
import { IWorkbenchEnvironmentService } from 'vscode/vscode/vs/workbench/services/environment/common/environmentService.service';
import { areSameExtensions } from 'vscode/vscode/vs/platform/extensionManagement/common/extensionManagementUtil';
import { Categories } from 'vscode/vscode/vs/platform/action/common/actionCommonCategories';
import { IWorkbenchExtensionEnablementService } from 'vscode/vscode/vs/workbench/services/extensionManagement/common/extensionManagement.service';
import { IExtensionBisectService } from 'vscode/vscode/vs/workbench/services/extensionManagement/browser/extensionBisect.service';
import Severity$1 from 'vscode/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(1138, "I can't reproduce")),
run: () => this._commandService.executeCommand('extension.bisect.next', false)
};
const badPrompt = {
label: ( localize(1139, "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(
1140,
"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(
1141,
"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$1.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(1142, '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(1143, "Extension Bisect")),
detail: ( localize(
1144,
"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(1145, "&&Start Extension Bisect"))
});
if (res.confirmed) {
await extensionsBisect.start(extensions);
hostService.reload();
}
}
});
registerAction2(class extends Action2 {
constructor() {
super({
id: 'extension.bisect.next',
title: ( localize2(1146, '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(1147, "Extension Bisect")), ( localize(
1148,
"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$1.Info,
message: ( localize(1147, "Extension Bisect")),
primaryButton: ( localize(1149, "&&Report Issue & Continue")),
cancelButton: ( localize(1150, "Continue")),
detail: ( localize(
1151,
"Extension Bisect is done and has identified {0} as the extension causing the problem.",
done.id
)),
checkbox: { label: ( localize(1152, "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$1.Info,
message: ( localize(1153, "Extension Bisect")),
detail: ( localize(
1154,
"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(1155, "I ca&&n't reproduce")),
run: () => false
},
{
label: ( localize(1156, "I can &&reproduce")),
run: () => true
},
{
label: ( localize(1157, "&&Stop Bisect")),
run: () => undefined
}
],
cancelButton: {
label: ( localize(1158, "&&Cancel Bisect")),
run: () => null
}
});
return result;
}
});
registerAction2(class extends Action2 {
constructor() {
super({
id: 'extension.bisect.stop',
title: ( localize2(1159, '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 };