@codingame/monaco-vscode-extensions-service-override
Version:
VSCode public API plugged on the monaco editor - extensions service-override
356 lines (352 loc) • 16 kB
JavaScript
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 };