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