Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/editor/browser/coreCommands.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 { isFirefox } from '../../base/browser/browser.js';
8
import { KeyCode, KeyMod } from '../../base/common/keyCodes.js';
9
import * as types from '../../base/common/types.js';
10
import { status } from '../../base/browser/ui/aria/aria.js';
11
import { ICodeEditor } from './editorBrowser.js';
12
import { Command, EditorCommand, ICommandOptions, registerEditorCommand, MultiCommand, UndoCommand, RedoCommand, SelectAllCommand } from './editorExtensions.js';
13
import { ICodeEditorService } from './services/codeEditorService.js';
14
import { ColumnSelection, IColumnSelectResult } from '../common/cursor/cursorColumnSelection.js';
15
import { CursorState, EditOperationType, IColumnSelectData, PartialCursorState } from '../common/cursorCommon.js';
16
import { DeleteOperations } from '../common/cursor/cursorDeleteOperations.js';
17
import { CursorChangeReason } from '../common/cursorEvents.js';
18
import { CursorMove as CursorMove_, CursorMoveCommands } from '../common/cursor/cursorMoveCommands.js';
19
import { TypeOperations } from '../common/cursor/cursorTypeOperations.js';
20
import { IPosition, Position } from '../common/core/position.js';
21
import { Range } from '../common/core/range.js';
22
import { Handler, ScrollType } from '../common/editorCommon.js';
23
import { EditorContextKeys } from '../common/editorContextKeys.js';
24
import { VerticalRevealType } from '../common/viewEvents.js';
25
import { ICommandMetadata } from '../../platform/commands/common/commands.js';
26
import { ContextKeyExpr } from '../../platform/contextkey/common/contextkey.js';
27
import { ServicesAccessor } from '../../platform/instantiation/common/instantiation.js';
28
import { KeybindingWeight, KeybindingsRegistry } from '../../platform/keybinding/common/keybindingsRegistry.js';
29
import { EditorOption } from '../common/config/editorOptions.js';
30
import { IViewModel } from '../common/viewModel.js';
31
import { ISelection } from '../common/core/selection.js';
32
import { getActiveElement, isEditableElement } from '../../base/browser/dom.js';
33
import { EnterOperation } from '../common/cursor/cursorTypeEditOperations.js';
34
35
const CORE_WEIGHT = KeybindingWeight.EditorCore;
36
37
export abstract class CoreEditorCommand<T> extends EditorCommand {
38
public runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, args?: Partial<T> | null): void {
39
const viewModel = editor._getViewModel();
40
if (!viewModel) {
41
// the editor has no view => has no cursors
42
return;
43
}
44
this.runCoreEditorCommand(viewModel, args || {});
45
}
46
47
public abstract runCoreEditorCommand(viewModel: IViewModel, args: Partial<T>): void;
48
}
49
50
export namespace EditorScroll_ {
51
52
const isEditorScrollArgs = function (arg: any): boolean {
53
if (!types.isObject(arg)) {
54
return false;
55
}
56
57
const scrollArg: RawArguments = arg;
58
59
if (!types.isString(scrollArg.to)) {
60
return false;
61
}
62
63
if (!types.isUndefined(scrollArg.by) && !types.isString(scrollArg.by)) {
64
return false;
65
}
66
67
if (!types.isUndefined(scrollArg.value) && !types.isNumber(scrollArg.value)) {
68
return false;
69
}
70
71
if (!types.isUndefined(scrollArg.revealCursor) && !types.isBoolean(scrollArg.revealCursor)) {
72
return false;
73
}
74
75
return true;
76
};
77
78
export const metadata: ICommandMetadata = {
79
description: 'Scroll editor in the given direction',
80
args: [
81
{
82
name: 'Editor scroll argument object',
83
description: `Property-value pairs that can be passed through this argument:
84
* 'to': A mandatory direction value.
85
\`\`\`
86
'up', 'down'
87
\`\`\`
88
* 'by': Unit to move. Default is computed based on 'to' value.
89
\`\`\`
90
'line', 'wrappedLine', 'page', 'halfPage', 'editor'
91
\`\`\`
92
* 'value': Number of units to move. Default is '1'.
93
* 'revealCursor': If 'true' reveals the cursor if it is outside view port.
94
`,
95
constraint: isEditorScrollArgs,
96
schema: {
97
'type': 'object',
98
'required': ['to'],
99
'properties': {
100
'to': {
101
'type': 'string',
102
'enum': ['up', 'down']
103
},
104
'by': {
105
'type': 'string',
106
'enum': ['line', 'wrappedLine', 'page', 'halfPage', 'editor']
107
},
108
'value': {
109
'type': 'number',
110
'default': 1
111
},
112
'revealCursor': {
113
'type': 'boolean',
114
}
115
}
116
}
117
}
118
]
119
};
120
121
/**
122
* Directions in the view for editor scroll command.
123
*/
124
export const RawDirection = {
125
Up: 'up',
126
Right: 'right',
127
Down: 'down',
128
Left: 'left'
129
};
130
131
/**
132
* Units for editor scroll 'by' argument
133
*/
134
export const RawUnit = {
135
Line: 'line',
136
WrappedLine: 'wrappedLine',
137
Page: 'page',
138
HalfPage: 'halfPage',
139
Editor: 'editor',
140
Column: 'column'
141
};
142
143
/**
144
* Arguments for editor scroll command
145
*/
146
export interface RawArguments {
147
to: string;
148
by?: string;
149
value?: number;
150
revealCursor?: boolean;
151
select?: boolean;
152
}
153
154
export function parse(args: Partial<RawArguments>): ParsedArguments | null {
155
let direction: Direction;
156
switch (args.to) {
157
case RawDirection.Up:
158
direction = Direction.Up;
159
break;
160
case RawDirection.Right:
161
direction = Direction.Right;
162
break;
163
case RawDirection.Down:
164
direction = Direction.Down;
165
break;
166
case RawDirection.Left:
167
direction = Direction.Left;
168
break;
169
default:
170
// Illegal arguments
171
return null;
172
}
173
174
let unit: Unit;
175
switch (args.by) {
176
case RawUnit.Line:
177
unit = Unit.Line;
178
break;
179
case RawUnit.WrappedLine:
180
unit = Unit.WrappedLine;
181
break;
182
case RawUnit.Page:
183
unit = Unit.Page;
184
break;
185
case RawUnit.HalfPage:
186
unit = Unit.HalfPage;
187
break;
188
case RawUnit.Editor:
189
unit = Unit.Editor;
190
break;
191
case RawUnit.Column:
192
unit = Unit.Column;
193
break;
194
default:
195
unit = Unit.WrappedLine;
196
}
197
198
const value = Math.floor(args.value || 1);
199
const revealCursor = !!args.revealCursor;
200
201
return {
202
direction: direction,
203
unit: unit,
204
value: value,
205
revealCursor: revealCursor,
206
select: (!!args.select)
207
};
208
}
209
210
export interface ParsedArguments {
211
direction: Direction;
212
unit: Unit;
213
value: number;
214
revealCursor: boolean;
215
select: boolean;
216
}
217
218
219
export const enum Direction {
220
Up = 1,
221
Right = 2,
222
Down = 3,
223
Left = 4
224
}
225
226
export const enum Unit {
227
Line = 1,
228
WrappedLine = 2,
229
Page = 3,
230
HalfPage = 4,
231
Editor = 5,
232
Column = 6
233
}
234
}
235
236
export namespace RevealLine_ {
237
238
const isRevealLineArgs = function (arg: any): boolean {
239
if (!types.isObject(arg)) {
240
return false;
241
}
242
243
const reveaLineArg: RawArguments = arg;
244
245
if (!types.isNumber(reveaLineArg.lineNumber) && !types.isString(reveaLineArg.lineNumber)) {
246
return false;
247
}
248
249
if (!types.isUndefined(reveaLineArg.at) && !types.isString(reveaLineArg.at)) {
250
return false;
251
}
252
253
return true;
254
};
255
256
export const metadata: ICommandMetadata = {
257
description: 'Reveal the given line at the given logical position',
258
args: [
259
{
260
name: 'Reveal line argument object',
261
description: `Property-value pairs that can be passed through this argument:
262
* 'lineNumber': A mandatory line number value.
263
* 'at': Logical position at which line has to be revealed.
264
\`\`\`
265
'top', 'center', 'bottom'
266
\`\`\`
267
`,
268
constraint: isRevealLineArgs,
269
schema: {
270
'type': 'object',
271
'required': ['lineNumber'],
272
'properties': {
273
'lineNumber': {
274
'type': ['number', 'string'],
275
},
276
'at': {
277
'type': 'string',
278
'enum': ['top', 'center', 'bottom']
279
}
280
}
281
}
282
}
283
]
284
};
285
286
/**
287
* Arguments for reveal line command
288
*/
289
export interface RawArguments {
290
lineNumber?: number | string;
291
at?: string;
292
}
293
294
/**
295
* Values for reveal line 'at' argument
296
*/
297
export const RawAtArgument = {
298
Top: 'top',
299
Center: 'center',
300
Bottom: 'bottom'
301
};
302
}
303
304
abstract class EditorOrNativeTextInputCommand {
305
306
constructor(target: MultiCommand) {
307
// 1. handle case when focus is in editor.
308
target.addImplementation(10000, 'code-editor', (accessor: ServicesAccessor, args: unknown) => {
309
// Only if editor text focus (i.e. not if editor has widget focus).
310
const focusedEditor = accessor.get(ICodeEditorService).getFocusedCodeEditor();
311
if (focusedEditor && focusedEditor.hasTextFocus()) {
312
return this._runEditorCommand(accessor, focusedEditor, args);
313
}
314
return false;
315
});
316
317
// 2. handle case when focus is in some other `input` / `textarea`.
318
target.addImplementation(1000, 'generic-dom-input-textarea', (accessor: ServicesAccessor, args: unknown) => {
319
// Only if focused on an element that allows for entering text
320
const activeElement = getActiveElement();
321
if (activeElement && isEditableElement(activeElement)) {
322
this.runDOMCommand(activeElement);
323
return true;
324
}
325
return false;
326
});
327
328
// 3. (default) handle case when focus is somewhere else.
329
target.addImplementation(0, 'generic-dom', (accessor: ServicesAccessor, args: unknown) => {
330
// Redirecting to active editor
331
const activeEditor = accessor.get(ICodeEditorService).getActiveCodeEditor();
332
if (activeEditor) {
333
activeEditor.focus();
334
return this._runEditorCommand(accessor, activeEditor, args);
335
}
336
return false;
337
});
338
}
339
340
public _runEditorCommand(accessor: ServicesAccessor | null, editor: ICodeEditor, args: unknown): boolean | Promise<void> {
341
const result = this.runEditorCommand(accessor, editor, args);
342
if (result) {
343
return result;
344
}
345
return true;
346
}
347
348
public abstract runDOMCommand(activeElement: Element): void;
349
public abstract runEditorCommand(accessor: ServicesAccessor | null, editor: ICodeEditor, args: unknown): void | Promise<void>;
350
}
351
352
export const enum NavigationCommandRevealType {
353
/**
354
* Do regular revealing.
355
*/
356
Regular = 0,
357
/**
358
* Do only minimal revealing.
359
*/
360
Minimal = 1,
361
/**
362
* Do not reveal the position.
363
*/
364
None = 2
365
}
366
367
export namespace CoreNavigationCommands {
368
369
export interface BaseCommandOptions {
370
source?: 'mouse' | 'keyboard' | string;
371
}
372
373
export interface MoveCommandOptions extends BaseCommandOptions {
374
position: IPosition;
375
viewPosition?: IPosition;
376
revealType: NavigationCommandRevealType;
377
}
378
379
class BaseMoveToCommand extends CoreEditorCommand<MoveCommandOptions> {
380
381
private readonly _inSelectionMode: boolean;
382
383
constructor(opts: ICommandOptions & { inSelectionMode: boolean }) {
384
super(opts);
385
this._inSelectionMode = opts.inSelectionMode;
386
}
387
388
public runCoreEditorCommand(viewModel: IViewModel, args: Partial<MoveCommandOptions>): void {
389
if (!args.position) {
390
return;
391
}
392
viewModel.model.pushStackElement();
393
const cursorStateChanged = viewModel.setCursorStates(
394
args.source,
395
CursorChangeReason.Explicit,
396
[
397
CursorMoveCommands.moveTo(viewModel, viewModel.getPrimaryCursorState(), this._inSelectionMode, args.position, args.viewPosition)
398
]
399
);
400
if (cursorStateChanged && args.revealType !== NavigationCommandRevealType.None) {
401
viewModel.revealAllCursors(args.source, true, true);
402
}
403
}
404
}
405
406
export const MoveTo: CoreEditorCommand<MoveCommandOptions> = registerEditorCommand(new BaseMoveToCommand({
407
id: '_moveTo',
408
inSelectionMode: false,
409
precondition: undefined
410
}));
411
412
export const MoveToSelect: CoreEditorCommand<MoveCommandOptions> = registerEditorCommand(new BaseMoveToCommand({
413
id: '_moveToSelect',
414
inSelectionMode: true,
415
precondition: undefined
416
}));
417
418
abstract class ColumnSelectCommand<T extends BaseCommandOptions = BaseCommandOptions> extends CoreEditorCommand<T> {
419
public runCoreEditorCommand(viewModel: IViewModel, args: Partial<T>): void {
420
viewModel.model.pushStackElement();
421
const result = this._getColumnSelectResult(viewModel, viewModel.getPrimaryCursorState(), viewModel.getCursorColumnSelectData(), args);
422
if (result === null) {
423
// invalid arguments
424
return;
425
}
426
viewModel.setCursorStates(args.source, CursorChangeReason.Explicit, result.viewStates.map((viewState) => CursorState.fromViewState(viewState)));
427
viewModel.setCursorColumnSelectData({
428
isReal: true,
429
fromViewLineNumber: result.fromLineNumber,
430
fromViewVisualColumn: result.fromVisualColumn,
431
toViewLineNumber: result.toLineNumber,
432
toViewVisualColumn: result.toVisualColumn
433
});
434
if (result.reversed) {
435
viewModel.revealTopMostCursor(args.source);
436
} else {
437
viewModel.revealBottomMostCursor(args.source);
438
}
439
}
440
441
protected abstract _getColumnSelectResult(viewModel: IViewModel, primary: CursorState, prevColumnSelectData: IColumnSelectData, args: Partial<T>): IColumnSelectResult | null;
442
443
}
444
445
export interface ColumnSelectCommandOptions extends BaseCommandOptions {
446
position: IPosition;
447
viewPosition: IPosition;
448
mouseColumn: number;
449
doColumnSelect: boolean;
450
}
451
452
export const ColumnSelect: CoreEditorCommand<ColumnSelectCommandOptions> = registerEditorCommand(new class extends ColumnSelectCommand<ColumnSelectCommandOptions> {
453
constructor() {
454
super({
455
id: 'columnSelect',
456
precondition: undefined
457
});
458
}
459
460
protected _getColumnSelectResult(viewModel: IViewModel, primary: CursorState, prevColumnSelectData: IColumnSelectData, args: Partial<ColumnSelectCommandOptions>): IColumnSelectResult | null {
461
if (typeof args.position === 'undefined' || typeof args.viewPosition === 'undefined' || typeof args.mouseColumn === 'undefined') {
462
return null;
463
}
464
// validate `args`
465
const validatedPosition = viewModel.model.validatePosition(args.position);
466
const validatedViewPosition = viewModel.coordinatesConverter.validateViewPosition(new Position(args.viewPosition.lineNumber, args.viewPosition.column), validatedPosition);
467
468
const fromViewLineNumber = args.doColumnSelect ? prevColumnSelectData.fromViewLineNumber : validatedViewPosition.lineNumber;
469
const fromViewVisualColumn = args.doColumnSelect ? prevColumnSelectData.fromViewVisualColumn : args.mouseColumn - 1;
470
return ColumnSelection.columnSelect(viewModel.cursorConfig, viewModel, fromViewLineNumber, fromViewVisualColumn, validatedViewPosition.lineNumber, args.mouseColumn - 1);
471
}
472
});
473
474
export const CursorColumnSelectLeft: CoreEditorCommand<BaseCommandOptions> = registerEditorCommand(new class extends ColumnSelectCommand {
475
constructor() {
476
super({
477
id: 'cursorColumnSelectLeft',
478
precondition: undefined,
479
kbOpts: {
480
weight: CORE_WEIGHT,
481
kbExpr: EditorContextKeys.textInputFocus,
482
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.Alt | KeyCode.LeftArrow,
483
linux: { primary: 0 }
484
}
485
});
486
}
487
488
protected _getColumnSelectResult(viewModel: IViewModel, primary: CursorState, prevColumnSelectData: IColumnSelectData, args: Partial<BaseCommandOptions>): IColumnSelectResult {
489
return ColumnSelection.columnSelectLeft(viewModel.cursorConfig, viewModel, prevColumnSelectData);
490
}
491
});
492
493
export const CursorColumnSelectRight: CoreEditorCommand<BaseCommandOptions> = registerEditorCommand(new class extends ColumnSelectCommand {
494
constructor() {
495
super({
496
id: 'cursorColumnSelectRight',
497
precondition: undefined,
498
kbOpts: {
499
weight: CORE_WEIGHT,
500
kbExpr: EditorContextKeys.textInputFocus,
501
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.Alt | KeyCode.RightArrow,
502
linux: { primary: 0 }
503
}
504
});
505
}
506
507
protected _getColumnSelectResult(viewModel: IViewModel, primary: CursorState, prevColumnSelectData: IColumnSelectData, args: Partial<BaseCommandOptions>): IColumnSelectResult {
508
return ColumnSelection.columnSelectRight(viewModel.cursorConfig, viewModel, prevColumnSelectData);
509
}
510
});
511
512
class ColumnSelectUpCommand extends ColumnSelectCommand {
513
514
private readonly _isPaged: boolean;
515
516
constructor(opts: ICommandOptions & { isPaged: boolean }) {
517
super(opts);
518
this._isPaged = opts.isPaged;
519
}
520
521
protected _getColumnSelectResult(viewModel: IViewModel, primary: CursorState, prevColumnSelectData: IColumnSelectData, args: Partial<BaseCommandOptions>): IColumnSelectResult {
522
return ColumnSelection.columnSelectUp(viewModel.cursorConfig, viewModel, prevColumnSelectData, this._isPaged);
523
}
524
}
525
526
export const CursorColumnSelectUp: CoreEditorCommand<BaseCommandOptions> = registerEditorCommand(new ColumnSelectUpCommand({
527
isPaged: false,
528
id: 'cursorColumnSelectUp',
529
precondition: undefined,
530
kbOpts: {
531
weight: CORE_WEIGHT,
532
kbExpr: EditorContextKeys.textInputFocus,
533
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.Alt | KeyCode.UpArrow,
534
linux: { primary: 0 }
535
}
536
}));
537
538
export const CursorColumnSelectPageUp: CoreEditorCommand<BaseCommandOptions> = registerEditorCommand(new ColumnSelectUpCommand({
539
isPaged: true,
540
id: 'cursorColumnSelectPageUp',
541
precondition: undefined,
542
kbOpts: {
543
weight: CORE_WEIGHT,
544
kbExpr: EditorContextKeys.textInputFocus,
545
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.Alt | KeyCode.PageUp,
546
linux: { primary: 0 }
547
}
548
}));
549
550
class ColumnSelectDownCommand extends ColumnSelectCommand {
551
552
private readonly _isPaged: boolean;
553
554
constructor(opts: ICommandOptions & { isPaged: boolean }) {
555
super(opts);
556
this._isPaged = opts.isPaged;
557
}
558
559
protected _getColumnSelectResult(viewModel: IViewModel, primary: CursorState, prevColumnSelectData: IColumnSelectData, args: Partial<BaseCommandOptions>): IColumnSelectResult {
560
return ColumnSelection.columnSelectDown(viewModel.cursorConfig, viewModel, prevColumnSelectData, this._isPaged);
561
}
562
}
563
564
export const CursorColumnSelectDown: CoreEditorCommand<BaseCommandOptions> = registerEditorCommand(new ColumnSelectDownCommand({
565
isPaged: false,
566
id: 'cursorColumnSelectDown',
567
precondition: undefined,
568
kbOpts: {
569
weight: CORE_WEIGHT,
570
kbExpr: EditorContextKeys.textInputFocus,
571
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.Alt | KeyCode.DownArrow,
572
linux: { primary: 0 }
573
}
574
}));
575
576
export const CursorColumnSelectPageDown: CoreEditorCommand<BaseCommandOptions> = registerEditorCommand(new ColumnSelectDownCommand({
577
isPaged: true,
578
id: 'cursorColumnSelectPageDown',
579
precondition: undefined,
580
kbOpts: {
581
weight: CORE_WEIGHT,
582
kbExpr: EditorContextKeys.textInputFocus,
583
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.Alt | KeyCode.PageDown,
584
linux: { primary: 0 }
585
}
586
}));
587
588
export class CursorMoveImpl extends CoreEditorCommand<CursorMove_.RawArguments> {
589
constructor() {
590
super({
591
id: 'cursorMove',
592
precondition: undefined,
593
metadata: CursorMove_.metadata
594
});
595
}
596
597
public runCoreEditorCommand(viewModel: IViewModel, args: Partial<BaseCommandOptions & CursorMove_.RawArguments>): void {
598
const parsed = CursorMove_.parse(args);
599
if (!parsed) {
600
// illegal arguments
601
return;
602
}
603
this._runCursorMove(viewModel, args.source, parsed);
604
}
605
606
private _runCursorMove(viewModel: IViewModel, source: string | null | undefined, args: CursorMove_.ParsedArguments): void {
607
viewModel.model.pushStackElement();
608
viewModel.setCursorStates(
609
source,
610
CursorChangeReason.Explicit,
611
CursorMoveImpl._move(viewModel, viewModel.getCursorStates(), args)
612
);
613
viewModel.revealAllCursors(source, true);
614
}
615
616
private static _move(viewModel: IViewModel, cursors: CursorState[], args: CursorMove_.ParsedArguments): PartialCursorState[] | null {
617
const inSelectionMode = args.select;
618
const value = args.value;
619
620
switch (args.direction) {
621
case CursorMove_.Direction.Left:
622
case CursorMove_.Direction.Right:
623
case CursorMove_.Direction.Up:
624
case CursorMove_.Direction.Down:
625
case CursorMove_.Direction.PrevBlankLine:
626
case CursorMove_.Direction.NextBlankLine:
627
case CursorMove_.Direction.WrappedLineStart:
628
case CursorMove_.Direction.WrappedLineFirstNonWhitespaceCharacter:
629
case CursorMove_.Direction.WrappedLineColumnCenter:
630
case CursorMove_.Direction.WrappedLineEnd:
631
case CursorMove_.Direction.WrappedLineLastNonWhitespaceCharacter:
632
return CursorMoveCommands.simpleMove(viewModel, cursors, args.direction, inSelectionMode, value, args.unit);
633
634
case CursorMove_.Direction.ViewPortTop:
635
case CursorMove_.Direction.ViewPortBottom:
636
case CursorMove_.Direction.ViewPortCenter:
637
case CursorMove_.Direction.ViewPortIfOutside:
638
return CursorMoveCommands.viewportMove(viewModel, cursors, args.direction, inSelectionMode, value);
639
default:
640
return null;
641
}
642
}
643
}
644
645
export const CursorMove: CursorMoveImpl = registerEditorCommand(new CursorMoveImpl());
646
647
const enum Constants {
648
PAGE_SIZE_MARKER = -1
649
}
650
651
export interface CursorMoveCommandOptions extends BaseCommandOptions {
652
pageSize?: number;
653
}
654
655
class CursorMoveBasedCommand extends CoreEditorCommand<CursorMoveCommandOptions> {
656
657
private readonly _staticArgs: CursorMove_.SimpleMoveArguments;
658
659
constructor(opts: ICommandOptions & { args: CursorMove_.SimpleMoveArguments }) {
660
super(opts);
661
this._staticArgs = opts.args;
662
}
663
664
public runCoreEditorCommand(viewModel: IViewModel, dynamicArgs: Partial<CursorMoveCommandOptions>): void {
665
let args = this._staticArgs;
666
if (this._staticArgs.value === Constants.PAGE_SIZE_MARKER) {
667
// -1 is a marker for page size
668
args = {
669
direction: this._staticArgs.direction,
670
unit: this._staticArgs.unit,
671
select: this._staticArgs.select,
672
value: dynamicArgs.pageSize || viewModel.cursorConfig.pageSize
673
};
674
}
675
676
viewModel.model.pushStackElement();
677
viewModel.setCursorStates(
678
dynamicArgs.source,
679
CursorChangeReason.Explicit,
680
CursorMoveCommands.simpleMove(viewModel, viewModel.getCursorStates(), args.direction, args.select, args.value, args.unit)
681
);
682
viewModel.revealAllCursors(dynamicArgs.source, true);
683
}
684
}
685
686
export const CursorLeft: CoreEditorCommand<CursorMoveCommandOptions> = registerEditorCommand(new CursorMoveBasedCommand({
687
args: {
688
direction: CursorMove_.Direction.Left,
689
unit: CursorMove_.Unit.None,
690
select: false,
691
value: 1
692
},
693
id: 'cursorLeft',
694
precondition: undefined,
695
kbOpts: {
696
weight: CORE_WEIGHT,
697
kbExpr: EditorContextKeys.textInputFocus,
698
primary: KeyCode.LeftArrow,
699
mac: { primary: KeyCode.LeftArrow, secondary: [KeyMod.WinCtrl | KeyCode.KeyB] }
700
}
701
}));
702
703
export const CursorLeftSelect: CoreEditorCommand<CursorMoveCommandOptions> = registerEditorCommand(new CursorMoveBasedCommand({
704
args: {
705
direction: CursorMove_.Direction.Left,
706
unit: CursorMove_.Unit.None,
707
select: true,
708
value: 1
709
},
710
id: 'cursorLeftSelect',
711
precondition: undefined,
712
kbOpts: {
713
weight: CORE_WEIGHT,
714
kbExpr: EditorContextKeys.textInputFocus,
715
primary: KeyMod.Shift | KeyCode.LeftArrow
716
}
717
}));
718
719
export const CursorRight: CoreEditorCommand<CursorMoveCommandOptions> = registerEditorCommand(new CursorMoveBasedCommand({
720
args: {
721
direction: CursorMove_.Direction.Right,
722
unit: CursorMove_.Unit.None,
723
select: false,
724
value: 1
725
},
726
id: 'cursorRight',
727
precondition: undefined,
728
kbOpts: {
729
weight: CORE_WEIGHT,
730
kbExpr: EditorContextKeys.textInputFocus,
731
primary: KeyCode.RightArrow,
732
mac: { primary: KeyCode.RightArrow, secondary: [KeyMod.WinCtrl | KeyCode.KeyF] }
733
}
734
}));
735
736
export const CursorRightSelect: CoreEditorCommand<CursorMoveCommandOptions> = registerEditorCommand(new CursorMoveBasedCommand({
737
args: {
738
direction: CursorMove_.Direction.Right,
739
unit: CursorMove_.Unit.None,
740
select: true,
741
value: 1
742
},
743
id: 'cursorRightSelect',
744
precondition: undefined,
745
kbOpts: {
746
weight: CORE_WEIGHT,
747
kbExpr: EditorContextKeys.textInputFocus,
748
primary: KeyMod.Shift | KeyCode.RightArrow
749
}
750
}));
751
752
export const CursorUp: CoreEditorCommand<CursorMoveCommandOptions> = registerEditorCommand(new CursorMoveBasedCommand({
753
args: {
754
direction: CursorMove_.Direction.Up,
755
unit: CursorMove_.Unit.WrappedLine,
756
select: false,
757
value: 1
758
},
759
id: 'cursorUp',
760
precondition: undefined,
761
kbOpts: {
762
weight: CORE_WEIGHT,
763
kbExpr: EditorContextKeys.textInputFocus,
764
primary: KeyCode.UpArrow,
765
mac: { primary: KeyCode.UpArrow, secondary: [KeyMod.WinCtrl | KeyCode.KeyP] }
766
}
767
}));
768
769
export const CursorUpSelect: CoreEditorCommand<CursorMoveCommandOptions> = registerEditorCommand(new CursorMoveBasedCommand({
770
args: {
771
direction: CursorMove_.Direction.Up,
772
unit: CursorMove_.Unit.WrappedLine,
773
select: true,
774
value: 1
775
},
776
id: 'cursorUpSelect',
777
precondition: undefined,
778
kbOpts: {
779
weight: CORE_WEIGHT,
780
kbExpr: EditorContextKeys.textInputFocus,
781
primary: KeyMod.Shift | KeyCode.UpArrow,
782
secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.UpArrow],
783
mac: { primary: KeyMod.Shift | KeyCode.UpArrow },
784
linux: { primary: KeyMod.Shift | KeyCode.UpArrow }
785
}
786
}));
787
788
export const CursorPageUp: CoreEditorCommand<CursorMoveCommandOptions> = registerEditorCommand(new CursorMoveBasedCommand({
789
args: {
790
direction: CursorMove_.Direction.Up,
791
unit: CursorMove_.Unit.WrappedLine,
792
select: false,
793
value: Constants.PAGE_SIZE_MARKER
794
},
795
id: 'cursorPageUp',
796
precondition: undefined,
797
kbOpts: {
798
weight: CORE_WEIGHT,
799
kbExpr: EditorContextKeys.textInputFocus,
800
primary: KeyCode.PageUp
801
}
802
}));
803
804
export const CursorPageUpSelect: CoreEditorCommand<CursorMoveCommandOptions> = registerEditorCommand(new CursorMoveBasedCommand({
805
args: {
806
direction: CursorMove_.Direction.Up,
807
unit: CursorMove_.Unit.WrappedLine,
808
select: true,
809
value: Constants.PAGE_SIZE_MARKER
810
},
811
id: 'cursorPageUpSelect',
812
precondition: undefined,
813
kbOpts: {
814
weight: CORE_WEIGHT,
815
kbExpr: EditorContextKeys.textInputFocus,
816
primary: KeyMod.Shift | KeyCode.PageUp
817
}
818
}));
819
820
export const CursorDown: CoreEditorCommand<CursorMoveCommandOptions> = registerEditorCommand(new CursorMoveBasedCommand({
821
args: {
822
direction: CursorMove_.Direction.Down,
823
unit: CursorMove_.Unit.WrappedLine,
824
select: false,
825
value: 1
826
},
827
id: 'cursorDown',
828
precondition: undefined,
829
kbOpts: {
830
weight: CORE_WEIGHT,
831
kbExpr: EditorContextKeys.textInputFocus,
832
primary: KeyCode.DownArrow,
833
mac: { primary: KeyCode.DownArrow, secondary: [KeyMod.WinCtrl | KeyCode.KeyN] }
834
}
835
}));
836
837
export const CursorDownSelect: CoreEditorCommand<CursorMoveCommandOptions> = registerEditorCommand(new CursorMoveBasedCommand({
838
args: {
839
direction: CursorMove_.Direction.Down,
840
unit: CursorMove_.Unit.WrappedLine,
841
select: true,
842
value: 1
843
},
844
id: 'cursorDownSelect',
845
precondition: undefined,
846
kbOpts: {
847
weight: CORE_WEIGHT,
848
kbExpr: EditorContextKeys.textInputFocus,
849
primary: KeyMod.Shift | KeyCode.DownArrow,
850
secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.DownArrow],
851
mac: { primary: KeyMod.Shift | KeyCode.DownArrow },
852
linux: { primary: KeyMod.Shift | KeyCode.DownArrow }
853
}
854
}));
855
856
export const CursorPageDown: CoreEditorCommand<CursorMoveCommandOptions> = registerEditorCommand(new CursorMoveBasedCommand({
857
args: {
858
direction: CursorMove_.Direction.Down,
859
unit: CursorMove_.Unit.WrappedLine,
860
select: false,
861
value: Constants.PAGE_SIZE_MARKER
862
},
863
id: 'cursorPageDown',
864
precondition: undefined,
865
kbOpts: {
866
weight: CORE_WEIGHT,
867
kbExpr: EditorContextKeys.textInputFocus,
868
primary: KeyCode.PageDown
869
}
870
}));
871
872
export const CursorPageDownSelect: CoreEditorCommand<CursorMoveCommandOptions> = registerEditorCommand(new CursorMoveBasedCommand({
873
args: {
874
direction: CursorMove_.Direction.Down,
875
unit: CursorMove_.Unit.WrappedLine,
876
select: true,
877
value: Constants.PAGE_SIZE_MARKER
878
},
879
id: 'cursorPageDownSelect',
880
precondition: undefined,
881
kbOpts: {
882
weight: CORE_WEIGHT,
883
kbExpr: EditorContextKeys.textInputFocus,
884
primary: KeyMod.Shift | KeyCode.PageDown
885
}
886
}));
887
888
export interface CreateCursorCommandOptions extends MoveCommandOptions {
889
wholeLine?: boolean;
890
}
891
892
export const CreateCursor: CoreEditorCommand<CreateCursorCommandOptions> = registerEditorCommand(new class extends CoreEditorCommand<CreateCursorCommandOptions> {
893
constructor() {
894
super({
895
id: 'createCursor',
896
precondition: undefined
897
});
898
}
899
900
public runCoreEditorCommand(viewModel: IViewModel, args: Partial<CreateCursorCommandOptions>): void {
901
if (!args.position) {
902
return;
903
}
904
let newState: PartialCursorState;
905
if (args.wholeLine) {
906
newState = CursorMoveCommands.line(viewModel, viewModel.getPrimaryCursorState(), false, args.position, args.viewPosition);
907
} else {
908
newState = CursorMoveCommands.moveTo(viewModel, viewModel.getPrimaryCursorState(), false, args.position, args.viewPosition);
909
}
910
911
const states: PartialCursorState[] = viewModel.getCursorStates();
912
913
// Check if we should remove a cursor (sort of like a toggle)
914
if (states.length > 1) {
915
const newModelPosition = (newState.modelState ? newState.modelState.position : null);
916
const newViewPosition = (newState.viewState ? newState.viewState.position : null);
917
918
for (let i = 0, len = states.length; i < len; i++) {
919
const state = states[i];
920
921
if (newModelPosition && !state.modelState!.selection.containsPosition(newModelPosition)) {
922
continue;
923
}
924
925
if (newViewPosition && !state.viewState!.selection.containsPosition(newViewPosition)) {
926
continue;
927
}
928
929
// => Remove the cursor
930
states.splice(i, 1);
931
932
viewModel.model.pushStackElement();
933
viewModel.setCursorStates(
934
args.source,
935
CursorChangeReason.Explicit,
936
states
937
);
938
return;
939
}
940
}
941
942
// => Add the new cursor
943
states.push(newState);
944
945
viewModel.model.pushStackElement();
946
viewModel.setCursorStates(
947
args.source,
948
CursorChangeReason.Explicit,
949
states
950
);
951
}
952
});
953
954
export const LastCursorMoveToSelect: CoreEditorCommand<MoveCommandOptions> = registerEditorCommand(new class extends CoreEditorCommand<MoveCommandOptions> {
955
constructor() {
956
super({
957
id: '_lastCursorMoveToSelect',
958
precondition: undefined
959
});
960
}
961
962
public runCoreEditorCommand(viewModel: IViewModel, args: Partial<MoveCommandOptions>): void {
963
if (!args.position) {
964
return;
965
}
966
const lastAddedCursorIndex = viewModel.getLastAddedCursorIndex();
967
968
const states = viewModel.getCursorStates();
969
const newStates: PartialCursorState[] = states.slice(0);
970
newStates[lastAddedCursorIndex] = CursorMoveCommands.moveTo(viewModel, states[lastAddedCursorIndex], true, args.position, args.viewPosition);
971
972
viewModel.model.pushStackElement();
973
viewModel.setCursorStates(
974
args.source,
975
CursorChangeReason.Explicit,
976
newStates
977
);
978
}
979
});
980
981
class HomeCommand extends CoreEditorCommand<BaseCommandOptions> {
982
983
private readonly _inSelectionMode: boolean;
984
985
constructor(opts: ICommandOptions & { inSelectionMode: boolean }) {
986
super(opts);
987
this._inSelectionMode = opts.inSelectionMode;
988
}
989
990
public runCoreEditorCommand(viewModel: IViewModel, args: Partial<BaseCommandOptions>): void {
991
viewModel.model.pushStackElement();
992
viewModel.setCursorStates(
993
args.source,
994
CursorChangeReason.Explicit,
995
CursorMoveCommands.moveToBeginningOfLine(viewModel, viewModel.getCursorStates(), this._inSelectionMode)
996
);
997
viewModel.revealAllCursors(args.source, true);
998
}
999
}
1000
1001
export const CursorHome: CoreEditorCommand<BaseCommandOptions> = registerEditorCommand(new HomeCommand({
1002
inSelectionMode: false,
1003
id: 'cursorHome',
1004
precondition: undefined,
1005
kbOpts: {
1006
weight: CORE_WEIGHT,
1007
kbExpr: EditorContextKeys.textInputFocus,
1008
primary: KeyCode.Home,
1009
mac: { primary: KeyCode.Home, secondary: [KeyMod.CtrlCmd | KeyCode.LeftArrow] }
1010
}
1011
}));
1012
1013
export const CursorHomeSelect: CoreEditorCommand<BaseCommandOptions> = registerEditorCommand(new HomeCommand({
1014
inSelectionMode: true,
1015
id: 'cursorHomeSelect',
1016
precondition: undefined,
1017
kbOpts: {
1018
weight: CORE_WEIGHT,
1019
kbExpr: EditorContextKeys.textInputFocus,
1020
primary: KeyMod.Shift | KeyCode.Home,
1021
mac: { primary: KeyMod.Shift | KeyCode.Home, secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.LeftArrow] }
1022
}
1023
}));
1024
1025
class LineStartCommand extends CoreEditorCommand<BaseCommandOptions> {
1026
1027
private readonly _inSelectionMode: boolean;
1028
1029
constructor(opts: ICommandOptions & { inSelectionMode: boolean }) {
1030
super(opts);
1031
this._inSelectionMode = opts.inSelectionMode;
1032
}
1033
1034
public runCoreEditorCommand(viewModel: IViewModel, args: Partial<BaseCommandOptions>): void {
1035
viewModel.model.pushStackElement();
1036
viewModel.setCursorStates(
1037
args.source,
1038
CursorChangeReason.Explicit,
1039
this._exec(viewModel.getCursorStates())
1040
);
1041
viewModel.revealAllCursors(args.source, true);
1042
}
1043
1044
private _exec(cursors: CursorState[]): PartialCursorState[] {
1045
const result: PartialCursorState[] = [];
1046
for (let i = 0, len = cursors.length; i < len; i++) {
1047
const cursor = cursors[i];
1048
const lineNumber = cursor.modelState.position.lineNumber;
1049
result[i] = CursorState.fromModelState(cursor.modelState.move(this._inSelectionMode, lineNumber, 1, 0));
1050
}
1051
return result;
1052
}
1053
}
1054
1055
export const CursorLineStart: CoreEditorCommand<BaseCommandOptions> = registerEditorCommand(new LineStartCommand({
1056
inSelectionMode: false,
1057
id: 'cursorLineStart',
1058
precondition: undefined,
1059
kbOpts: {
1060
weight: CORE_WEIGHT,
1061
kbExpr: EditorContextKeys.textInputFocus,
1062
primary: 0,
1063
mac: { primary: KeyMod.WinCtrl | KeyCode.KeyA }
1064
}
1065
}));
1066
1067
export const CursorLineStartSelect: CoreEditorCommand<BaseCommandOptions> = registerEditorCommand(new LineStartCommand({
1068
inSelectionMode: true,
1069
id: 'cursorLineStartSelect',
1070
precondition: undefined,
1071
kbOpts: {
1072
weight: CORE_WEIGHT,
1073
kbExpr: EditorContextKeys.textInputFocus,
1074
primary: 0,
1075
mac: { primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.KeyA }
1076
}
1077
}));
1078
1079
export interface EndCommandOptions extends BaseCommandOptions {
1080
sticky?: boolean;
1081
}
1082
1083
class EndCommand extends CoreEditorCommand<EndCommandOptions> {
1084
1085
private readonly _inSelectionMode: boolean;
1086
1087
constructor(opts: ICommandOptions & { inSelectionMode: boolean }) {
1088
super(opts);
1089
this._inSelectionMode = opts.inSelectionMode;
1090
}
1091
1092
public runCoreEditorCommand(viewModel: IViewModel, args: Partial<EndCommandOptions>): void {
1093
viewModel.model.pushStackElement();
1094
viewModel.setCursorStates(
1095
args.source,
1096
CursorChangeReason.Explicit,
1097
CursorMoveCommands.moveToEndOfLine(viewModel, viewModel.getCursorStates(), this._inSelectionMode, args.sticky || false)
1098
);
1099
viewModel.revealAllCursors(args.source, true);
1100
}
1101
}
1102
1103
export const CursorEnd: CoreEditorCommand<EndCommandOptions> = registerEditorCommand(new EndCommand({
1104
inSelectionMode: false,
1105
id: 'cursorEnd',
1106
precondition: undefined,
1107
kbOpts: {
1108
args: { sticky: false },
1109
weight: CORE_WEIGHT,
1110
kbExpr: EditorContextKeys.textInputFocus,
1111
primary: KeyCode.End,
1112
mac: { primary: KeyCode.End, secondary: [KeyMod.CtrlCmd | KeyCode.RightArrow] }
1113
},
1114
metadata: {
1115
description: `Go to End`,
1116
args: [{
1117
name: 'args',
1118
schema: {
1119
type: 'object',
1120
properties: {
1121
'sticky': {
1122
description: nls.localize('stickydesc', "Stick to the end even when going to longer lines"),
1123
type: 'boolean',
1124
default: false
1125
}
1126
}
1127
}
1128
}]
1129
}
1130
}));
1131
1132
export const CursorEndSelect: CoreEditorCommand<EndCommandOptions> = registerEditorCommand(new EndCommand({
1133
inSelectionMode: true,
1134
id: 'cursorEndSelect',
1135
precondition: undefined,
1136
kbOpts: {
1137
args: { sticky: false },
1138
weight: CORE_WEIGHT,
1139
kbExpr: EditorContextKeys.textInputFocus,
1140
primary: KeyMod.Shift | KeyCode.End,
1141
mac: { primary: KeyMod.Shift | KeyCode.End, secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.RightArrow] }
1142
},
1143
metadata: {
1144
description: `Select to End`,
1145
args: [{
1146
name: 'args',
1147
schema: {
1148
type: 'object',
1149
properties: {
1150
'sticky': {
1151
description: nls.localize('stickydesc', "Stick to the end even when going to longer lines"),
1152
type: 'boolean',
1153
default: false
1154
}
1155
}
1156
}
1157
}]
1158
}
1159
}));
1160
1161
class LineEndCommand extends CoreEditorCommand<BaseCommandOptions> {
1162
1163
private readonly _inSelectionMode: boolean;
1164
1165
constructor(opts: ICommandOptions & { inSelectionMode: boolean }) {
1166
super(opts);
1167
this._inSelectionMode = opts.inSelectionMode;
1168
}
1169
1170
public runCoreEditorCommand(viewModel: IViewModel, args: Partial<BaseCommandOptions>): void {
1171
viewModel.model.pushStackElement();
1172
viewModel.setCursorStates(
1173
args.source,
1174
CursorChangeReason.Explicit,
1175
this._exec(viewModel, viewModel.getCursorStates())
1176
);
1177
viewModel.revealAllCursors(args.source, true);
1178
}
1179
1180
private _exec(viewModel: IViewModel, cursors: CursorState[]): PartialCursorState[] {
1181
const result: PartialCursorState[] = [];
1182
for (let i = 0, len = cursors.length; i < len; i++) {
1183
const cursor = cursors[i];
1184
const lineNumber = cursor.modelState.position.lineNumber;
1185
const maxColumn = viewModel.model.getLineMaxColumn(lineNumber);
1186
result[i] = CursorState.fromModelState(cursor.modelState.move(this._inSelectionMode, lineNumber, maxColumn, 0));
1187
}
1188
return result;
1189
}
1190
}
1191
1192
export const CursorLineEnd: CoreEditorCommand<BaseCommandOptions> = registerEditorCommand(new LineEndCommand({
1193
inSelectionMode: false,
1194
id: 'cursorLineEnd',
1195
precondition: undefined,
1196
kbOpts: {
1197
weight: CORE_WEIGHT,
1198
kbExpr: EditorContextKeys.textInputFocus,
1199
primary: 0,
1200
mac: { primary: KeyMod.WinCtrl | KeyCode.KeyE }
1201
}
1202
}));
1203
1204
export const CursorLineEndSelect: CoreEditorCommand<BaseCommandOptions> = registerEditorCommand(new LineEndCommand({
1205
inSelectionMode: true,
1206
id: 'cursorLineEndSelect',
1207
precondition: undefined,
1208
kbOpts: {
1209
weight: CORE_WEIGHT,
1210
kbExpr: EditorContextKeys.textInputFocus,
1211
primary: 0,
1212
mac: { primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.KeyE }
1213
}
1214
}));
1215
1216
class TopCommand extends CoreEditorCommand<BaseCommandOptions> {
1217
1218
private readonly _inSelectionMode: boolean;
1219
1220
constructor(opts: ICommandOptions & { inSelectionMode: boolean }) {
1221
super(opts);
1222
this._inSelectionMode = opts.inSelectionMode;
1223
}
1224
1225
public runCoreEditorCommand(viewModel: IViewModel, args: Partial<BaseCommandOptions>): void {
1226
viewModel.model.pushStackElement();
1227
viewModel.setCursorStates(
1228
args.source,
1229
CursorChangeReason.Explicit,
1230
CursorMoveCommands.moveToBeginningOfBuffer(viewModel, viewModel.getCursorStates(), this._inSelectionMode)
1231
);
1232
viewModel.revealAllCursors(args.source, true);
1233
}
1234
}
1235
1236
export const CursorTop: CoreEditorCommand<BaseCommandOptions> = registerEditorCommand(new TopCommand({
1237
inSelectionMode: false,
1238
id: 'cursorTop',
1239
precondition: undefined,
1240
kbOpts: {
1241
weight: CORE_WEIGHT,
1242
kbExpr: EditorContextKeys.textInputFocus,
1243
primary: KeyMod.CtrlCmd | KeyCode.Home,
1244
mac: { primary: KeyMod.CtrlCmd | KeyCode.UpArrow }
1245
}
1246
}));
1247
1248
export const CursorTopSelect: CoreEditorCommand<BaseCommandOptions> = registerEditorCommand(new TopCommand({
1249
inSelectionMode: true,
1250
id: 'cursorTopSelect',
1251
precondition: undefined,
1252
kbOpts: {
1253
weight: CORE_WEIGHT,
1254
kbExpr: EditorContextKeys.textInputFocus,
1255
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.Home,
1256
mac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.UpArrow }
1257
}
1258
}));
1259
1260
class BottomCommand extends CoreEditorCommand<BaseCommandOptions> {
1261
1262
private readonly _inSelectionMode: boolean;
1263
1264
constructor(opts: ICommandOptions & { inSelectionMode: boolean }) {
1265
super(opts);
1266
this._inSelectionMode = opts.inSelectionMode;
1267
}
1268
1269
public runCoreEditorCommand(viewModel: IViewModel, args: Partial<BaseCommandOptions>): void {
1270
viewModel.model.pushStackElement();
1271
viewModel.setCursorStates(
1272
args.source,
1273
CursorChangeReason.Explicit,
1274
CursorMoveCommands.moveToEndOfBuffer(viewModel, viewModel.getCursorStates(), this._inSelectionMode)
1275
);
1276
viewModel.revealAllCursors(args.source, true);
1277
}
1278
}
1279
1280
export const CursorBottom: CoreEditorCommand<BaseCommandOptions> = registerEditorCommand(new BottomCommand({
1281
inSelectionMode: false,
1282
id: 'cursorBottom',
1283
precondition: undefined,
1284
kbOpts: {
1285
weight: CORE_WEIGHT,
1286
kbExpr: EditorContextKeys.textInputFocus,
1287
primary: KeyMod.CtrlCmd | KeyCode.End,
1288
mac: { primary: KeyMod.CtrlCmd | KeyCode.DownArrow }
1289
}
1290
}));
1291
1292
export const CursorBottomSelect: CoreEditorCommand<BaseCommandOptions> = registerEditorCommand(new BottomCommand({
1293
inSelectionMode: true,
1294
id: 'cursorBottomSelect',
1295
precondition: undefined,
1296
kbOpts: {
1297
weight: CORE_WEIGHT,
1298
kbExpr: EditorContextKeys.textInputFocus,
1299
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.End,
1300
mac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.DownArrow }
1301
}
1302
}));
1303
1304
export type EditorScrollCommandOptions = EditorScroll_.RawArguments & BaseCommandOptions;
1305
1306
export class EditorScrollImpl extends CoreEditorCommand<EditorScrollCommandOptions> {
1307
constructor() {
1308
super({
1309
id: 'editorScroll',
1310
precondition: undefined,
1311
metadata: EditorScroll_.metadata
1312
});
1313
}
1314
1315
determineScrollMethod(args: EditorScroll_.ParsedArguments) {
1316
const horizontalUnits = [EditorScroll_.Unit.Column];
1317
const verticalUnits = [
1318
EditorScroll_.Unit.Line,
1319
EditorScroll_.Unit.WrappedLine,
1320
EditorScroll_.Unit.Page,
1321
EditorScroll_.Unit.HalfPage,
1322
EditorScroll_.Unit.Editor,
1323
EditorScroll_.Unit.Column
1324
];
1325
const horizontalDirections = [EditorScroll_.Direction.Left, EditorScroll_.Direction.Right];
1326
const verticalDirections = [EditorScroll_.Direction.Up, EditorScroll_.Direction.Down];
1327
1328
if (horizontalUnits.includes(args.unit) && horizontalDirections.includes(args.direction)) {
1329
return this._runHorizontalEditorScroll.bind(this);
1330
}
1331
if (verticalUnits.includes(args.unit) && verticalDirections.includes(args.direction)) {
1332
return this._runVerticalEditorScroll.bind(this);
1333
}
1334
return null;
1335
}
1336
1337
public runCoreEditorCommand(viewModel: IViewModel, args: Partial<EditorScrollCommandOptions>): void {
1338
const parsed = EditorScroll_.parse(args);
1339
if (!parsed) {
1340
// illegal arguments
1341
return;
1342
}
1343
const runEditorScroll = this.determineScrollMethod(parsed);
1344
if (!runEditorScroll) {
1345
// Incompatible unit and direction
1346
return;
1347
}
1348
runEditorScroll(viewModel, args.source, parsed);
1349
}
1350
1351
_runVerticalEditorScroll(viewModel: IViewModel, source: string | null | undefined, args: EditorScroll_.ParsedArguments): void {
1352
1353
const desiredScrollTop = this._computeDesiredScrollTop(viewModel, args);
1354
1355
if (args.revealCursor) {
1356
// must ensure cursor is in new visible range
1357
const desiredVisibleViewRange = viewModel.getCompletelyVisibleViewRangeAtScrollTop(desiredScrollTop);
1358
viewModel.setCursorStates(
1359
source,
1360
CursorChangeReason.Explicit,
1361
[
1362
CursorMoveCommands.findPositionInViewportIfOutside(viewModel, viewModel.getPrimaryCursorState(), desiredVisibleViewRange, args.select)
1363
]
1364
);
1365
}
1366
1367
viewModel.viewLayout.setScrollPosition({ scrollTop: desiredScrollTop }, ScrollType.Smooth);
1368
}
1369
1370
private _computeDesiredScrollTop(viewModel: IViewModel, args: EditorScroll_.ParsedArguments): number {
1371
1372
if (args.unit === EditorScroll_.Unit.Line) {
1373
// scrolling by model lines
1374
const futureViewport = viewModel.viewLayout.getFutureViewport();
1375
const visibleViewRange = viewModel.getCompletelyVisibleViewRangeAtScrollTop(futureViewport.top);
1376
const visibleModelRange = viewModel.coordinatesConverter.convertViewRangeToModelRange(visibleViewRange);
1377
1378
let desiredTopModelLineNumber: number;
1379
if (args.direction === EditorScroll_.Direction.Up) {
1380
// must go x model lines up
1381
desiredTopModelLineNumber = Math.max(1, visibleModelRange.startLineNumber - args.value);
1382
} else {
1383
// must go x model lines down
1384
desiredTopModelLineNumber = Math.min(viewModel.model.getLineCount(), visibleModelRange.startLineNumber + args.value);
1385
}
1386
1387
const viewPosition = viewModel.coordinatesConverter.convertModelPositionToViewPosition(new Position(desiredTopModelLineNumber, 1));
1388
return viewModel.viewLayout.getVerticalOffsetForLineNumber(viewPosition.lineNumber);
1389
}
1390
1391
if (args.unit === EditorScroll_.Unit.Editor) {
1392
let desiredTopModelLineNumber = 0;
1393
if (args.direction === EditorScroll_.Direction.Down) {
1394
desiredTopModelLineNumber = viewModel.model.getLineCount() - viewModel.cursorConfig.pageSize;
1395
}
1396
return viewModel.viewLayout.getVerticalOffsetForLineNumber(desiredTopModelLineNumber);
1397
}
1398
1399
let noOfLines: number;
1400
if (args.unit === EditorScroll_.Unit.Page) {
1401
noOfLines = viewModel.cursorConfig.pageSize * args.value;
1402
} else if (args.unit === EditorScroll_.Unit.HalfPage) {
1403
noOfLines = Math.round(viewModel.cursorConfig.pageSize / 2) * args.value;
1404
} else {
1405
noOfLines = args.value;
1406
}
1407
const deltaLines = (args.direction === EditorScroll_.Direction.Up ? -1 : 1) * noOfLines;
1408
return viewModel.viewLayout.getCurrentScrollTop() + deltaLines * viewModel.cursorConfig.lineHeight;
1409
}
1410
1411
_runHorizontalEditorScroll(viewModel: IViewModel, source: string | null | undefined, args: EditorScroll_.ParsedArguments): void {
1412
const desiredScrollLeft = this._computeDesiredScrollLeft(viewModel, args);
1413
viewModel.viewLayout.setScrollPosition({ scrollLeft: desiredScrollLeft }, ScrollType.Smooth);
1414
}
1415
1416
_computeDesiredScrollLeft(viewModel: IViewModel, args: EditorScroll_.ParsedArguments) {
1417
const deltaColumns = (args.direction === EditorScroll_.Direction.Left ? -1 : 1) * args.value;
1418
return viewModel.viewLayout.getCurrentScrollLeft() + deltaColumns * viewModel.cursorConfig.typicalHalfwidthCharacterWidth;
1419
}
1420
}
1421
1422
export const EditorScroll: EditorScrollImpl = registerEditorCommand(new EditorScrollImpl());
1423
1424
export const ScrollLineUp: CoreEditorCommand<BaseCommandOptions> = registerEditorCommand(new class extends CoreEditorCommand<BaseCommandOptions> {
1425
constructor() {
1426
super({
1427
id: 'scrollLineUp',
1428
precondition: undefined,
1429
kbOpts: {
1430
weight: CORE_WEIGHT,
1431
kbExpr: EditorContextKeys.textInputFocus,
1432
primary: KeyMod.CtrlCmd | KeyCode.UpArrow,
1433
mac: { primary: KeyMod.WinCtrl | KeyCode.PageUp }
1434
}
1435
});
1436
}
1437
1438
runCoreEditorCommand(viewModel: IViewModel, args: Partial<BaseCommandOptions>): void {
1439
EditorScroll.runCoreEditorCommand(viewModel, {
1440
to: EditorScroll_.RawDirection.Up,
1441
by: EditorScroll_.RawUnit.WrappedLine,
1442
value: 1,
1443
revealCursor: false,
1444
select: false,
1445
source: args.source
1446
});
1447
}
1448
});
1449
1450
export const ScrollPageUp: CoreEditorCommand<BaseCommandOptions> = registerEditorCommand(new class extends CoreEditorCommand<BaseCommandOptions> {
1451
constructor() {
1452
super({
1453
id: 'scrollPageUp',
1454
precondition: undefined,
1455
kbOpts: {
1456
weight: CORE_WEIGHT,
1457
kbExpr: EditorContextKeys.textInputFocus,
1458
primary: KeyMod.CtrlCmd | KeyCode.PageUp,
1459
win: { primary: KeyMod.Alt | KeyCode.PageUp },
1460
linux: { primary: KeyMod.Alt | KeyCode.PageUp }
1461
}
1462
});
1463
}
1464
1465
runCoreEditorCommand(viewModel: IViewModel, args: Partial<BaseCommandOptions>): void {
1466
EditorScroll.runCoreEditorCommand(viewModel, {
1467
to: EditorScroll_.RawDirection.Up,
1468
by: EditorScroll_.RawUnit.Page,
1469
value: 1,
1470
revealCursor: false,
1471
select: false,
1472
source: args.source
1473
});
1474
}
1475
});
1476
1477
export const ScrollEditorTop: CoreEditorCommand<BaseCommandOptions> = registerEditorCommand(new class extends CoreEditorCommand<BaseCommandOptions> {
1478
constructor() {
1479
super({
1480
id: 'scrollEditorTop',
1481
precondition: undefined,
1482
kbOpts: {
1483
weight: CORE_WEIGHT,
1484
kbExpr: EditorContextKeys.textInputFocus,
1485
}
1486
});
1487
}
1488
1489
runCoreEditorCommand(viewModel: IViewModel, args: Partial<BaseCommandOptions>): void {
1490
EditorScroll.runCoreEditorCommand(viewModel, {
1491
to: EditorScroll_.RawDirection.Up,
1492
by: EditorScroll_.RawUnit.Editor,
1493
value: 1,
1494
revealCursor: false,
1495
select: false,
1496
source: args.source
1497
});
1498
}
1499
});
1500
1501
export const ScrollLineDown: CoreEditorCommand<BaseCommandOptions> = registerEditorCommand(new class extends CoreEditorCommand<BaseCommandOptions> {
1502
constructor() {
1503
super({
1504
id: 'scrollLineDown',
1505
precondition: undefined,
1506
kbOpts: {
1507
weight: CORE_WEIGHT,
1508
kbExpr: EditorContextKeys.textInputFocus,
1509
primary: KeyMod.CtrlCmd | KeyCode.DownArrow,
1510
mac: { primary: KeyMod.WinCtrl | KeyCode.PageDown }
1511
}
1512
});
1513
}
1514
1515
runCoreEditorCommand(viewModel: IViewModel, args: Partial<BaseCommandOptions>): void {
1516
EditorScroll.runCoreEditorCommand(viewModel, {
1517
to: EditorScroll_.RawDirection.Down,
1518
by: EditorScroll_.RawUnit.WrappedLine,
1519
value: 1,
1520
revealCursor: false,
1521
select: false,
1522
source: args.source
1523
});
1524
}
1525
});
1526
1527
export const ScrollPageDown: CoreEditorCommand<BaseCommandOptions> = registerEditorCommand(new class extends CoreEditorCommand<BaseCommandOptions> {
1528
constructor() {
1529
super({
1530
id: 'scrollPageDown',
1531
precondition: undefined,
1532
kbOpts: {
1533
weight: CORE_WEIGHT,
1534
kbExpr: EditorContextKeys.textInputFocus,
1535
primary: KeyMod.CtrlCmd | KeyCode.PageDown,
1536
win: { primary: KeyMod.Alt | KeyCode.PageDown },
1537
linux: { primary: KeyMod.Alt | KeyCode.PageDown }
1538
}
1539
});
1540
}
1541
1542
runCoreEditorCommand(viewModel: IViewModel, args: Partial<BaseCommandOptions>): void {
1543
EditorScroll.runCoreEditorCommand(viewModel, {
1544
to: EditorScroll_.RawDirection.Down,
1545
by: EditorScroll_.RawUnit.Page,
1546
value: 1,
1547
revealCursor: false,
1548
select: false,
1549
source: args.source
1550
});
1551
}
1552
});
1553
1554
export const ScrollEditorBottom: CoreEditorCommand<BaseCommandOptions> = registerEditorCommand(new class extends CoreEditorCommand<BaseCommandOptions> {
1555
constructor() {
1556
super({
1557
id: 'scrollEditorBottom',
1558
precondition: undefined,
1559
kbOpts: {
1560
weight: CORE_WEIGHT,
1561
kbExpr: EditorContextKeys.textInputFocus,
1562
}
1563
});
1564
}
1565
1566
runCoreEditorCommand(viewModel: IViewModel, args: Partial<BaseCommandOptions>): void {
1567
EditorScroll.runCoreEditorCommand(viewModel, {
1568
to: EditorScroll_.RawDirection.Down,
1569
by: EditorScroll_.RawUnit.Editor,
1570
value: 1,
1571
revealCursor: false,
1572
select: false,
1573
source: args.source
1574
});
1575
}
1576
});
1577
1578
export const ScrollLeft: CoreEditorCommand<BaseCommandOptions> = registerEditorCommand(new class extends CoreEditorCommand<BaseCommandOptions> {
1579
constructor() {
1580
super({
1581
id: 'scrollLeft',
1582
precondition: undefined,
1583
kbOpts: {
1584
weight: CORE_WEIGHT,
1585
kbExpr: EditorContextKeys.textInputFocus,
1586
}
1587
});
1588
}
1589
1590
runCoreEditorCommand(viewModel: IViewModel, args: Partial<BaseCommandOptions>): void {
1591
EditorScroll.runCoreEditorCommand(viewModel, {
1592
to: EditorScroll_.RawDirection.Left,
1593
by: EditorScroll_.RawUnit.Column,
1594
value: 2,
1595
revealCursor: false,
1596
select: false,
1597
source: args.source
1598
});
1599
}
1600
});
1601
1602
export const ScrollRight: CoreEditorCommand<BaseCommandOptions> = registerEditorCommand(new class extends CoreEditorCommand<BaseCommandOptions> {
1603
constructor() {
1604
super({
1605
id: 'scrollRight',
1606
precondition: undefined,
1607
kbOpts: {
1608
weight: CORE_WEIGHT,
1609
kbExpr: EditorContextKeys.textInputFocus,
1610
}
1611
});
1612
}
1613
1614
runCoreEditorCommand(viewModel: IViewModel, args: Partial<BaseCommandOptions>): void {
1615
EditorScroll.runCoreEditorCommand(viewModel, {
1616
to: EditorScroll_.RawDirection.Right,
1617
by: EditorScroll_.RawUnit.Column,
1618
value: 2,
1619
revealCursor: false,
1620
select: false,
1621
source: args.source
1622
});
1623
}
1624
});
1625
1626
class WordCommand extends CoreEditorCommand<MoveCommandOptions> {
1627
1628
private readonly _inSelectionMode: boolean;
1629
1630
constructor(opts: ICommandOptions & { inSelectionMode: boolean }) {
1631
super(opts);
1632
this._inSelectionMode = opts.inSelectionMode;
1633
}
1634
1635
public runCoreEditorCommand(viewModel: IViewModel, args: Partial<MoveCommandOptions>): void {
1636
if (!args.position) {
1637
return;
1638
}
1639
viewModel.model.pushStackElement();
1640
viewModel.setCursorStates(
1641
args.source,
1642
CursorChangeReason.Explicit,
1643
[
1644
CursorMoveCommands.word(viewModel, viewModel.getPrimaryCursorState(), this._inSelectionMode, args.position)
1645
]
1646
);
1647
if (args.revealType !== NavigationCommandRevealType.None) {
1648
viewModel.revealAllCursors(args.source, true, true);
1649
}
1650
}
1651
}
1652
1653
export const WordSelect: CoreEditorCommand<MoveCommandOptions> = registerEditorCommand(new WordCommand({
1654
inSelectionMode: false,
1655
id: '_wordSelect',
1656
precondition: undefined
1657
}));
1658
1659
export const WordSelectDrag: CoreEditorCommand<MoveCommandOptions> = registerEditorCommand(new WordCommand({
1660
inSelectionMode: true,
1661
id: '_wordSelectDrag',
1662
precondition: undefined
1663
}));
1664
1665
export const LastCursorWordSelect: CoreEditorCommand<MoveCommandOptions> = registerEditorCommand(new class extends CoreEditorCommand<MoveCommandOptions> {
1666
constructor() {
1667
super({
1668
id: 'lastCursorWordSelect',
1669
precondition: undefined
1670
});
1671
}
1672
1673
public runCoreEditorCommand(viewModel: IViewModel, args: Partial<MoveCommandOptions>): void {
1674
if (!args.position) {
1675
return;
1676
}
1677
const lastAddedCursorIndex = viewModel.getLastAddedCursorIndex();
1678
1679
const states = viewModel.getCursorStates();
1680
const newStates: PartialCursorState[] = states.slice(0);
1681
const lastAddedState = states[lastAddedCursorIndex];
1682
newStates[lastAddedCursorIndex] = CursorMoveCommands.word(viewModel, lastAddedState, lastAddedState.modelState.hasSelection(), args.position);
1683
1684
viewModel.model.pushStackElement();
1685
viewModel.setCursorStates(
1686
args.source,
1687
CursorChangeReason.Explicit,
1688
newStates
1689
);
1690
}
1691
});
1692
1693
class LineCommand extends CoreEditorCommand<MoveCommandOptions> {
1694
private readonly _inSelectionMode: boolean;
1695
1696
constructor(opts: ICommandOptions & { inSelectionMode: boolean }) {
1697
super(opts);
1698
this._inSelectionMode = opts.inSelectionMode;
1699
}
1700
1701
public runCoreEditorCommand(viewModel: IViewModel, args: Partial<MoveCommandOptions>): void {
1702
if (!args.position) {
1703
return;
1704
}
1705
viewModel.model.pushStackElement();
1706
viewModel.setCursorStates(
1707
args.source,
1708
CursorChangeReason.Explicit,
1709
[
1710
CursorMoveCommands.line(viewModel, viewModel.getPrimaryCursorState(), this._inSelectionMode, args.position, args.viewPosition)
1711
]
1712
);
1713
if (args.revealType !== NavigationCommandRevealType.None) {
1714
viewModel.revealAllCursors(args.source, false, true);
1715
}
1716
}
1717
}
1718
1719
export const LineSelect: CoreEditorCommand<MoveCommandOptions> = registerEditorCommand(new LineCommand({
1720
inSelectionMode: false,
1721
id: '_lineSelect',
1722
precondition: undefined
1723
}));
1724
1725
export const LineSelectDrag: CoreEditorCommand<MoveCommandOptions> = registerEditorCommand(new LineCommand({
1726
inSelectionMode: true,
1727
id: '_lineSelectDrag',
1728
precondition: undefined
1729
}));
1730
1731
class LastCursorLineCommand extends CoreEditorCommand<MoveCommandOptions> {
1732
private readonly _inSelectionMode: boolean;
1733
1734
constructor(opts: ICommandOptions & { inSelectionMode: boolean }) {
1735
super(opts);
1736
this._inSelectionMode = opts.inSelectionMode;
1737
}
1738
1739
public runCoreEditorCommand(viewModel: IViewModel, args: Partial<MoveCommandOptions>): void {
1740
if (!args.position) {
1741
return;
1742
}
1743
const lastAddedCursorIndex = viewModel.getLastAddedCursorIndex();
1744
1745
const states = viewModel.getCursorStates();
1746
const newStates: PartialCursorState[] = states.slice(0);
1747
newStates[lastAddedCursorIndex] = CursorMoveCommands.line(viewModel, states[lastAddedCursorIndex], this._inSelectionMode, args.position, args.viewPosition);
1748
1749
viewModel.model.pushStackElement();
1750
viewModel.setCursorStates(
1751
args.source,
1752
CursorChangeReason.Explicit,
1753
newStates
1754
);
1755
}
1756
}
1757
1758
export const LastCursorLineSelect: CoreEditorCommand<MoveCommandOptions> = registerEditorCommand(new LastCursorLineCommand({
1759
inSelectionMode: false,
1760
id: 'lastCursorLineSelect',
1761
precondition: undefined
1762
}));
1763
1764
export const LastCursorLineSelectDrag: CoreEditorCommand<MoveCommandOptions> = registerEditorCommand(new LastCursorLineCommand({
1765
inSelectionMode: true,
1766
id: 'lastCursorLineSelectDrag',
1767
precondition: undefined
1768
}));
1769
1770
export const CancelSelection: CoreEditorCommand<BaseCommandOptions> = registerEditorCommand(new class extends CoreEditorCommand<BaseCommandOptions> {
1771
constructor() {
1772
super({
1773
id: 'cancelSelection',
1774
precondition: EditorContextKeys.hasNonEmptySelection,
1775
kbOpts: {
1776
weight: CORE_WEIGHT,
1777
kbExpr: EditorContextKeys.textInputFocus,
1778
primary: KeyCode.Escape,
1779
secondary: [KeyMod.Shift | KeyCode.Escape]
1780
}
1781
});
1782
}
1783
1784
public runCoreEditorCommand(viewModel: IViewModel, args: Partial<BaseCommandOptions>): void {
1785
viewModel.model.pushStackElement();
1786
viewModel.setCursorStates(
1787
args.source,
1788
CursorChangeReason.Explicit,
1789
[
1790
CursorMoveCommands.cancelSelection(viewModel, viewModel.getPrimaryCursorState())
1791
]
1792
);
1793
viewModel.revealAllCursors(args.source, true);
1794
}
1795
});
1796
1797
export const RemoveSecondaryCursors: CoreEditorCommand<BaseCommandOptions> = registerEditorCommand(new class extends CoreEditorCommand<BaseCommandOptions> {
1798
constructor() {
1799
super({
1800
id: 'removeSecondaryCursors',
1801
precondition: EditorContextKeys.hasMultipleSelections,
1802
kbOpts: {
1803
weight: CORE_WEIGHT + 1,
1804
kbExpr: EditorContextKeys.textInputFocus,
1805
primary: KeyCode.Escape,
1806
secondary: [KeyMod.Shift | KeyCode.Escape]
1807
}
1808
});
1809
}
1810
1811
public runCoreEditorCommand(viewModel: IViewModel, args: Partial<BaseCommandOptions>): void {
1812
viewModel.model.pushStackElement();
1813
viewModel.setCursorStates(
1814
args.source,
1815
CursorChangeReason.Explicit,
1816
[
1817
viewModel.getPrimaryCursorState()
1818
]
1819
);
1820
viewModel.revealAllCursors(args.source, true);
1821
status(nls.localize('removedCursor', "Removed secondary cursors"));
1822
}
1823
});
1824
1825
export type RevealLineCommandOptions = RevealLine_.RawArguments & BaseCommandOptions;
1826
1827
export const RevealLine: CoreEditorCommand<RevealLineCommandOptions> = registerEditorCommand(new class extends CoreEditorCommand<RevealLineCommandOptions> {
1828
constructor() {
1829
super({
1830
id: 'revealLine',
1831
precondition: undefined,
1832
metadata: RevealLine_.metadata
1833
});
1834
}
1835
1836
public runCoreEditorCommand(viewModel: IViewModel, args: Partial<RevealLineCommandOptions>): void {
1837
const revealLineArg = args;
1838
const lineNumberArg = revealLineArg.lineNumber || 0;
1839
let lineNumber = typeof lineNumberArg === 'number' ? (lineNumberArg + 1) : (parseInt(lineNumberArg) + 1);
1840
if (lineNumber < 1) {
1841
lineNumber = 1;
1842
}
1843
const lineCount = viewModel.model.getLineCount();
1844
if (lineNumber > lineCount) {
1845
lineNumber = lineCount;
1846
}
1847
1848
const range = new Range(
1849
lineNumber, 1,
1850
lineNumber, viewModel.model.getLineMaxColumn(lineNumber)
1851
);
1852
1853
let revealAt = VerticalRevealType.Simple;
1854
if (revealLineArg.at) {
1855
switch (revealLineArg.at) {
1856
case RevealLine_.RawAtArgument.Top:
1857
revealAt = VerticalRevealType.Top;
1858
break;
1859
case RevealLine_.RawAtArgument.Center:
1860
revealAt = VerticalRevealType.Center;
1861
break;
1862
case RevealLine_.RawAtArgument.Bottom:
1863
revealAt = VerticalRevealType.Bottom;
1864
break;
1865
default:
1866
break;
1867
}
1868
}
1869
1870
const viewRange = viewModel.coordinatesConverter.convertModelRangeToViewRange(range);
1871
1872
viewModel.revealRange(args.source, false, viewRange, revealAt, ScrollType.Smooth);
1873
}
1874
});
1875
1876
export const SelectAll = new class extends EditorOrNativeTextInputCommand {
1877
constructor() {
1878
super(SelectAllCommand);
1879
}
1880
public runDOMCommand(activeElement: Element): void {
1881
if (isFirefox) {
1882
(<HTMLInputElement>activeElement).focus();
1883
(<HTMLInputElement>activeElement).select();
1884
}
1885
1886
activeElement.ownerDocument.execCommand('selectAll');
1887
}
1888
public runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, args: unknown): void {
1889
const viewModel = editor._getViewModel();
1890
if (!viewModel) {
1891
// the editor has no view => has no cursors
1892
return;
1893
}
1894
this.runCoreEditorCommand(viewModel, args);
1895
}
1896
public runCoreEditorCommand(viewModel: IViewModel, args: unknown): void {
1897
viewModel.model.pushStackElement();
1898
viewModel.setCursorStates(
1899
'keyboard',
1900
CursorChangeReason.Explicit,
1901
[
1902
CursorMoveCommands.selectAll(viewModel, viewModel.getPrimaryCursorState())
1903
]
1904
);
1905
}
1906
}();
1907
1908
export interface SetSelectionCommandOptions extends BaseCommandOptions {
1909
selection: ISelection;
1910
}
1911
1912
export const SetSelection: CoreEditorCommand<SetSelectionCommandOptions> = registerEditorCommand(new class extends CoreEditorCommand<SetSelectionCommandOptions> {
1913
constructor() {
1914
super({
1915
id: 'setSelection',
1916
precondition: undefined
1917
});
1918
}
1919
1920
public runCoreEditorCommand(viewModel: IViewModel, args: Partial<SetSelectionCommandOptions>): void {
1921
if (!args.selection) {
1922
return;
1923
}
1924
viewModel.model.pushStackElement();
1925
viewModel.setCursorStates(
1926
args.source,
1927
CursorChangeReason.Explicit,
1928
[
1929
CursorState.fromModelSelection(args.selection)
1930
]
1931
);
1932
}
1933
});
1934
}
1935
1936
const columnSelectionCondition = ContextKeyExpr.and(
1937
EditorContextKeys.textInputFocus,
1938
EditorContextKeys.columnSelection
1939
);
1940
function registerColumnSelection(id: string, keybinding: number): void {
1941
KeybindingsRegistry.registerKeybindingRule({
1942
id: id,
1943
primary: keybinding,
1944
when: columnSelectionCondition,
1945
weight: CORE_WEIGHT + 1
1946
});
1947
}
1948
1949
registerColumnSelection(CoreNavigationCommands.CursorColumnSelectLeft.id, KeyMod.Shift | KeyCode.LeftArrow);
1950
registerColumnSelection(CoreNavigationCommands.CursorColumnSelectRight.id, KeyMod.Shift | KeyCode.RightArrow);
1951
registerColumnSelection(CoreNavigationCommands.CursorColumnSelectUp.id, KeyMod.Shift | KeyCode.UpArrow);
1952
registerColumnSelection(CoreNavigationCommands.CursorColumnSelectPageUp.id, KeyMod.Shift | KeyCode.PageUp);
1953
registerColumnSelection(CoreNavigationCommands.CursorColumnSelectDown.id, KeyMod.Shift | KeyCode.DownArrow);
1954
registerColumnSelection(CoreNavigationCommands.CursorColumnSelectPageDown.id, KeyMod.Shift | KeyCode.PageDown);
1955
1956
function registerCommand<T extends Command>(command: T): T {
1957
command.register();
1958
return command;
1959
}
1960
1961
export namespace CoreEditingCommands {
1962
1963
export abstract class CoreEditingCommand extends EditorCommand {
1964
public runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, args: unknown): void {
1965
const viewModel = editor._getViewModel();
1966
if (!viewModel) {
1967
// the editor has no view => has no cursors
1968
return;
1969
}
1970
this.runCoreEditingCommand(editor, viewModel, args || {});
1971
}
1972
1973
public abstract runCoreEditingCommand(editor: ICodeEditor, viewModel: IViewModel, args: unknown): void;
1974
}
1975
1976
export const LineBreakInsert: EditorCommand = registerEditorCommand(new class extends CoreEditingCommand {
1977
constructor() {
1978
super({
1979
id: 'lineBreakInsert',
1980
precondition: EditorContextKeys.writable,
1981
kbOpts: {
1982
weight: CORE_WEIGHT,
1983
kbExpr: EditorContextKeys.textInputFocus,
1984
primary: 0,
1985
mac: { primary: KeyMod.WinCtrl | KeyCode.KeyO }
1986
}
1987
});
1988
}
1989
1990
public runCoreEditingCommand(editor: ICodeEditor, viewModel: IViewModel, args: unknown): void {
1991
editor.pushUndoStop();
1992
editor.executeCommands(this.id, EnterOperation.lineBreakInsert(viewModel.cursorConfig, viewModel.model, viewModel.getCursorStates().map(s => s.modelState.selection)));
1993
}
1994
});
1995
1996
export const Outdent: EditorCommand = registerEditorCommand(new class extends CoreEditingCommand {
1997
constructor() {
1998
super({
1999
id: 'outdent',
2000
precondition: EditorContextKeys.writable,
2001
kbOpts: {
2002
weight: CORE_WEIGHT,
2003
kbExpr: ContextKeyExpr.and(
2004
EditorContextKeys.editorTextFocus,
2005
EditorContextKeys.tabDoesNotMoveFocus
2006
),
2007
primary: KeyMod.Shift | KeyCode.Tab
2008
}
2009
});
2010
}
2011
2012
public runCoreEditingCommand(editor: ICodeEditor, viewModel: IViewModel, args: unknown): void {
2013
editor.pushUndoStop();
2014
editor.executeCommands(this.id, TypeOperations.outdent(viewModel.cursorConfig, viewModel.model, viewModel.getCursorStates().map(s => s.modelState.selection)));
2015
editor.pushUndoStop();
2016
}
2017
});
2018
2019
export const Tab: EditorCommand = registerEditorCommand(new class extends CoreEditingCommand {
2020
constructor() {
2021
super({
2022
id: 'tab',
2023
precondition: EditorContextKeys.writable,
2024
kbOpts: {
2025
weight: CORE_WEIGHT,
2026
kbExpr: ContextKeyExpr.and(
2027
EditorContextKeys.editorTextFocus,
2028
EditorContextKeys.tabDoesNotMoveFocus
2029
),
2030
primary: KeyCode.Tab
2031
}
2032
});
2033
}
2034
2035
public runCoreEditingCommand(editor: ICodeEditor, viewModel: IViewModel, args: unknown): void {
2036
editor.pushUndoStop();
2037
editor.executeCommands(this.id, TypeOperations.tab(viewModel.cursorConfig, viewModel.model, viewModel.getCursorStates().map(s => s.modelState.selection)));
2038
editor.pushUndoStop();
2039
}
2040
});
2041
2042
export const DeleteLeft: EditorCommand = registerEditorCommand(new class extends CoreEditingCommand {
2043
constructor() {
2044
super({
2045
id: 'deleteLeft',
2046
precondition: undefined,
2047
kbOpts: {
2048
weight: CORE_WEIGHT,
2049
kbExpr: EditorContextKeys.textInputFocus,
2050
primary: KeyCode.Backspace,
2051
secondary: [KeyMod.Shift | KeyCode.Backspace],
2052
mac: { primary: KeyCode.Backspace, secondary: [KeyMod.Shift | KeyCode.Backspace, KeyMod.WinCtrl | KeyCode.KeyH, KeyMod.WinCtrl | KeyCode.Backspace] }
2053
}
2054
});
2055
}
2056
2057
public runCoreEditingCommand(editor: ICodeEditor, viewModel: IViewModel, args: unknown): void {
2058
const [shouldPushStackElementBefore, commands] = DeleteOperations.deleteLeft(viewModel.getPrevEditOperationType(), viewModel.cursorConfig, viewModel.model, viewModel.getCursorStates().map(s => s.modelState.selection), viewModel.getCursorAutoClosedCharacters());
2059
if (shouldPushStackElementBefore) {
2060
editor.pushUndoStop();
2061
}
2062
editor.executeCommands(this.id, commands);
2063
viewModel.setPrevEditOperationType(EditOperationType.DeletingLeft);
2064
}
2065
});
2066
2067
export const DeleteRight: EditorCommand = registerEditorCommand(new class extends CoreEditingCommand {
2068
constructor() {
2069
super({
2070
id: 'deleteRight',
2071
precondition: undefined,
2072
kbOpts: {
2073
weight: CORE_WEIGHT,
2074
kbExpr: EditorContextKeys.textInputFocus,
2075
primary: KeyCode.Delete,
2076
mac: { primary: KeyCode.Delete, secondary: [KeyMod.WinCtrl | KeyCode.KeyD, KeyMod.WinCtrl | KeyCode.Delete] }
2077
}
2078
});
2079
}
2080
2081
public runCoreEditingCommand(editor: ICodeEditor, viewModel: IViewModel, args: unknown): void {
2082
const [shouldPushStackElementBefore, commands] = DeleteOperations.deleteRight(viewModel.getPrevEditOperationType(), viewModel.cursorConfig, viewModel.model, viewModel.getCursorStates().map(s => s.modelState.selection));
2083
if (shouldPushStackElementBefore) {
2084
editor.pushUndoStop();
2085
}
2086
editor.executeCommands(this.id, commands);
2087
viewModel.setPrevEditOperationType(EditOperationType.DeletingRight);
2088
}
2089
});
2090
2091
export const Undo = new class extends EditorOrNativeTextInputCommand {
2092
constructor() {
2093
super(UndoCommand);
2094
}
2095
public runDOMCommand(activeElement: Element): void {
2096
activeElement.ownerDocument.execCommand('undo');
2097
}
2098
public runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, args: unknown): void | Promise<void> {
2099
if (!editor.hasModel() || editor.getOption(EditorOption.readOnly) === true) {
2100
return;
2101
}
2102
return editor.getModel().undo();
2103
}
2104
}();
2105
2106
export const Redo = new class extends EditorOrNativeTextInputCommand {
2107
constructor() {
2108
super(RedoCommand);
2109
}
2110
public runDOMCommand(activeElement: Element): void {
2111
activeElement.ownerDocument.execCommand('redo');
2112
}
2113
public runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, args: unknown): void | Promise<void> {
2114
if (!editor.hasModel() || editor.getOption(EditorOption.readOnly) === true) {
2115
return;
2116
}
2117
return editor.getModel().redo();
2118
}
2119
}();
2120
}
2121
2122
/**
2123
* A command that will invoke a command on the focused editor.
2124
*/
2125
class EditorHandlerCommand extends Command {
2126
2127
private readonly _handlerId: string;
2128
2129
constructor(id: string, handlerId: string, metadata?: ICommandMetadata) {
2130
super({
2131
id: id,
2132
precondition: undefined,
2133
metadata
2134
});
2135
this._handlerId = handlerId;
2136
}
2137
2138
public runCommand(accessor: ServicesAccessor, args: unknown): void {
2139
const editor = accessor.get(ICodeEditorService).getFocusedCodeEditor();
2140
if (!editor) {
2141
return;
2142
}
2143
2144
editor.trigger('keyboard', this._handlerId, args);
2145
}
2146
}
2147
2148
function registerOverwritableCommand(handlerId: string, metadata?: ICommandMetadata): void {
2149
registerCommand(new EditorHandlerCommand('default:' + handlerId, handlerId));
2150
registerCommand(new EditorHandlerCommand(handlerId, handlerId, metadata));
2151
}
2152
2153
registerOverwritableCommand(Handler.Type, {
2154
description: `Type`,
2155
args: [{
2156
name: 'args',
2157
schema: {
2158
'type': 'object',
2159
'required': ['text'],
2160
'properties': {
2161
'text': {
2162
'type': 'string'
2163
}
2164
},
2165
}
2166
}]
2167
});
2168
registerOverwritableCommand(Handler.ReplacePreviousChar);
2169
registerOverwritableCommand(Handler.CompositionType);
2170
registerOverwritableCommand(Handler.CompositionStart);
2171
registerOverwritableCommand(Handler.CompositionEnd);
2172
registerOverwritableCommand(Handler.Paste);
2173
registerOverwritableCommand(Handler.Cut);
2174
2175