Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/editor/browser/editorExtensions.ts
5220 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import * as nls from '../../nls.js';
7
import { URI } from '../../base/common/uri.js';
8
import { ICodeEditor, IDiffEditor } from './editorBrowser.js';
9
import { ICodeEditorService } from './services/codeEditorService.js';
10
import { Position } from '../common/core/position.js';
11
import { IEditorContribution, IDiffEditorContribution } from '../common/editorCommon.js';
12
import { ITextModel } from '../common/model.js';
13
import { IModelService } from '../common/services/model.js';
14
import { ITextModelService } from '../common/services/resolverService.js';
15
import { MenuId, MenuRegistry, Action2 } from '../../platform/actions/common/actions.js';
16
import { CommandsRegistry, ICommandMetadata } from '../../platform/commands/common/commands.js';
17
import { ContextKeyExpr, IContextKeyService, ContextKeyExpression } from '../../platform/contextkey/common/contextkey.js';
18
import { ServicesAccessor as InstantiationServicesAccessor, BrandedService, IInstantiationService, IConstructorSignature } from '../../platform/instantiation/common/instantiation.js';
19
import { IKeybindings, KeybindingsRegistry, KeybindingWeight } from '../../platform/keybinding/common/keybindingsRegistry.js';
20
import { Registry } from '../../platform/registry/common/platform.js';
21
import { ITelemetryService } from '../../platform/telemetry/common/telemetry.js';
22
import { assertType } from '../../base/common/types.js';
23
import { ThemeIcon } from '../../base/common/themables.js';
24
import { IDisposable } from '../../base/common/lifecycle.js';
25
import { KeyMod, KeyCode } from '../../base/common/keyCodes.js';
26
import { ILogService } from '../../platform/log/common/log.js';
27
import { getActiveElement } from '../../base/browser/dom.js';
28
import { TriggerInlineEditCommandsRegistry } from './triggerInlineEditCommandsRegistry.js';
29
30
export type ServicesAccessor = InstantiationServicesAccessor;
31
export type EditorContributionCtor = IConstructorSignature<IEditorContribution, [ICodeEditor]>;
32
export type DiffEditorContributionCtor = IConstructorSignature<IDiffEditorContribution, [IDiffEditor]>;
33
34
export const enum EditorContributionInstantiation {
35
/**
36
* The contribution is created eagerly when the {@linkcode ICodeEditor} is instantiated.
37
* Only Eager contributions can participate in saving or restoring of view state.
38
*/
39
Eager,
40
41
/**
42
* The contribution is created at the latest 50ms after the first render after attaching a text model.
43
* If the contribution is explicitly requested via `getContribution`, it will be instantiated sooner.
44
* If there is idle time available, it will be instantiated sooner.
45
*/
46
AfterFirstRender,
47
48
/**
49
* The contribution is created before the editor emits events produced by user interaction (mouse events, keyboard events).
50
* If the contribution is explicitly requested via `getContribution`, it will be instantiated sooner.
51
* If there is idle time available, it will be instantiated sooner.
52
*/
53
BeforeFirstInteraction,
54
55
/**
56
* The contribution is created when there is idle time available, at the latest 5000ms after the editor creation.
57
* If the contribution is explicitly requested via `getContribution`, it will be instantiated sooner.
58
*/
59
Eventually,
60
61
/**
62
* The contribution is created only when explicitly requested via `getContribution`.
63
*/
64
Lazy,
65
}
66
67
export interface IEditorContributionDescription {
68
readonly id: string;
69
readonly ctor: EditorContributionCtor;
70
readonly instantiation: EditorContributionInstantiation;
71
}
72
73
export interface IDiffEditorContributionDescription {
74
id: string;
75
ctor: DiffEditorContributionCtor;
76
}
77
78
//#region Command
79
80
export interface ICommandKeybindingsOptions extends IKeybindings {
81
kbExpr?: ContextKeyExpression | null;
82
weight: number;
83
/**
84
* the default keybinding arguments
85
*/
86
args?: unknown;
87
}
88
export interface ICommandMenuOptions {
89
menuId: MenuId;
90
group: string;
91
order: number;
92
when?: ContextKeyExpression;
93
title: string;
94
icon?: ThemeIcon;
95
}
96
export interface ICommandOptions {
97
id: string;
98
precondition: ContextKeyExpression | undefined;
99
kbOpts?: ICommandKeybindingsOptions | ICommandKeybindingsOptions[];
100
metadata?: ICommandMetadata;
101
menuOpts?: ICommandMenuOptions | ICommandMenuOptions[];
102
canTriggerInlineEdits?: boolean;
103
}
104
export abstract class Command {
105
public readonly id: string;
106
public readonly precondition: ContextKeyExpression | undefined;
107
private readonly _kbOpts: ICommandKeybindingsOptions | ICommandKeybindingsOptions[] | undefined;
108
private readonly _menuOpts: ICommandMenuOptions | ICommandMenuOptions[] | undefined;
109
public readonly metadata: ICommandMetadata | undefined;
110
public readonly canTriggerInlineEdits: boolean | undefined;
111
112
constructor(opts: ICommandOptions) {
113
this.id = opts.id;
114
this.precondition = opts.precondition;
115
this._kbOpts = opts.kbOpts;
116
this._menuOpts = opts.menuOpts;
117
this.metadata = opts.metadata;
118
this.canTriggerInlineEdits = opts.canTriggerInlineEdits;
119
}
120
121
public register(): void {
122
123
if (Array.isArray(this._menuOpts)) {
124
this._menuOpts.forEach(this._registerMenuItem, this);
125
} else if (this._menuOpts) {
126
this._registerMenuItem(this._menuOpts);
127
}
128
129
if (this._kbOpts) {
130
const kbOptsArr = Array.isArray(this._kbOpts) ? this._kbOpts : [this._kbOpts];
131
for (const kbOpts of kbOptsArr) {
132
let kbWhen = kbOpts.kbExpr;
133
if (this.precondition) {
134
if (kbWhen) {
135
kbWhen = ContextKeyExpr.and(kbWhen, this.precondition);
136
} else {
137
kbWhen = this.precondition;
138
}
139
}
140
141
const desc = {
142
id: this.id,
143
weight: kbOpts.weight,
144
args: kbOpts.args,
145
when: kbWhen,
146
primary: kbOpts.primary,
147
secondary: kbOpts.secondary,
148
win: kbOpts.win,
149
linux: kbOpts.linux,
150
mac: kbOpts.mac,
151
};
152
153
KeybindingsRegistry.registerKeybindingRule(desc);
154
}
155
}
156
157
CommandsRegistry.registerCommand({
158
id: this.id,
159
handler: (accessor, args) => this.runCommand(accessor, args),
160
metadata: this.metadata
161
});
162
163
if (this.canTriggerInlineEdits) {
164
TriggerInlineEditCommandsRegistry.registerCommand(this.id);
165
}
166
}
167
168
private _registerMenuItem(item: ICommandMenuOptions): void {
169
MenuRegistry.appendMenuItem(item.menuId, {
170
group: item.group,
171
command: {
172
id: this.id,
173
title: item.title,
174
icon: item.icon,
175
precondition: this.precondition
176
},
177
when: item.when,
178
order: item.order
179
});
180
}
181
182
public abstract runCommand(accessor: ServicesAccessor, args: unknown): void | Promise<void>;
183
}
184
185
//#endregion Command
186
187
//#region MultiplexingCommand
188
189
/**
190
* Potential override for a command.
191
*
192
* @return `true` or a Promise if the command was successfully run. This stops other overrides from being executed.
193
*/
194
export type CommandImplementation = (accessor: ServicesAccessor, args: unknown) => boolean | Promise<void>;
195
196
interface ICommandImplementationRegistration {
197
priority: number;
198
name: string;
199
implementation: CommandImplementation;
200
when?: ContextKeyExpression;
201
}
202
203
export class MultiCommand extends Command {
204
205
private readonly _implementations: ICommandImplementationRegistration[] = [];
206
207
/**
208
* A higher priority gets to be looked at first
209
*/
210
public addImplementation(priority: number, name: string, implementation: CommandImplementation, when?: ContextKeyExpression): IDisposable {
211
this._implementations.push({ priority, name, implementation, when });
212
this._implementations.sort((a, b) => b.priority - a.priority);
213
return {
214
dispose: () => {
215
for (let i = 0; i < this._implementations.length; i++) {
216
if (this._implementations[i].implementation === implementation) {
217
this._implementations.splice(i, 1);
218
return;
219
}
220
}
221
}
222
};
223
}
224
225
public runCommand(accessor: ServicesAccessor, args: unknown): void | Promise<void> {
226
const logService = accessor.get(ILogService);
227
const contextKeyService = accessor.get(IContextKeyService);
228
logService.trace(`Executing Command '${this.id}' which has ${this._implementations.length} bound.`);
229
for (const impl of this._implementations) {
230
if (impl.when) {
231
const context = contextKeyService.getContext(getActiveElement());
232
const value = impl.when.evaluate(context);
233
if (!value) {
234
continue;
235
}
236
}
237
const result = impl.implementation(accessor, args);
238
if (result) {
239
logService.trace(`Command '${this.id}' was handled by '${impl.name}'.`);
240
if (typeof result === 'boolean') {
241
return;
242
}
243
return result;
244
}
245
}
246
logService.trace(`The Command '${this.id}' was not handled by any implementation.`);
247
}
248
}
249
250
//#endregion
251
252
/**
253
* A command that delegates to another command's implementation.
254
*
255
* This lets different commands be registered but share the same implementation
256
*/
257
export class ProxyCommand extends Command {
258
constructor(
259
private readonly command: Command,
260
opts: ICommandOptions
261
) {
262
super(opts);
263
}
264
265
public runCommand(accessor: ServicesAccessor, args: unknown): void | Promise<void> {
266
return this.command.runCommand(accessor, args);
267
}
268
}
269
270
//#region EditorCommand
271
272
export interface IContributionCommandOptions<T> extends ICommandOptions {
273
handler: (controller: T, args: unknown) => void;
274
}
275
export interface EditorControllerCommand<T extends IEditorContribution> {
276
new(opts: IContributionCommandOptions<T>): EditorCommand;
277
}
278
export abstract class EditorCommand extends Command {
279
280
/**
281
* Create a command class that is bound to a certain editor contribution.
282
*/
283
public static bindToContribution<T extends IEditorContribution>(controllerGetter: (editor: ICodeEditor) => T | null): EditorControllerCommand<T> {
284
return class EditorControllerCommandImpl extends EditorCommand {
285
private readonly _callback: (controller: T, args: unknown) => void;
286
287
constructor(opts: IContributionCommandOptions<T>) {
288
super(opts);
289
290
this._callback = opts.handler;
291
}
292
293
public runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, args: unknown): void {
294
const controller = controllerGetter(editor);
295
if (controller) {
296
this._callback(controller, args);
297
}
298
}
299
};
300
}
301
302
public static runEditorCommand<T = unknown>(
303
accessor: ServicesAccessor,
304
args: T,
305
precondition: ContextKeyExpression | undefined,
306
runner: (accessor: ServicesAccessor, editor: ICodeEditor, args: T) => void | Promise<void>
307
): void | Promise<void> {
308
const codeEditorService = accessor.get(ICodeEditorService);
309
310
// Find the editor with text focus or active
311
const editor = codeEditorService.getFocusedCodeEditor() || codeEditorService.getActiveCodeEditor();
312
if (!editor) {
313
// well, at least we tried...
314
return;
315
}
316
317
return editor.invokeWithinContext((editorAccessor) => {
318
const kbService = editorAccessor.get(IContextKeyService);
319
if (!kbService.contextMatchesRules(precondition ?? undefined)) {
320
// precondition does not hold
321
return;
322
}
323
324
return runner(editorAccessor, editor, args);
325
});
326
}
327
328
public runCommand(accessor: ServicesAccessor, args: unknown): void | Promise<void> {
329
return EditorCommand.runEditorCommand(accessor, args, this.precondition, (accessor, editor, args) => this.runEditorCommand(accessor, editor, args));
330
}
331
332
public abstract runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, args: unknown): void | Promise<void>;
333
}
334
335
//#endregion EditorCommand
336
337
//#region EditorAction
338
339
export interface IEditorActionContextMenuOptions {
340
group: string;
341
order: number;
342
when?: ContextKeyExpression;
343
menuId?: MenuId;
344
}
345
export type IActionOptions = ICommandOptions & {
346
contextMenuOpts?: IEditorActionContextMenuOptions | IEditorActionContextMenuOptions[];
347
} & ({
348
label: nls.ILocalizedString;
349
alias?: string;
350
} | {
351
label: string;
352
alias: string;
353
});
354
355
export abstract class EditorAction extends EditorCommand {
356
357
private static convertOptions(opts: IActionOptions): ICommandOptions {
358
359
let menuOpts: ICommandMenuOptions[];
360
if (Array.isArray(opts.menuOpts)) {
361
menuOpts = opts.menuOpts;
362
} else if (opts.menuOpts) {
363
menuOpts = [opts.menuOpts];
364
} else {
365
menuOpts = [];
366
}
367
368
function withDefaults(item: Partial<ICommandMenuOptions>): ICommandMenuOptions {
369
if (!item.menuId) {
370
item.menuId = MenuId.EditorContext;
371
}
372
if (!item.title) {
373
item.title = typeof opts.label === 'string' ? opts.label : opts.label.value;
374
}
375
item.when = ContextKeyExpr.and(opts.precondition, item.when);
376
return <ICommandMenuOptions>item;
377
}
378
379
if (Array.isArray(opts.contextMenuOpts)) {
380
menuOpts.push(...opts.contextMenuOpts.map(withDefaults));
381
} else if (opts.contextMenuOpts) {
382
menuOpts.push(withDefaults(opts.contextMenuOpts));
383
}
384
385
opts.menuOpts = menuOpts;
386
return <ICommandOptions>opts;
387
}
388
389
public readonly label: string;
390
public readonly alias: string;
391
392
constructor(opts: IActionOptions) {
393
super(EditorAction.convertOptions(opts));
394
if (typeof opts.label === 'string') {
395
this.label = opts.label;
396
this.alias = opts.alias ?? opts.label;
397
} else {
398
this.label = opts.label.value;
399
this.alias = opts.alias ?? opts.label.original;
400
}
401
}
402
403
public runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, args: unknown): void | Promise<void> {
404
this.reportTelemetry(accessor, editor);
405
return this.run(accessor, editor, args || {});
406
}
407
408
protected reportTelemetry(accessor: ServicesAccessor, editor: ICodeEditor) {
409
type EditorActionInvokedClassification = {
410
owner: 'alexdima';
411
comment: 'An editor action has been invoked.';
412
name: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The label of the action that was invoked.' };
413
id: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The identifier of the action that was invoked.' };
414
};
415
type EditorActionInvokedEvent = {
416
name: string;
417
id: string;
418
};
419
accessor.get(ITelemetryService).publicLog2<EditorActionInvokedEvent, EditorActionInvokedClassification>('editorActionInvoked', { name: this.label, id: this.id });
420
}
421
422
public abstract run(accessor: ServicesAccessor, editor: ICodeEditor, args: unknown): void | Promise<void>;
423
}
424
425
export type EditorActionImplementation = (accessor: ServicesAccessor, editor: ICodeEditor, args: unknown) => boolean | Promise<void>;
426
427
export class MultiEditorAction extends EditorAction {
428
429
private readonly _implementations: [number, EditorActionImplementation][] = [];
430
431
/**
432
* A higher priority gets to be looked at first
433
*/
434
public addImplementation(priority: number, implementation: EditorActionImplementation): IDisposable {
435
this._implementations.push([priority, implementation]);
436
this._implementations.sort((a, b) => b[0] - a[0]);
437
return {
438
dispose: () => {
439
for (let i = 0; i < this._implementations.length; i++) {
440
if (this._implementations[i][1] === implementation) {
441
this._implementations.splice(i, 1);
442
return;
443
}
444
}
445
}
446
};
447
}
448
449
public run(accessor: ServicesAccessor, editor: ICodeEditor, args: unknown): void | Promise<void> {
450
for (const impl of this._implementations) {
451
const result = impl[1](accessor, editor, args);
452
if (result) {
453
if (typeof result === 'boolean') {
454
return;
455
}
456
return result;
457
}
458
}
459
}
460
461
}
462
463
//#endregion EditorAction
464
465
//#region EditorAction2
466
467
export abstract class EditorAction2 extends Action2 {
468
469
run(accessor: ServicesAccessor, ...args: unknown[]) {
470
// Find the editor with text focus or active
471
const codeEditorService = accessor.get(ICodeEditorService);
472
const editor = codeEditorService.getFocusedCodeEditor() || codeEditorService.getActiveCodeEditor();
473
if (!editor) {
474
// well, at least we tried...
475
return;
476
}
477
// precondition does hold
478
return editor.invokeWithinContext((editorAccessor) => {
479
const kbService = editorAccessor.get(IContextKeyService);
480
const logService = editorAccessor.get(ILogService);
481
const enabled = kbService.contextMatchesRules(this.desc.precondition ?? undefined);
482
if (!enabled) {
483
logService.debug(`[EditorAction2] NOT running command because its precondition is FALSE`, this.desc.id, this.desc.precondition?.serialize());
484
return;
485
}
486
return this.runEditorCommand(editorAccessor, editor, ...args);
487
});
488
}
489
490
abstract runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, ...args: unknown[]): unknown;
491
}
492
493
//#endregion
494
495
// --- Registration of commands and actions
496
497
498
export function registerModelAndPositionCommand(id: string, handler: (accessor: ServicesAccessor, model: ITextModel, position: Position, ...args: unknown[]) => unknown) {
499
CommandsRegistry.registerCommand(id, function (accessor, ...args) {
500
501
const instaService = accessor.get(IInstantiationService);
502
503
const [resource, position] = args;
504
assertType(URI.isUri(resource));
505
assertType(Position.isIPosition(position));
506
507
const model = accessor.get(IModelService).getModel(resource);
508
if (model) {
509
const editorPosition = Position.lift(position);
510
return instaService.invokeFunction(handler, model, editorPosition, ...args.slice(2));
511
}
512
513
return accessor.get(ITextModelService).createModelReference(resource).then(reference => {
514
return new Promise((resolve, reject) => {
515
try {
516
const result = instaService.invokeFunction(handler, reference.object.textEditorModel, Position.lift(position), args.slice(2));
517
resolve(result);
518
} catch (err) {
519
reject(err);
520
}
521
}).finally(() => {
522
reference.dispose();
523
});
524
});
525
});
526
}
527
528
export function registerEditorCommand<T extends EditorCommand>(editorCommand: T): T {
529
EditorContributionRegistry.INSTANCE.registerEditorCommand(editorCommand);
530
return editorCommand;
531
}
532
533
export function registerEditorAction<T extends EditorAction>(ctor: { new(): T }): T {
534
const action = new ctor();
535
EditorContributionRegistry.INSTANCE.registerEditorAction(action);
536
return action;
537
}
538
539
export function registerMultiEditorAction<T extends MultiEditorAction>(action: T): T {
540
EditorContributionRegistry.INSTANCE.registerEditorAction(action);
541
return action;
542
}
543
544
export function registerInstantiatedEditorAction(editorAction: EditorAction): void {
545
EditorContributionRegistry.INSTANCE.registerEditorAction(editorAction);
546
}
547
548
/**
549
* Registers an editor contribution. Editor contributions have a lifecycle which is bound
550
* to a specific code editor instance.
551
*/
552
export function registerEditorContribution<Services extends BrandedService[]>(id: string, ctor: { new(editor: ICodeEditor, ...services: Services): IEditorContribution }, instantiation: EditorContributionInstantiation): void {
553
EditorContributionRegistry.INSTANCE.registerEditorContribution(id, ctor, instantiation);
554
}
555
556
/**
557
* Registers a diff editor contribution. Diff editor contributions have a lifecycle which
558
* is bound to a specific diff editor instance.
559
*/
560
export function registerDiffEditorContribution<Services extends BrandedService[]>(id: string, ctor: { new(editor: IDiffEditor, ...services: Services): IEditorContribution }): void {
561
EditorContributionRegistry.INSTANCE.registerDiffEditorContribution(id, ctor);
562
}
563
564
export namespace EditorExtensionsRegistry {
565
566
export function getEditorCommand(commandId: string): EditorCommand {
567
return EditorContributionRegistry.INSTANCE.getEditorCommand(commandId);
568
}
569
570
export function getEditorActions(): Iterable<EditorAction> {
571
return EditorContributionRegistry.INSTANCE.getEditorActions();
572
}
573
574
export function getEditorContributions(): IEditorContributionDescription[] {
575
return EditorContributionRegistry.INSTANCE.getEditorContributions();
576
}
577
578
export function getSomeEditorContributions(ids: string[]): IEditorContributionDescription[] {
579
return EditorContributionRegistry.INSTANCE.getEditorContributions().filter(c => ids.indexOf(c.id) >= 0);
580
}
581
582
export function getDiffEditorContributions(): IDiffEditorContributionDescription[] {
583
return EditorContributionRegistry.INSTANCE.getDiffEditorContributions();
584
}
585
}
586
587
// Editor extension points
588
const Extensions = {
589
EditorCommonContributions: 'editor.contributions'
590
};
591
592
class EditorContributionRegistry {
593
594
public static readonly INSTANCE = new EditorContributionRegistry();
595
596
private readonly editorContributions: IEditorContributionDescription[] = [];
597
private readonly diffEditorContributions: IDiffEditorContributionDescription[] = [];
598
private readonly editorActions: EditorAction[] = [];
599
private readonly editorCommands: { [commandId: string]: EditorCommand } = Object.create(null);
600
601
constructor() {
602
}
603
604
public registerEditorContribution<Services extends BrandedService[]>(id: string, ctor: { new(editor: ICodeEditor, ...services: Services): IEditorContribution }, instantiation: EditorContributionInstantiation): void {
605
this.editorContributions.push({ id, ctor: ctor as EditorContributionCtor, instantiation });
606
}
607
608
public getEditorContributions(): IEditorContributionDescription[] {
609
return this.editorContributions.slice(0);
610
}
611
612
public registerDiffEditorContribution<Services extends BrandedService[]>(id: string, ctor: { new(editor: IDiffEditor, ...services: Services): IEditorContribution }): void {
613
this.diffEditorContributions.push({ id, ctor: ctor as DiffEditorContributionCtor });
614
}
615
616
public getDiffEditorContributions(): IDiffEditorContributionDescription[] {
617
return this.diffEditorContributions.slice(0);
618
}
619
620
public registerEditorAction(action: EditorAction) {
621
action.register();
622
this.editorActions.push(action);
623
}
624
625
public getEditorActions(): Iterable<EditorAction> {
626
return this.editorActions;
627
}
628
629
public registerEditorCommand(editorCommand: EditorCommand) {
630
editorCommand.register();
631
this.editorCommands[editorCommand.id] = editorCommand;
632
}
633
634
public getEditorCommand(commandId: string): EditorCommand {
635
return (this.editorCommands[commandId] || null);
636
}
637
638
}
639
Registry.add(Extensions.EditorCommonContributions, EditorContributionRegistry.INSTANCE);
640
641
function registerCommand<T extends Command>(command: T): T {
642
command.register();
643
return command;
644
}
645
646
export const UndoCommand = registerCommand(new MultiCommand({
647
id: 'undo',
648
precondition: undefined,
649
kbOpts: {
650
weight: KeybindingWeight.EditorCore,
651
primary: KeyMod.CtrlCmd | KeyCode.KeyZ
652
},
653
menuOpts: [{
654
menuId: MenuId.MenubarEditMenu,
655
group: '1_do',
656
title: nls.localize({ key: 'miUndo', comment: ['&& denotes a mnemonic'] }, "&&Undo"),
657
order: 1
658
}, {
659
menuId: MenuId.CommandPalette,
660
group: '',
661
title: nls.localize('undo', "Undo"),
662
order: 1
663
}, {
664
menuId: MenuId.SimpleEditorContext,
665
group: '1_do',
666
title: nls.localize('undo', "Undo"),
667
order: 1
668
}]
669
}));
670
671
registerCommand(new ProxyCommand(UndoCommand, { id: 'default:undo', precondition: undefined }));
672
673
export const RedoCommand = registerCommand(new MultiCommand({
674
id: 'redo',
675
precondition: undefined,
676
kbOpts: {
677
weight: KeybindingWeight.EditorCore,
678
primary: KeyMod.CtrlCmd | KeyCode.KeyY,
679
secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KeyZ],
680
mac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KeyZ }
681
},
682
menuOpts: [{
683
menuId: MenuId.MenubarEditMenu,
684
group: '1_do',
685
title: nls.localize({ key: 'miRedo', comment: ['&& denotes a mnemonic'] }, "&&Redo"),
686
order: 2
687
}, {
688
menuId: MenuId.CommandPalette,
689
group: '',
690
title: nls.localize('redo', "Redo"),
691
order: 1
692
}, {
693
menuId: MenuId.SimpleEditorContext,
694
group: '1_do',
695
title: nls.localize('redo', "Redo"),
696
order: 2
697
}]
698
}));
699
700
registerCommand(new ProxyCommand(RedoCommand, { id: 'default:redo', precondition: undefined }));
701
702
export const SelectAllCommand = registerCommand(new MultiCommand({
703
id: 'editor.action.selectAll',
704
precondition: undefined,
705
kbOpts: {
706
weight: KeybindingWeight.EditorCore,
707
kbExpr: null,
708
primary: KeyMod.CtrlCmd | KeyCode.KeyA
709
},
710
menuOpts: [{
711
menuId: MenuId.MenubarSelectionMenu,
712
group: '1_basic',
713
title: nls.localize({ key: 'miSelectAll', comment: ['&& denotes a mnemonic'] }, "&&Select All"),
714
order: 1
715
}, {
716
menuId: MenuId.CommandPalette,
717
group: '',
718
title: nls.localize('selectAll', "Select All"),
719
order: 1
720
}, {
721
menuId: MenuId.SimpleEditorContext,
722
group: '9_select',
723
title: nls.localize('selectAll', "Select All"),
724
order: 1
725
}]
726
}));
727
728