mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-22 17:48:56 +01:00
685 lines
22 KiB
TypeScript
685 lines
22 KiB
TypeScript
/*---------------------------------------------------------------------------------------------
|
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
*--------------------------------------------------------------------------------------------*/
|
|
|
|
import * as nls from 'vs/nls';
|
|
import { URI } from 'vs/base/common/uri';
|
|
import { ICodeEditor, IDiffEditor } from 'vs/editor/browser/editorBrowser';
|
|
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
|
import { Position } from 'vs/editor/common/core/position';
|
|
import { IEditorContribution, IDiffEditorContribution } from 'vs/editor/common/editorCommon';
|
|
import { ITextModel } from 'vs/editor/common/model';
|
|
import { IModelService } from 'vs/editor/common/services/model';
|
|
import { ITextModelService } from 'vs/editor/common/services/resolverService';
|
|
import { MenuId, MenuRegistry, Action2 } from 'vs/platform/actions/common/actions';
|
|
import { CommandsRegistry, ICommandHandlerDescription } from 'vs/platform/commands/common/commands';
|
|
import { ContextKeyExpr, IContextKeyService, ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey';
|
|
import { ServicesAccessor as InstantiationServicesAccessor, BrandedService, IInstantiationService, IConstructorSignature } from 'vs/platform/instantiation/common/instantiation';
|
|
import { IKeybindings, KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
|
import { Registry } from 'vs/platform/registry/common/platform';
|
|
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
|
import { withNullAsUndefined, assertType } from 'vs/base/common/types';
|
|
import { ThemeIcon } from 'vs/base/common/themables';
|
|
import { IDisposable } from 'vs/base/common/lifecycle';
|
|
import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
|
|
import { ILogService } from 'vs/platform/log/common/log';
|
|
|
|
export type ServicesAccessor = InstantiationServicesAccessor;
|
|
export type EditorContributionCtor = IConstructorSignature<IEditorContribution, [ICodeEditor]>;
|
|
export type DiffEditorContributionCtor = IConstructorSignature<IDiffEditorContribution, [IDiffEditor]>;
|
|
|
|
export const enum EditorContributionInstantiation {
|
|
/**
|
|
* The contribution is created eagerly when the {@linkcode ICodeEditor} is instantiated.
|
|
* Only Eager contributions can participate in saving or restoring of view state.
|
|
*/
|
|
Eager,
|
|
|
|
/**
|
|
* The contribution is created at the latest 50ms after the first render after attaching a text model.
|
|
* If the contribution is explicitly requested via `getContribution`, it will be instantiated sooner.
|
|
* If there is idle time available, it will be instantiated sooner.
|
|
*/
|
|
AfterFirstRender,
|
|
|
|
/**
|
|
* The contribution is created before the editor emits events produced by user interaction (mouse events, keyboard events).
|
|
* If the contribution is explicitly requested via `getContribution`, it will be instantiated sooner.
|
|
* If there is idle time available, it will be instantiated sooner.
|
|
*/
|
|
BeforeFirstInteraction,
|
|
|
|
/**
|
|
* The contribution is created when there is idle time available, at the latest 5000ms after the editor creation.
|
|
* If the contribution is explicitly requested via `getContribution`, it will be instantiated sooner.
|
|
*/
|
|
Eventually,
|
|
|
|
/**
|
|
* The contribution is created only when explicitly requested via `getContribution`.
|
|
*/
|
|
Lazy,
|
|
}
|
|
|
|
export interface IEditorContributionDescription {
|
|
readonly id: string;
|
|
readonly ctor: EditorContributionCtor;
|
|
readonly instantiation: EditorContributionInstantiation;
|
|
}
|
|
|
|
export interface IDiffEditorContributionDescription {
|
|
id: string;
|
|
ctor: DiffEditorContributionCtor;
|
|
}
|
|
|
|
//#region Command
|
|
|
|
export interface ICommandKeybindingsOptions extends IKeybindings {
|
|
kbExpr?: ContextKeyExpression | null;
|
|
weight: number;
|
|
/**
|
|
* the default keybinding arguments
|
|
*/
|
|
args?: any;
|
|
}
|
|
export interface ICommandMenuOptions {
|
|
menuId: MenuId;
|
|
group: string;
|
|
order: number;
|
|
when?: ContextKeyExpression;
|
|
title: string;
|
|
icon?: ThemeIcon;
|
|
}
|
|
export interface ICommandOptions {
|
|
id: string;
|
|
precondition: ContextKeyExpression | undefined;
|
|
kbOpts?: ICommandKeybindingsOptions | ICommandKeybindingsOptions[];
|
|
description?: ICommandHandlerDescription;
|
|
menuOpts?: ICommandMenuOptions | ICommandMenuOptions[];
|
|
}
|
|
export abstract class Command {
|
|
public readonly id: string;
|
|
public readonly precondition: ContextKeyExpression | undefined;
|
|
private readonly _kbOpts: ICommandKeybindingsOptions | ICommandKeybindingsOptions[] | undefined;
|
|
private readonly _menuOpts: ICommandMenuOptions | ICommandMenuOptions[] | undefined;
|
|
private readonly _description: ICommandHandlerDescription | undefined;
|
|
|
|
constructor(opts: ICommandOptions) {
|
|
this.id = opts.id;
|
|
this.precondition = opts.precondition;
|
|
this._kbOpts = opts.kbOpts;
|
|
this._menuOpts = opts.menuOpts;
|
|
this._description = opts.description;
|
|
}
|
|
|
|
public register(): void {
|
|
|
|
if (Array.isArray(this._menuOpts)) {
|
|
this._menuOpts.forEach(this._registerMenuItem, this);
|
|
} else if (this._menuOpts) {
|
|
this._registerMenuItem(this._menuOpts);
|
|
}
|
|
|
|
if (this._kbOpts) {
|
|
const kbOptsArr = Array.isArray(this._kbOpts) ? this._kbOpts : [this._kbOpts];
|
|
for (const kbOpts of kbOptsArr) {
|
|
let kbWhen = kbOpts.kbExpr;
|
|
if (this.precondition) {
|
|
if (kbWhen) {
|
|
kbWhen = ContextKeyExpr.and(kbWhen, this.precondition);
|
|
} else {
|
|
kbWhen = this.precondition;
|
|
}
|
|
}
|
|
|
|
const desc = {
|
|
id: this.id,
|
|
weight: kbOpts.weight,
|
|
args: kbOpts.args,
|
|
when: kbWhen,
|
|
primary: kbOpts.primary,
|
|
secondary: kbOpts.secondary,
|
|
win: kbOpts.win,
|
|
linux: kbOpts.linux,
|
|
mac: kbOpts.mac,
|
|
};
|
|
|
|
KeybindingsRegistry.registerKeybindingRule(desc);
|
|
}
|
|
}
|
|
|
|
CommandsRegistry.registerCommand({
|
|
id: this.id,
|
|
handler: (accessor, args) => this.runCommand(accessor, args),
|
|
description: this._description
|
|
});
|
|
}
|
|
|
|
private _registerMenuItem(item: ICommandMenuOptions): void {
|
|
MenuRegistry.appendMenuItem(item.menuId, {
|
|
group: item.group,
|
|
command: {
|
|
id: this.id,
|
|
title: item.title,
|
|
icon: item.icon,
|
|
precondition: this.precondition
|
|
},
|
|
when: item.when,
|
|
order: item.order
|
|
});
|
|
}
|
|
|
|
public abstract runCommand(accessor: ServicesAccessor, args: any): void | Promise<void>;
|
|
}
|
|
|
|
//#endregion Command
|
|
|
|
//#region MultiplexingCommand
|
|
|
|
/**
|
|
* Potential override for a command.
|
|
*
|
|
* @return `true` if the command was successfully run. This stops other overrides from being executed.
|
|
*/
|
|
export type CommandImplementation = (accessor: ServicesAccessor, args: unknown) => boolean | Promise<void>;
|
|
|
|
interface ICommandImplementationRegistration {
|
|
priority: number;
|
|
name: string;
|
|
implementation: CommandImplementation;
|
|
}
|
|
|
|
export class MultiCommand extends Command {
|
|
|
|
private readonly _implementations: ICommandImplementationRegistration[] = [];
|
|
|
|
/**
|
|
* A higher priority gets to be looked at first
|
|
*/
|
|
public addImplementation(priority: number, name: string, implementation: CommandImplementation): IDisposable {
|
|
this._implementations.push({ priority, name, implementation });
|
|
this._implementations.sort((a, b) => b.priority - a.priority);
|
|
return {
|
|
dispose: () => {
|
|
for (let i = 0; i < this._implementations.length; i++) {
|
|
if (this._implementations[i].implementation === implementation) {
|
|
this._implementations.splice(i, 1);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
public runCommand(accessor: ServicesAccessor, args: any): void | Promise<void> {
|
|
const logService = accessor.get(ILogService);
|
|
logService.trace(`Executing Command '${this.id}' which has ${this._implementations.length} bound.`);
|
|
for (const impl of this._implementations) {
|
|
const result = impl.implementation(accessor, args);
|
|
if (result) {
|
|
logService.trace(`Command '${this.id}' was handled by '${impl.name}'.`);
|
|
if (typeof result === 'boolean') {
|
|
return;
|
|
}
|
|
return result;
|
|
}
|
|
}
|
|
logService.trace(`The Command '${this.id}' was not handled by any implementation.`);
|
|
}
|
|
}
|
|
|
|
//#endregion
|
|
|
|
/**
|
|
* A command that delegates to another command's implementation.
|
|
*
|
|
* This lets different commands be registered but share the same implementation
|
|
*/
|
|
export class ProxyCommand extends Command {
|
|
constructor(
|
|
private readonly command: Command,
|
|
opts: ICommandOptions
|
|
) {
|
|
super(opts);
|
|
}
|
|
|
|
public runCommand(accessor: ServicesAccessor, args: any): void | Promise<void> {
|
|
return this.command.runCommand(accessor, args);
|
|
}
|
|
}
|
|
|
|
//#region EditorCommand
|
|
|
|
export interface IContributionCommandOptions<T> extends ICommandOptions {
|
|
handler: (controller: T, args: any) => void;
|
|
}
|
|
export interface EditorControllerCommand<T extends IEditorContribution> {
|
|
new(opts: IContributionCommandOptions<T>): EditorCommand;
|
|
}
|
|
export abstract class EditorCommand extends Command {
|
|
|
|
/**
|
|
* Create a command class that is bound to a certain editor contribution.
|
|
*/
|
|
public static bindToContribution<T extends IEditorContribution>(controllerGetter: (editor: ICodeEditor) => T | null): EditorControllerCommand<T> {
|
|
return class EditorControllerCommandImpl extends EditorCommand {
|
|
private readonly _callback: (controller: T, args: any) => void;
|
|
|
|
constructor(opts: IContributionCommandOptions<T>) {
|
|
super(opts);
|
|
|
|
this._callback = opts.handler;
|
|
}
|
|
|
|
public runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void {
|
|
const controller = controllerGetter(editor);
|
|
if (controller) {
|
|
this._callback(controller, args);
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
public static runEditorCommand(
|
|
accessor: ServicesAccessor,
|
|
args: any,
|
|
precondition: ContextKeyExpression | undefined,
|
|
runner: (accessor: ServicesAccessor | null, editor: ICodeEditor, args: any) => void | Promise<void>
|
|
): void | Promise<void> {
|
|
const codeEditorService = accessor.get(ICodeEditorService);
|
|
|
|
// Find the editor with text focus or active
|
|
const editor = codeEditorService.getFocusedCodeEditor() || codeEditorService.getActiveCodeEditor();
|
|
if (!editor) {
|
|
// well, at least we tried...
|
|
return;
|
|
}
|
|
|
|
return editor.invokeWithinContext((editorAccessor) => {
|
|
const kbService = editorAccessor.get(IContextKeyService);
|
|
if (!kbService.contextMatchesRules(withNullAsUndefined(precondition))) {
|
|
// precondition does not hold
|
|
return;
|
|
}
|
|
|
|
return runner(editorAccessor, editor, args);
|
|
});
|
|
}
|
|
|
|
public runCommand(accessor: ServicesAccessor, args: any): void | Promise<void> {
|
|
return EditorCommand.runEditorCommand(accessor, args, this.precondition, (accessor, editor, args) => this.runEditorCommand(accessor, editor, args));
|
|
}
|
|
|
|
public abstract runEditorCommand(accessor: ServicesAccessor | null, editor: ICodeEditor, args: any): void | Promise<void>;
|
|
}
|
|
|
|
//#endregion EditorCommand
|
|
|
|
//#region EditorAction
|
|
|
|
export interface IEditorActionContextMenuOptions {
|
|
group: string;
|
|
order: number;
|
|
when?: ContextKeyExpression;
|
|
menuId?: MenuId;
|
|
}
|
|
export interface IActionOptions extends ICommandOptions {
|
|
label: string;
|
|
alias: string;
|
|
contextMenuOpts?: IEditorActionContextMenuOptions | IEditorActionContextMenuOptions[];
|
|
}
|
|
|
|
export abstract class EditorAction extends EditorCommand {
|
|
|
|
private static convertOptions(opts: IActionOptions): ICommandOptions {
|
|
|
|
let menuOpts: ICommandMenuOptions[];
|
|
if (Array.isArray(opts.menuOpts)) {
|
|
menuOpts = opts.menuOpts;
|
|
} else if (opts.menuOpts) {
|
|
menuOpts = [opts.menuOpts];
|
|
} else {
|
|
menuOpts = [];
|
|
}
|
|
|
|
function withDefaults(item: Partial<ICommandMenuOptions>): ICommandMenuOptions {
|
|
if (!item.menuId) {
|
|
item.menuId = MenuId.EditorContext;
|
|
}
|
|
if (!item.title) {
|
|
item.title = opts.label;
|
|
}
|
|
item.when = ContextKeyExpr.and(opts.precondition, item.when);
|
|
return <ICommandMenuOptions>item;
|
|
}
|
|
|
|
if (Array.isArray(opts.contextMenuOpts)) {
|
|
menuOpts.push(...opts.contextMenuOpts.map(withDefaults));
|
|
} else if (opts.contextMenuOpts) {
|
|
menuOpts.push(withDefaults(opts.contextMenuOpts));
|
|
}
|
|
|
|
opts.menuOpts = menuOpts;
|
|
return <ICommandOptions>opts;
|
|
}
|
|
|
|
public readonly label: string;
|
|
public readonly alias: string;
|
|
|
|
constructor(opts: IActionOptions) {
|
|
super(EditorAction.convertOptions(opts));
|
|
this.label = opts.label;
|
|
this.alias = opts.alias;
|
|
}
|
|
|
|
public runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void | Promise<void> {
|
|
this.reportTelemetry(accessor, editor);
|
|
return this.run(accessor, editor, args || {});
|
|
}
|
|
|
|
protected reportTelemetry(accessor: ServicesAccessor, editor: ICodeEditor) {
|
|
type EditorActionInvokedClassification = {
|
|
owner: 'alexdima';
|
|
comment: 'An editor action has been invoked.';
|
|
name: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The label of the action that was invoked.' };
|
|
id: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The identifier of the action that was invoked.' };
|
|
};
|
|
type EditorActionInvokedEvent = {
|
|
name: string;
|
|
id: string;
|
|
};
|
|
accessor.get(ITelemetryService).publicLog2<EditorActionInvokedEvent, EditorActionInvokedClassification>('editorActionInvoked', { name: this.label, id: this.id });
|
|
}
|
|
|
|
public abstract run(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void | Promise<void>;
|
|
}
|
|
|
|
export type EditorActionImplementation = (accessor: ServicesAccessor, editor: ICodeEditor, args: any) => boolean | Promise<void>;
|
|
|
|
export class MultiEditorAction extends EditorAction {
|
|
|
|
private readonly _implementations: [number, EditorActionImplementation][] = [];
|
|
|
|
/**
|
|
* A higher priority gets to be looked at first
|
|
*/
|
|
public addImplementation(priority: number, implementation: EditorActionImplementation): IDisposable {
|
|
this._implementations.push([priority, implementation]);
|
|
this._implementations.sort((a, b) => b[0] - a[0]);
|
|
return {
|
|
dispose: () => {
|
|
for (let i = 0; i < this._implementations.length; i++) {
|
|
if (this._implementations[i][1] === implementation) {
|
|
this._implementations.splice(i, 1);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
public run(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void | Promise<void> {
|
|
for (const impl of this._implementations) {
|
|
const result = impl[1](accessor, editor, args);
|
|
if (result) {
|
|
if (typeof result === 'boolean') {
|
|
return;
|
|
}
|
|
return result;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
//#endregion EditorAction
|
|
|
|
//#region EditorAction2
|
|
|
|
export abstract class EditorAction2 extends Action2 {
|
|
|
|
run(accessor: ServicesAccessor, ...args: any[]) {
|
|
// Find the editor with text focus or active
|
|
const codeEditorService = accessor.get(ICodeEditorService);
|
|
const editor = codeEditorService.getFocusedCodeEditor() || codeEditorService.getActiveCodeEditor();
|
|
if (!editor) {
|
|
// well, at least we tried...
|
|
return;
|
|
}
|
|
// precondition does hold
|
|
return editor.invokeWithinContext((editorAccessor) => {
|
|
const kbService = editorAccessor.get(IContextKeyService);
|
|
const logService = editorAccessor.get(ILogService);
|
|
const enabled = kbService.contextMatchesRules(withNullAsUndefined(this.desc.precondition));
|
|
if (!enabled) {
|
|
logService.debug(`[EditorAction2] NOT running command because its precondition is FALSE`, this.desc.id, this.desc.precondition?.serialize());
|
|
return;
|
|
}
|
|
return this.runEditorCommand(editorAccessor, editor!, ...args);
|
|
});
|
|
}
|
|
|
|
abstract runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, ...args: any[]): any;
|
|
}
|
|
|
|
//#endregion
|
|
|
|
// --- Registration of commands and actions
|
|
|
|
|
|
export function registerModelAndPositionCommand(id: string, handler: (accessor: ServicesAccessor, model: ITextModel, position: Position, ...args: any[]) => any) {
|
|
CommandsRegistry.registerCommand(id, function (accessor, ...args) {
|
|
|
|
const instaService = accessor.get(IInstantiationService);
|
|
|
|
const [resource, position] = args;
|
|
assertType(URI.isUri(resource));
|
|
assertType(Position.isIPosition(position));
|
|
|
|
const model = accessor.get(IModelService).getModel(resource);
|
|
if (model) {
|
|
const editorPosition = Position.lift(position);
|
|
return instaService.invokeFunction(handler, model, editorPosition, ...args.slice(2));
|
|
}
|
|
|
|
return accessor.get(ITextModelService).createModelReference(resource).then(reference => {
|
|
return new Promise((resolve, reject) => {
|
|
try {
|
|
const result = instaService.invokeFunction(handler, reference.object.textEditorModel, Position.lift(position), args.slice(2));
|
|
resolve(result);
|
|
} catch (err) {
|
|
reject(err);
|
|
}
|
|
}).finally(() => {
|
|
reference.dispose();
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
export function registerEditorCommand<T extends EditorCommand>(editorCommand: T): T {
|
|
EditorContributionRegistry.INSTANCE.registerEditorCommand(editorCommand);
|
|
return editorCommand;
|
|
}
|
|
|
|
export function registerEditorAction<T extends EditorAction>(ctor: { new(): T }): T {
|
|
const action = new ctor();
|
|
EditorContributionRegistry.INSTANCE.registerEditorAction(action);
|
|
return action;
|
|
}
|
|
|
|
export function registerMultiEditorAction<T extends MultiEditorAction>(action: T): T {
|
|
EditorContributionRegistry.INSTANCE.registerEditorAction(action);
|
|
return action;
|
|
}
|
|
|
|
export function registerInstantiatedEditorAction(editorAction: EditorAction): void {
|
|
EditorContributionRegistry.INSTANCE.registerEditorAction(editorAction);
|
|
}
|
|
|
|
/**
|
|
* Registers an editor contribution. Editor contributions have a lifecycle which is bound
|
|
* to a specific code editor instance.
|
|
*/
|
|
export function registerEditorContribution<Services extends BrandedService[]>(id: string, ctor: { new(editor: ICodeEditor, ...services: Services): IEditorContribution }, instantiation: EditorContributionInstantiation): void {
|
|
EditorContributionRegistry.INSTANCE.registerEditorContribution(id, ctor, instantiation);
|
|
}
|
|
|
|
/**
|
|
* Registers a diff editor contribution. Diff editor contributions have a lifecycle which
|
|
* is bound to a specific diff editor instance.
|
|
*/
|
|
export function registerDiffEditorContribution<Services extends BrandedService[]>(id: string, ctor: { new(editor: IDiffEditor, ...services: Services): IEditorContribution }): void {
|
|
EditorContributionRegistry.INSTANCE.registerDiffEditorContribution(id, ctor);
|
|
}
|
|
|
|
export namespace EditorExtensionsRegistry {
|
|
|
|
export function getEditorCommand(commandId: string): EditorCommand {
|
|
return EditorContributionRegistry.INSTANCE.getEditorCommand(commandId);
|
|
}
|
|
|
|
export function getEditorActions(): Iterable<EditorAction> {
|
|
return EditorContributionRegistry.INSTANCE.getEditorActions();
|
|
}
|
|
|
|
export function getEditorContributions(): IEditorContributionDescription[] {
|
|
return EditorContributionRegistry.INSTANCE.getEditorContributions();
|
|
}
|
|
|
|
export function getSomeEditorContributions(ids: string[]): IEditorContributionDescription[] {
|
|
return EditorContributionRegistry.INSTANCE.getEditorContributions().filter(c => ids.indexOf(c.id) >= 0);
|
|
}
|
|
|
|
export function getDiffEditorContributions(): IDiffEditorContributionDescription[] {
|
|
return EditorContributionRegistry.INSTANCE.getDiffEditorContributions();
|
|
}
|
|
}
|
|
|
|
// Editor extension points
|
|
const Extensions = {
|
|
EditorCommonContributions: 'editor.contributions'
|
|
};
|
|
|
|
class EditorContributionRegistry {
|
|
|
|
public static readonly INSTANCE = new EditorContributionRegistry();
|
|
|
|
private readonly editorContributions: IEditorContributionDescription[] = [];
|
|
private readonly diffEditorContributions: IDiffEditorContributionDescription[] = [];
|
|
private readonly editorActions: EditorAction[] = [];
|
|
private readonly editorCommands: { [commandId: string]: EditorCommand } = Object.create(null);
|
|
|
|
constructor() {
|
|
}
|
|
|
|
public registerEditorContribution<Services extends BrandedService[]>(id: string, ctor: { new(editor: ICodeEditor, ...services: Services): IEditorContribution }, instantiation: EditorContributionInstantiation): void {
|
|
this.editorContributions.push({ id, ctor: ctor as EditorContributionCtor, instantiation });
|
|
}
|
|
|
|
public getEditorContributions(): IEditorContributionDescription[] {
|
|
return this.editorContributions.slice(0);
|
|
}
|
|
|
|
public registerDiffEditorContribution<Services extends BrandedService[]>(id: string, ctor: { new(editor: IDiffEditor, ...services: Services): IEditorContribution }): void {
|
|
this.diffEditorContributions.push({ id, ctor: ctor as DiffEditorContributionCtor });
|
|
}
|
|
|
|
public getDiffEditorContributions(): IDiffEditorContributionDescription[] {
|
|
return this.diffEditorContributions.slice(0);
|
|
}
|
|
|
|
public registerEditorAction(action: EditorAction) {
|
|
action.register();
|
|
this.editorActions.push(action);
|
|
}
|
|
|
|
public getEditorActions(): Iterable<EditorAction> {
|
|
return this.editorActions;
|
|
}
|
|
|
|
public registerEditorCommand(editorCommand: EditorCommand) {
|
|
editorCommand.register();
|
|
this.editorCommands[editorCommand.id] = editorCommand;
|
|
}
|
|
|
|
public getEditorCommand(commandId: string): EditorCommand {
|
|
return (this.editorCommands[commandId] || null);
|
|
}
|
|
|
|
}
|
|
Registry.add(Extensions.EditorCommonContributions, EditorContributionRegistry.INSTANCE);
|
|
|
|
function registerCommand<T extends Command>(command: T): T {
|
|
command.register();
|
|
return command;
|
|
}
|
|
|
|
export const UndoCommand = registerCommand(new MultiCommand({
|
|
id: 'undo',
|
|
precondition: undefined,
|
|
kbOpts: {
|
|
weight: KeybindingWeight.EditorCore,
|
|
primary: KeyMod.CtrlCmd | KeyCode.KeyZ
|
|
},
|
|
menuOpts: [{
|
|
menuId: MenuId.MenubarEditMenu,
|
|
group: '1_do',
|
|
title: nls.localize({ key: 'miUndo', comment: ['&& denotes a mnemonic'] }, "&&Undo"),
|
|
order: 1
|
|
}, {
|
|
menuId: MenuId.CommandPalette,
|
|
group: '',
|
|
title: nls.localize('undo', "Undo"),
|
|
order: 1
|
|
}]
|
|
}));
|
|
|
|
registerCommand(new ProxyCommand(UndoCommand, { id: 'default:undo', precondition: undefined }));
|
|
|
|
export const RedoCommand = registerCommand(new MultiCommand({
|
|
id: 'redo',
|
|
precondition: undefined,
|
|
kbOpts: {
|
|
weight: KeybindingWeight.EditorCore,
|
|
primary: KeyMod.CtrlCmd | KeyCode.KeyY,
|
|
secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KeyZ],
|
|
mac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KeyZ }
|
|
},
|
|
menuOpts: [{
|
|
menuId: MenuId.MenubarEditMenu,
|
|
group: '1_do',
|
|
title: nls.localize({ key: 'miRedo', comment: ['&& denotes a mnemonic'] }, "&&Redo"),
|
|
order: 2
|
|
}, {
|
|
menuId: MenuId.CommandPalette,
|
|
group: '',
|
|
title: nls.localize('redo', "Redo"),
|
|
order: 1
|
|
}]
|
|
}));
|
|
|
|
registerCommand(new ProxyCommand(RedoCommand, { id: 'default:redo', precondition: undefined }));
|
|
|
|
export const SelectAllCommand = registerCommand(new MultiCommand({
|
|
id: 'editor.action.selectAll',
|
|
precondition: undefined,
|
|
kbOpts: {
|
|
weight: KeybindingWeight.EditorCore,
|
|
kbExpr: null,
|
|
primary: KeyMod.CtrlCmd | KeyCode.KeyA
|
|
},
|
|
menuOpts: [{
|
|
menuId: MenuId.MenubarSelectionMenu,
|
|
group: '1_basic',
|
|
title: nls.localize({ key: 'miSelectAll', comment: ['&& denotes a mnemonic'] }, "&&Select All"),
|
|
order: 1
|
|
}, {
|
|
menuId: MenuId.CommandPalette,
|
|
group: '',
|
|
title: nls.localize('selectAll', "Select All"),
|
|
order: 1
|
|
}]
|
|
}));
|