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