From 25018bedbcddb43e861ce141d7e0ae627cce404d Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Mon, 19 Sep 2022 08:56:42 +0200 Subject: [PATCH 1/5] Add `IMouseTargetOutsideEditor.outsidePosition` --- src/vs/editor/browser/controller/mouseHandler.ts | 12 ++++++------ src/vs/editor/browser/controller/mouseTarget.ts | 4 ++-- src/vs/editor/browser/editorBrowser.ts | 1 + src/vs/monaco.d.ts | 1 + 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/vs/editor/browser/controller/mouseHandler.ts b/src/vs/editor/browser/controller/mouseHandler.ts index 8b1bab406b2..09f5fca5ec7 100644 --- a/src/vs/editor/browser/controller/mouseHandler.ts +++ b/src/vs/editor/browser/controller/mouseHandler.ts @@ -501,12 +501,12 @@ class MouseDownOperation extends Disposable { if (viewZoneData) { const newPosition = this._helpPositionJumpOverViewZone(viewZoneData); if (newPosition) { - return MouseTarget.createOutsideEditor(mouseColumn, newPosition); + return MouseTarget.createOutsideEditor(mouseColumn, newPosition, 'above'); } } const aboveLineNumber = viewLayout.getLineNumberAtVerticalOffset(verticalOffset); - return MouseTarget.createOutsideEditor(mouseColumn, new Position(aboveLineNumber, 1)); + return MouseTarget.createOutsideEditor(mouseColumn, new Position(aboveLineNumber, 1), 'above'); } if (e.posy > editorContent.y + editorContent.height) { @@ -515,22 +515,22 @@ class MouseDownOperation extends Disposable { if (viewZoneData) { const newPosition = this._helpPositionJumpOverViewZone(viewZoneData); if (newPosition) { - return MouseTarget.createOutsideEditor(mouseColumn, newPosition); + return MouseTarget.createOutsideEditor(mouseColumn, newPosition, 'below'); } } const belowLineNumber = viewLayout.getLineNumberAtVerticalOffset(verticalOffset); - return MouseTarget.createOutsideEditor(mouseColumn, new Position(belowLineNumber, model.getLineMaxColumn(belowLineNumber))); + return MouseTarget.createOutsideEditor(mouseColumn, new Position(belowLineNumber, model.getLineMaxColumn(belowLineNumber)), 'below'); } const possibleLineNumber = viewLayout.getLineNumberAtVerticalOffset(viewLayout.getCurrentScrollTop() + e.relativePos.y); if (e.posx < editorContent.x) { - return MouseTarget.createOutsideEditor(mouseColumn, new Position(possibleLineNumber, 1)); + return MouseTarget.createOutsideEditor(mouseColumn, new Position(possibleLineNumber, 1), 'left'); } if (e.posx > editorContent.x + editorContent.width) { - return MouseTarget.createOutsideEditor(mouseColumn, new Position(possibleLineNumber, model.getLineMaxColumn(possibleLineNumber))); + return MouseTarget.createOutsideEditor(mouseColumn, new Position(possibleLineNumber, model.getLineMaxColumn(possibleLineNumber)), 'right'); } return null; diff --git a/src/vs/editor/browser/controller/mouseTarget.ts b/src/vs/editor/browser/controller/mouseTarget.ts index c13cd539659..d8f70006003 100644 --- a/src/vs/editor/browser/controller/mouseTarget.ts +++ b/src/vs/editor/browser/controller/mouseTarget.ts @@ -99,8 +99,8 @@ export class MouseTarget { public static createOverlayWidget(element: Element | null, mouseColumn: number, detail: string): IMouseTargetOverlayWidget { return { type: MouseTargetType.OVERLAY_WIDGET, element, mouseColumn, position: null, range: null, detail }; } - public static createOutsideEditor(mouseColumn: number, position: Position): IMouseTargetOutsideEditor { - return { type: MouseTargetType.OUTSIDE_EDITOR, element: null, mouseColumn, position, range: this._deduceRage(position) }; + public static createOutsideEditor(mouseColumn: number, position: Position, outsidePosition: 'above' | 'below' | 'left' | 'right'): IMouseTargetOutsideEditor { + return { type: MouseTargetType.OUTSIDE_EDITOR, element: null, mouseColumn, position, range: this._deduceRage(position), outsidePosition }; } private static _typeToString(type: MouseTargetType): string { diff --git a/src/vs/editor/browser/editorBrowser.ts b/src/vs/editor/browser/editorBrowser.ts index d80aaf6042d..2290aa541eb 100644 --- a/src/vs/editor/browser/editorBrowser.ts +++ b/src/vs/editor/browser/editorBrowser.ts @@ -391,6 +391,7 @@ export interface IMouseTargetOverviewRuler extends IBaseMouseTarget { } export interface IMouseTargetOutsideEditor extends IBaseMouseTarget { readonly type: MouseTargetType.OUTSIDE_EDITOR; + readonly outsidePosition: 'above' | 'below' | 'left' | 'right'; } /** * Target hit with the mouse in the editor. diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 8736a56f0b9..dcd7586f36c 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -5046,6 +5046,7 @@ declare namespace monaco.editor { export interface IMouseTargetOutsideEditor extends IBaseMouseTarget { readonly type: MouseTargetType.OUTSIDE_EDITOR; + readonly outsidePosition: 'above' | 'below' | 'left' | 'right'; } /** From 77fc18104bed0678b37861d792a9598b4bd457ab Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Mon, 19 Sep 2022 09:00:10 +0200 Subject: [PATCH 2/5] Add `IMouseTargetOutsideEditor.outsideDistance` --- .../editor/browser/controller/mouseHandler.ts | 18 +++++++++++------- .../editor/browser/controller/mouseTarget.ts | 4 ++-- src/vs/editor/browser/editorBrowser.ts | 1 + src/vs/monaco.d.ts | 1 + 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/vs/editor/browser/controller/mouseHandler.ts b/src/vs/editor/browser/controller/mouseHandler.ts index 09f5fca5ec7..f8960556738 100644 --- a/src/vs/editor/browser/controller/mouseHandler.ts +++ b/src/vs/editor/browser/controller/mouseHandler.ts @@ -496,41 +496,45 @@ class MouseDownOperation extends Disposable { const mouseColumn = this._getMouseColumn(e); if (e.posy < editorContent.y) { - const verticalOffset = Math.max(viewLayout.getCurrentScrollTop() - (editorContent.y - e.posy), 0); + const outsideDistance = editorContent.y - e.posy; + const verticalOffset = Math.max(viewLayout.getCurrentScrollTop() - outsideDistance, 0); const viewZoneData = HitTestContext.getZoneAtCoord(this._context, verticalOffset); if (viewZoneData) { const newPosition = this._helpPositionJumpOverViewZone(viewZoneData); if (newPosition) { - return MouseTarget.createOutsideEditor(mouseColumn, newPosition, 'above'); + return MouseTarget.createOutsideEditor(mouseColumn, newPosition, 'above', outsideDistance); } } const aboveLineNumber = viewLayout.getLineNumberAtVerticalOffset(verticalOffset); - return MouseTarget.createOutsideEditor(mouseColumn, new Position(aboveLineNumber, 1), 'above'); + return MouseTarget.createOutsideEditor(mouseColumn, new Position(aboveLineNumber, 1), 'above', outsideDistance); } if (e.posy > editorContent.y + editorContent.height) { + const outsideDistance = e.posy - editorContent.y - editorContent.height; const verticalOffset = viewLayout.getCurrentScrollTop() + e.relativePos.y; const viewZoneData = HitTestContext.getZoneAtCoord(this._context, verticalOffset); if (viewZoneData) { const newPosition = this._helpPositionJumpOverViewZone(viewZoneData); if (newPosition) { - return MouseTarget.createOutsideEditor(mouseColumn, newPosition, 'below'); + return MouseTarget.createOutsideEditor(mouseColumn, newPosition, 'below', outsideDistance); } } const belowLineNumber = viewLayout.getLineNumberAtVerticalOffset(verticalOffset); - return MouseTarget.createOutsideEditor(mouseColumn, new Position(belowLineNumber, model.getLineMaxColumn(belowLineNumber)), 'below'); + return MouseTarget.createOutsideEditor(mouseColumn, new Position(belowLineNumber, model.getLineMaxColumn(belowLineNumber)), 'below', outsideDistance); } const possibleLineNumber = viewLayout.getLineNumberAtVerticalOffset(viewLayout.getCurrentScrollTop() + e.relativePos.y); if (e.posx < editorContent.x) { - return MouseTarget.createOutsideEditor(mouseColumn, new Position(possibleLineNumber, 1), 'left'); + const outsideDistance = editorContent.x - e.posx; + return MouseTarget.createOutsideEditor(mouseColumn, new Position(possibleLineNumber, 1), 'left', outsideDistance); } if (e.posx > editorContent.x + editorContent.width) { - return MouseTarget.createOutsideEditor(mouseColumn, new Position(possibleLineNumber, model.getLineMaxColumn(possibleLineNumber)), 'right'); + const outsideDistance = e.posx - editorContent.x - editorContent.width; + return MouseTarget.createOutsideEditor(mouseColumn, new Position(possibleLineNumber, model.getLineMaxColumn(possibleLineNumber)), 'right', outsideDistance); } return null; diff --git a/src/vs/editor/browser/controller/mouseTarget.ts b/src/vs/editor/browser/controller/mouseTarget.ts index d8f70006003..beca450d9ef 100644 --- a/src/vs/editor/browser/controller/mouseTarget.ts +++ b/src/vs/editor/browser/controller/mouseTarget.ts @@ -99,8 +99,8 @@ export class MouseTarget { public static createOverlayWidget(element: Element | null, mouseColumn: number, detail: string): IMouseTargetOverlayWidget { return { type: MouseTargetType.OVERLAY_WIDGET, element, mouseColumn, position: null, range: null, detail }; } - public static createOutsideEditor(mouseColumn: number, position: Position, outsidePosition: 'above' | 'below' | 'left' | 'right'): IMouseTargetOutsideEditor { - return { type: MouseTargetType.OUTSIDE_EDITOR, element: null, mouseColumn, position, range: this._deduceRage(position), outsidePosition }; + public static createOutsideEditor(mouseColumn: number, position: Position, outsidePosition: 'above' | 'below' | 'left' | 'right', outsideDistance: number): IMouseTargetOutsideEditor { + return { type: MouseTargetType.OUTSIDE_EDITOR, element: null, mouseColumn, position, range: this._deduceRage(position), outsidePosition, outsideDistance }; } private static _typeToString(type: MouseTargetType): string { diff --git a/src/vs/editor/browser/editorBrowser.ts b/src/vs/editor/browser/editorBrowser.ts index 2290aa541eb..d768689d23a 100644 --- a/src/vs/editor/browser/editorBrowser.ts +++ b/src/vs/editor/browser/editorBrowser.ts @@ -392,6 +392,7 @@ export interface IMouseTargetOverviewRuler extends IBaseMouseTarget { export interface IMouseTargetOutsideEditor extends IBaseMouseTarget { readonly type: MouseTargetType.OUTSIDE_EDITOR; readonly outsidePosition: 'above' | 'below' | 'left' | 'right'; + readonly outsideDistance: number; } /** * Target hit with the mouse in the editor. diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index dcd7586f36c..5c9c1a1a25c 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -5047,6 +5047,7 @@ declare namespace monaco.editor { export interface IMouseTargetOutsideEditor extends IBaseMouseTarget { readonly type: MouseTargetType.OUTSIDE_EDITOR; readonly outsidePosition: 'above' | 'below' | 'left' | 'right'; + readonly outsideDistance: number; } /** From 5b7dc41f027bc590c679882bb394a84ce91cb622 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Tue, 20 Sep 2022 18:44:00 +0200 Subject: [PATCH 3/5] Add types to editor core commands arguments --- src/vs/editor/browser/coreCommands.ts | 317 +++++++++++------- .../common/cursor/cursorMoveCommands.ts | 6 +- 2 files changed, 197 insertions(+), 126 deletions(-) diff --git a/src/vs/editor/browser/coreCommands.ts b/src/vs/editor/browser/coreCommands.ts index b5ab2a699e1..de59a8b7f6e 100644 --- a/src/vs/editor/browser/coreCommands.ts +++ b/src/vs/editor/browser/coreCommands.ts @@ -17,7 +17,7 @@ import { DeleteOperations } from 'vs/editor/common/cursor/cursorDeleteOperations import { CursorChangeReason } from 'vs/editor/common/cursorEvents'; import { CursorMove as CursorMove_, CursorMoveCommands } from 'vs/editor/common/cursor/cursorMoveCommands'; import { TypeOperations } from 'vs/editor/common/cursor/cursorTypeOperations'; -import { Position } from 'vs/editor/common/core/position'; +import { IPosition, Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; import { Handler, ScrollType } from 'vs/editor/common/editorCommon'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; @@ -28,11 +28,12 @@ import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation import { KeybindingWeight, KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; import { IViewModel } from 'vs/editor/common/viewModel'; +import { ISelection } from 'vs/editor/common/core/selection'; const CORE_WEIGHT = KeybindingWeight.EditorCore; -export abstract class CoreEditorCommand extends EditorCommand { - public runEditorCommand(accessor: ServicesAccessor | null, editor: ICodeEditor, args: any): void { +export abstract class CoreEditorCommand extends EditorCommand { + public runEditorCommand(accessor: ServicesAccessor | null, editor: ICodeEditor, args?: T | null): void { const viewModel = editor._getViewModel(); if (!viewModel) { // the editor has no view => has no cursors @@ -41,7 +42,7 @@ export abstract class CoreEditorCommand extends EditorCommand { this.runCoreEditorCommand(viewModel, args || {}); } - public abstract runCoreEditorCommand(viewModel: IViewModel, args: any): void; + public abstract runCoreEditorCommand(viewModel: IViewModel, args: Partial): void; } export namespace EditorScroll_ { @@ -145,7 +146,7 @@ export namespace EditorScroll_ { select?: boolean; } - export function parse(args: RawArguments): ParsedArguments | null { + export function parse(args: Partial): ParsedArguments | null { let direction: Direction; switch (args.to) { case RawDirection.Up: @@ -286,7 +287,7 @@ abstract class EditorOrNativeTextInputCommand { constructor(target: MultiCommand) { // 1. handle case when focus is in editor. - target.addImplementation(10000, 'code-editor', (accessor: ServicesAccessor, args: any) => { + target.addImplementation(10000, 'code-editor', (accessor: ServicesAccessor, args: unknown) => { // Only if editor text focus (i.e. not if editor has widget focus). const focusedEditor = accessor.get(ICodeEditorService).getFocusedCodeEditor(); if (focusedEditor && focusedEditor.hasTextFocus()) { @@ -296,7 +297,7 @@ abstract class EditorOrNativeTextInputCommand { }); // 2. handle case when focus is in some other `input` / `textarea`. - target.addImplementation(1000, 'generic-dom-input-textarea', (accessor: ServicesAccessor, args: any) => { + target.addImplementation(1000, 'generic-dom-input-textarea', (accessor: ServicesAccessor, args: unknown) => { // Only if focused on an element that allows for entering text const activeElement = document.activeElement; if (activeElement && ['input', 'textarea'].indexOf(activeElement.tagName.toLowerCase()) >= 0) { @@ -307,7 +308,7 @@ abstract class EditorOrNativeTextInputCommand { }); // 3. (default) handle case when focus is somewhere else. - target.addImplementation(0, 'generic-dom', (accessor: ServicesAccessor, args: any) => { + target.addImplementation(0, 'generic-dom', (accessor: ServicesAccessor, args: unknown) => { // Redirecting to active editor const activeEditor = accessor.get(ICodeEditorService).getActiveCodeEditor(); if (activeEditor) { @@ -318,7 +319,7 @@ abstract class EditorOrNativeTextInputCommand { }); } - public _runEditorCommand(accessor: ServicesAccessor | null, editor: ICodeEditor, args: any): boolean | Promise { + public _runEditorCommand(accessor: ServicesAccessor | null, editor: ICodeEditor, args: unknown): boolean | Promise { const result = this.runEditorCommand(accessor, editor, args); if (result) { return result; @@ -327,12 +328,21 @@ abstract class EditorOrNativeTextInputCommand { } public abstract runDOMCommand(): void; - public abstract runEditorCommand(accessor: ServicesAccessor | null, editor: ICodeEditor, args: any): void | Promise; + public abstract runEditorCommand(accessor: ServicesAccessor | null, editor: ICodeEditor, args: unknown): void | Promise; } export namespace CoreNavigationCommands { - class BaseMoveToCommand extends CoreEditorCommand { + export interface BaseCommandOptions { + source?: 'mouse' | 'keyboard' | string; + } + + export interface MoveCommandOptions extends BaseCommandOptions { + position: IPosition; + viewPosition?: IPosition; + } + + class BaseMoveToCommand extends CoreEditorCommand { private readonly _minimalReveal: boolean; private readonly _inSelectionMode: boolean; @@ -343,7 +353,10 @@ export namespace CoreNavigationCommands { this._inSelectionMode = opts.inSelectionMode; } - public runCoreEditorCommand(viewModel: IViewModel, args: any): void { + public runCoreEditorCommand(viewModel: IViewModel, args: Partial): void { + if (!args.position) { + return; + } viewModel.model.pushStackElement(); const cursorStateChanged = viewModel.setCursorStates( args.source, @@ -358,24 +371,28 @@ export namespace CoreNavigationCommands { } } - export const MoveTo: CoreEditorCommand = registerEditorCommand(new BaseMoveToCommand({ + export const MoveTo: CoreEditorCommand = registerEditorCommand(new BaseMoveToCommand({ id: '_moveTo', minimalReveal: true, inSelectionMode: false, precondition: undefined })); - export const MoveToSelect: CoreEditorCommand = registerEditorCommand(new BaseMoveToCommand({ + export const MoveToSelect: CoreEditorCommand = registerEditorCommand(new BaseMoveToCommand({ id: '_moveToSelect', minimalReveal: false, inSelectionMode: true, precondition: undefined })); - abstract class ColumnSelectCommand extends CoreEditorCommand { - public runCoreEditorCommand(viewModel: IViewModel, args: any): void { + abstract class ColumnSelectCommand extends CoreEditorCommand { + public runCoreEditorCommand(viewModel: IViewModel, args: Partial): void { viewModel.model.pushStackElement(); const result = this._getColumnSelectResult(viewModel, viewModel.getPrimaryCursorState(), viewModel.getCursorColumnSelectData(), args); + if (result === null) { + // invalid arguments + return; + } viewModel.setCursorStates(args.source, CursorChangeReason.Explicit, result.viewStates.map((viewState) => CursorState.fromViewState(viewState))); viewModel.setCursorColumnSelectData({ isReal: true, @@ -391,11 +408,18 @@ export namespace CoreNavigationCommands { } } - protected abstract _getColumnSelectResult(viewModel: IViewModel, primary: CursorState, prevColumnSelectData: IColumnSelectData, args: any): IColumnSelectResult; + protected abstract _getColumnSelectResult(viewModel: IViewModel, primary: CursorState, prevColumnSelectData: IColumnSelectData, args: Partial): IColumnSelectResult | null; } - export const ColumnSelect: CoreEditorCommand = registerEditorCommand(new class extends ColumnSelectCommand { + export interface ColumnSelectCommandOptions extends BaseCommandOptions { + position: IPosition; + viewPosition: IPosition; + doColumnSelect: boolean; + mouseColumn: number; + } + + export const ColumnSelect: CoreEditorCommand = registerEditorCommand(new class extends ColumnSelectCommand { constructor() { super({ id: 'columnSelect', @@ -403,8 +427,10 @@ export namespace CoreNavigationCommands { }); } - protected _getColumnSelectResult(viewModel: IViewModel, primary: CursorState, prevColumnSelectData: IColumnSelectData, args: any): IColumnSelectResult { - + protected _getColumnSelectResult(viewModel: IViewModel, primary: CursorState, prevColumnSelectData: IColumnSelectData, args: Partial): IColumnSelectResult | null { + if (typeof args.position === 'undefined' || typeof args.viewPosition === 'undefined' || typeof args.mouseColumn === 'undefined') { + return null; + } // validate `args` const validatedPosition = viewModel.model.validatePosition(args.position); const validatedViewPosition = viewModel.coordinatesConverter.validateViewPosition(new Position(args.viewPosition.lineNumber, args.viewPosition.column), validatedPosition); @@ -415,7 +441,7 @@ export namespace CoreNavigationCommands { } }); - export const CursorColumnSelectLeft: CoreEditorCommand = registerEditorCommand(new class extends ColumnSelectCommand { + export const CursorColumnSelectLeft: CoreEditorCommand = registerEditorCommand(new class extends ColumnSelectCommand { constructor() { super({ id: 'cursorColumnSelectLeft', @@ -429,12 +455,12 @@ export namespace CoreNavigationCommands { }); } - protected _getColumnSelectResult(viewModel: IViewModel, primary: CursorState, prevColumnSelectData: IColumnSelectData, args: any): IColumnSelectResult { + protected _getColumnSelectResult(viewModel: IViewModel, primary: CursorState, prevColumnSelectData: IColumnSelectData, args: Partial): IColumnSelectResult { return ColumnSelection.columnSelectLeft(viewModel.cursorConfig, viewModel, prevColumnSelectData); } }); - export const CursorColumnSelectRight: CoreEditorCommand = registerEditorCommand(new class extends ColumnSelectCommand { + export const CursorColumnSelectRight: CoreEditorCommand = registerEditorCommand(new class extends ColumnSelectCommand { constructor() { super({ id: 'cursorColumnSelectRight', @@ -448,7 +474,7 @@ export namespace CoreNavigationCommands { }); } - protected _getColumnSelectResult(viewModel: IViewModel, primary: CursorState, prevColumnSelectData: IColumnSelectData, args: any): IColumnSelectResult { + protected _getColumnSelectResult(viewModel: IViewModel, primary: CursorState, prevColumnSelectData: IColumnSelectData, args: Partial): IColumnSelectResult { return ColumnSelection.columnSelectRight(viewModel.cursorConfig, viewModel, prevColumnSelectData); } }); @@ -462,12 +488,12 @@ export namespace CoreNavigationCommands { this._isPaged = opts.isPaged; } - protected _getColumnSelectResult(viewModel: IViewModel, primary: CursorState, prevColumnSelectData: IColumnSelectData, args: any): IColumnSelectResult { + protected _getColumnSelectResult(viewModel: IViewModel, primary: CursorState, prevColumnSelectData: IColumnSelectData, args: Partial): IColumnSelectResult { return ColumnSelection.columnSelectUp(viewModel.cursorConfig, viewModel, prevColumnSelectData, this._isPaged); } } - export const CursorColumnSelectUp: CoreEditorCommand = registerEditorCommand(new ColumnSelectUpCommand({ + export const CursorColumnSelectUp: CoreEditorCommand = registerEditorCommand(new ColumnSelectUpCommand({ isPaged: false, id: 'cursorColumnSelectUp', precondition: undefined, @@ -479,7 +505,7 @@ export namespace CoreNavigationCommands { } })); - export const CursorColumnSelectPageUp: CoreEditorCommand = registerEditorCommand(new ColumnSelectUpCommand({ + export const CursorColumnSelectPageUp: CoreEditorCommand = registerEditorCommand(new ColumnSelectUpCommand({ isPaged: true, id: 'cursorColumnSelectPageUp', precondition: undefined, @@ -500,12 +526,12 @@ export namespace CoreNavigationCommands { this._isPaged = opts.isPaged; } - protected _getColumnSelectResult(viewModel: IViewModel, primary: CursorState, prevColumnSelectData: IColumnSelectData, args: any): IColumnSelectResult { + protected _getColumnSelectResult(viewModel: IViewModel, primary: CursorState, prevColumnSelectData: IColumnSelectData, args: Partial): IColumnSelectResult { return ColumnSelection.columnSelectDown(viewModel.cursorConfig, viewModel, prevColumnSelectData, this._isPaged); } } - export const CursorColumnSelectDown: CoreEditorCommand = registerEditorCommand(new ColumnSelectDownCommand({ + export const CursorColumnSelectDown: CoreEditorCommand = registerEditorCommand(new ColumnSelectDownCommand({ isPaged: false, id: 'cursorColumnSelectDown', precondition: undefined, @@ -517,7 +543,7 @@ export namespace CoreNavigationCommands { } })); - export const CursorColumnSelectPageDown: CoreEditorCommand = registerEditorCommand(new ColumnSelectDownCommand({ + export const CursorColumnSelectPageDown: CoreEditorCommand = registerEditorCommand(new ColumnSelectDownCommand({ isPaged: true, id: 'cursorColumnSelectPageDown', precondition: undefined, @@ -529,7 +555,7 @@ export namespace CoreNavigationCommands { } })); - export class CursorMoveImpl extends CoreEditorCommand { + export class CursorMoveImpl extends CoreEditorCommand { constructor() { super({ id: 'cursorMove', @@ -538,7 +564,7 @@ export namespace CoreNavigationCommands { }); } - public runCoreEditorCommand(viewModel: IViewModel, args: any): void { + public runCoreEditorCommand(viewModel: IViewModel, args: Partial): void { const parsed = CursorMove_.parse(args); if (!parsed) { // illegal arguments @@ -592,7 +618,11 @@ export namespace CoreNavigationCommands { PAGE_SIZE_MARKER = -1 } - class CursorMoveBasedCommand extends CoreEditorCommand { + export interface CursorMoveCommandOptions extends BaseCommandOptions { + pageSize?: number; + } + + class CursorMoveBasedCommand extends CoreEditorCommand { private readonly _staticArgs: CursorMove_.SimpleMoveArguments; @@ -601,7 +631,7 @@ export namespace CoreNavigationCommands { this._staticArgs = opts.args; } - public runCoreEditorCommand(viewModel: IViewModel, dynamicArgs: any): void { + public runCoreEditorCommand(viewModel: IViewModel, dynamicArgs: Partial): void { let args = this._staticArgs; if (this._staticArgs.value === Constants.PAGE_SIZE_MARKER) { // -1 is a marker for page size @@ -623,7 +653,7 @@ export namespace CoreNavigationCommands { } } - export const CursorLeft: CoreEditorCommand = registerEditorCommand(new CursorMoveBasedCommand({ + export const CursorLeft: CoreEditorCommand = registerEditorCommand(new CursorMoveBasedCommand({ args: { direction: CursorMove_.Direction.Left, unit: CursorMove_.Unit.None, @@ -640,7 +670,7 @@ export namespace CoreNavigationCommands { } })); - export const CursorLeftSelect: CoreEditorCommand = registerEditorCommand(new CursorMoveBasedCommand({ + export const CursorLeftSelect: CoreEditorCommand = registerEditorCommand(new CursorMoveBasedCommand({ args: { direction: CursorMove_.Direction.Left, unit: CursorMove_.Unit.None, @@ -656,7 +686,7 @@ export namespace CoreNavigationCommands { } })); - export const CursorRight: CoreEditorCommand = registerEditorCommand(new CursorMoveBasedCommand({ + export const CursorRight: CoreEditorCommand = registerEditorCommand(new CursorMoveBasedCommand({ args: { direction: CursorMove_.Direction.Right, unit: CursorMove_.Unit.None, @@ -673,7 +703,7 @@ export namespace CoreNavigationCommands { } })); - export const CursorRightSelect: CoreEditorCommand = registerEditorCommand(new CursorMoveBasedCommand({ + export const CursorRightSelect: CoreEditorCommand = registerEditorCommand(new CursorMoveBasedCommand({ args: { direction: CursorMove_.Direction.Right, unit: CursorMove_.Unit.None, @@ -689,7 +719,7 @@ export namespace CoreNavigationCommands { } })); - export const CursorUp: CoreEditorCommand = registerEditorCommand(new CursorMoveBasedCommand({ + export const CursorUp: CoreEditorCommand = registerEditorCommand(new CursorMoveBasedCommand({ args: { direction: CursorMove_.Direction.Up, unit: CursorMove_.Unit.WrappedLine, @@ -706,7 +736,7 @@ export namespace CoreNavigationCommands { } })); - export const CursorUpSelect: CoreEditorCommand = registerEditorCommand(new CursorMoveBasedCommand({ + export const CursorUpSelect: CoreEditorCommand = registerEditorCommand(new CursorMoveBasedCommand({ args: { direction: CursorMove_.Direction.Up, unit: CursorMove_.Unit.WrappedLine, @@ -725,7 +755,7 @@ export namespace CoreNavigationCommands { } })); - export const CursorPageUp: CoreEditorCommand = registerEditorCommand(new CursorMoveBasedCommand({ + export const CursorPageUp: CoreEditorCommand = registerEditorCommand(new CursorMoveBasedCommand({ args: { direction: CursorMove_.Direction.Up, unit: CursorMove_.Unit.WrappedLine, @@ -741,7 +771,7 @@ export namespace CoreNavigationCommands { } })); - export const CursorPageUpSelect: CoreEditorCommand = registerEditorCommand(new CursorMoveBasedCommand({ + export const CursorPageUpSelect: CoreEditorCommand = registerEditorCommand(new CursorMoveBasedCommand({ args: { direction: CursorMove_.Direction.Up, unit: CursorMove_.Unit.WrappedLine, @@ -757,7 +787,7 @@ export namespace CoreNavigationCommands { } })); - export const CursorDown: CoreEditorCommand = registerEditorCommand(new CursorMoveBasedCommand({ + export const CursorDown: CoreEditorCommand = registerEditorCommand(new CursorMoveBasedCommand({ args: { direction: CursorMove_.Direction.Down, unit: CursorMove_.Unit.WrappedLine, @@ -774,7 +804,7 @@ export namespace CoreNavigationCommands { } })); - export const CursorDownSelect: CoreEditorCommand = registerEditorCommand(new CursorMoveBasedCommand({ + export const CursorDownSelect: CoreEditorCommand = registerEditorCommand(new CursorMoveBasedCommand({ args: { direction: CursorMove_.Direction.Down, unit: CursorMove_.Unit.WrappedLine, @@ -793,7 +823,7 @@ export namespace CoreNavigationCommands { } })); - export const CursorPageDown: CoreEditorCommand = registerEditorCommand(new CursorMoveBasedCommand({ + export const CursorPageDown: CoreEditorCommand = registerEditorCommand(new CursorMoveBasedCommand({ args: { direction: CursorMove_.Direction.Down, unit: CursorMove_.Unit.WrappedLine, @@ -809,7 +839,7 @@ export namespace CoreNavigationCommands { } })); - export const CursorPageDownSelect: CoreEditorCommand = registerEditorCommand(new CursorMoveBasedCommand({ + export const CursorPageDownSelect: CoreEditorCommand = registerEditorCommand(new CursorMoveBasedCommand({ args: { direction: CursorMove_.Direction.Down, unit: CursorMove_.Unit.WrappedLine, @@ -825,7 +855,11 @@ export namespace CoreNavigationCommands { } })); - export const CreateCursor: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand { + export interface CreateCursorCommandOptions extends MoveCommandOptions { + wholeLine?: boolean; + } + + export const CreateCursor: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand { constructor() { super({ id: 'createCursor', @@ -833,7 +867,10 @@ export namespace CoreNavigationCommands { }); } - public runCoreEditorCommand(viewModel: IViewModel, args: any): void { + public runCoreEditorCommand(viewModel: IViewModel, args: Partial): void { + if (!args.position) { + return; + } let newState: PartialCursorState; if (args.wholeLine) { newState = CursorMoveCommands.line(viewModel, viewModel.getPrimaryCursorState(), false, args.position, args.viewPosition); @@ -884,7 +921,7 @@ export namespace CoreNavigationCommands { } }); - export const LastCursorMoveToSelect: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand { + export const LastCursorMoveToSelect: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand { constructor() { super({ id: '_lastCursorMoveToSelect', @@ -892,7 +929,10 @@ export namespace CoreNavigationCommands { }); } - public runCoreEditorCommand(viewModel: IViewModel, args: any): void { + public runCoreEditorCommand(viewModel: IViewModel, args: Partial): void { + if (!args.position) { + return; + } const lastAddedCursorIndex = viewModel.getLastAddedCursorIndex(); const states = viewModel.getCursorStates(); @@ -908,7 +948,7 @@ export namespace CoreNavigationCommands { } }); - class HomeCommand extends CoreEditorCommand { + class HomeCommand extends CoreEditorCommand { private readonly _inSelectionMode: boolean; @@ -917,7 +957,7 @@ export namespace CoreNavigationCommands { this._inSelectionMode = opts.inSelectionMode; } - public runCoreEditorCommand(viewModel: IViewModel, args: any): void { + public runCoreEditorCommand(viewModel: IViewModel, args: Partial): void { viewModel.model.pushStackElement(); viewModel.setCursorStates( args.source, @@ -928,7 +968,7 @@ export namespace CoreNavigationCommands { } } - export const CursorHome: CoreEditorCommand = registerEditorCommand(new HomeCommand({ + export const CursorHome: CoreEditorCommand = registerEditorCommand(new HomeCommand({ inSelectionMode: false, id: 'cursorHome', precondition: undefined, @@ -940,7 +980,7 @@ export namespace CoreNavigationCommands { } })); - export const CursorHomeSelect: CoreEditorCommand = registerEditorCommand(new HomeCommand({ + export const CursorHomeSelect: CoreEditorCommand = registerEditorCommand(new HomeCommand({ inSelectionMode: true, id: 'cursorHomeSelect', precondition: undefined, @@ -952,7 +992,7 @@ export namespace CoreNavigationCommands { } })); - class LineStartCommand extends CoreEditorCommand { + class LineStartCommand extends CoreEditorCommand { private readonly _inSelectionMode: boolean; @@ -961,7 +1001,7 @@ export namespace CoreNavigationCommands { this._inSelectionMode = opts.inSelectionMode; } - public runCoreEditorCommand(viewModel: IViewModel, args: any): void { + public runCoreEditorCommand(viewModel: IViewModel, args: Partial): void { viewModel.model.pushStackElement(); viewModel.setCursorStates( args.source, @@ -982,7 +1022,7 @@ export namespace CoreNavigationCommands { } } - export const CursorLineStart: CoreEditorCommand = registerEditorCommand(new LineStartCommand({ + export const CursorLineStart: CoreEditorCommand = registerEditorCommand(new LineStartCommand({ inSelectionMode: false, id: 'cursorLineStart', precondition: undefined, @@ -994,7 +1034,7 @@ export namespace CoreNavigationCommands { } })); - export const CursorLineStartSelect: CoreEditorCommand = registerEditorCommand(new LineStartCommand({ + export const CursorLineStartSelect: CoreEditorCommand = registerEditorCommand(new LineStartCommand({ inSelectionMode: true, id: 'cursorLineStartSelect', precondition: undefined, @@ -1006,7 +1046,11 @@ export namespace CoreNavigationCommands { } })); - class EndCommand extends CoreEditorCommand { + export interface EndCommandOptions extends BaseCommandOptions { + sticky?: boolean; + } + + class EndCommand extends CoreEditorCommand { private readonly _inSelectionMode: boolean; @@ -1015,7 +1059,7 @@ export namespace CoreNavigationCommands { this._inSelectionMode = opts.inSelectionMode; } - public runCoreEditorCommand(viewModel: IViewModel, args: any): void { + public runCoreEditorCommand(viewModel: IViewModel, args: Partial): void { viewModel.model.pushStackElement(); viewModel.setCursorStates( args.source, @@ -1026,7 +1070,7 @@ export namespace CoreNavigationCommands { } } - export const CursorEnd: CoreEditorCommand = registerEditorCommand(new EndCommand({ + export const CursorEnd: CoreEditorCommand = registerEditorCommand(new EndCommand({ inSelectionMode: false, id: 'cursorEnd', precondition: undefined, @@ -1055,7 +1099,7 @@ export namespace CoreNavigationCommands { } })); - export const CursorEndSelect: CoreEditorCommand = registerEditorCommand(new EndCommand({ + export const CursorEndSelect: CoreEditorCommand = registerEditorCommand(new EndCommand({ inSelectionMode: true, id: 'cursorEndSelect', precondition: undefined, @@ -1084,7 +1128,7 @@ export namespace CoreNavigationCommands { } })); - class LineEndCommand extends CoreEditorCommand { + class LineEndCommand extends CoreEditorCommand { private readonly _inSelectionMode: boolean; @@ -1093,7 +1137,7 @@ export namespace CoreNavigationCommands { this._inSelectionMode = opts.inSelectionMode; } - public runCoreEditorCommand(viewModel: IViewModel, args: any): void { + public runCoreEditorCommand(viewModel: IViewModel, args: Partial): void { viewModel.model.pushStackElement(); viewModel.setCursorStates( args.source, @@ -1115,7 +1159,7 @@ export namespace CoreNavigationCommands { } } - export const CursorLineEnd: CoreEditorCommand = registerEditorCommand(new LineEndCommand({ + export const CursorLineEnd: CoreEditorCommand = registerEditorCommand(new LineEndCommand({ inSelectionMode: false, id: 'cursorLineEnd', precondition: undefined, @@ -1127,7 +1171,7 @@ export namespace CoreNavigationCommands { } })); - export const CursorLineEndSelect: CoreEditorCommand = registerEditorCommand(new LineEndCommand({ + export const CursorLineEndSelect: CoreEditorCommand = registerEditorCommand(new LineEndCommand({ inSelectionMode: true, id: 'cursorLineEndSelect', precondition: undefined, @@ -1139,7 +1183,7 @@ export namespace CoreNavigationCommands { } })); - class TopCommand extends CoreEditorCommand { + class TopCommand extends CoreEditorCommand { private readonly _inSelectionMode: boolean; @@ -1148,7 +1192,7 @@ export namespace CoreNavigationCommands { this._inSelectionMode = opts.inSelectionMode; } - public runCoreEditorCommand(viewModel: IViewModel, args: any): void { + public runCoreEditorCommand(viewModel: IViewModel, args: Partial): void { viewModel.model.pushStackElement(); viewModel.setCursorStates( args.source, @@ -1159,7 +1203,7 @@ export namespace CoreNavigationCommands { } } - export const CursorTop: CoreEditorCommand = registerEditorCommand(new TopCommand({ + export const CursorTop: CoreEditorCommand = registerEditorCommand(new TopCommand({ inSelectionMode: false, id: 'cursorTop', precondition: undefined, @@ -1171,7 +1215,7 @@ export namespace CoreNavigationCommands { } })); - export const CursorTopSelect: CoreEditorCommand = registerEditorCommand(new TopCommand({ + export const CursorTopSelect: CoreEditorCommand = registerEditorCommand(new TopCommand({ inSelectionMode: true, id: 'cursorTopSelect', precondition: undefined, @@ -1183,7 +1227,7 @@ export namespace CoreNavigationCommands { } })); - class BottomCommand extends CoreEditorCommand { + class BottomCommand extends CoreEditorCommand { private readonly _inSelectionMode: boolean; @@ -1192,7 +1236,7 @@ export namespace CoreNavigationCommands { this._inSelectionMode = opts.inSelectionMode; } - public runCoreEditorCommand(viewModel: IViewModel, args: any): void { + public runCoreEditorCommand(viewModel: IViewModel, args: Partial): void { viewModel.model.pushStackElement(); viewModel.setCursorStates( args.source, @@ -1203,7 +1247,7 @@ export namespace CoreNavigationCommands { } } - export const CursorBottom: CoreEditorCommand = registerEditorCommand(new BottomCommand({ + export const CursorBottom: CoreEditorCommand = registerEditorCommand(new BottomCommand({ inSelectionMode: false, id: 'cursorBottom', precondition: undefined, @@ -1215,7 +1259,7 @@ export namespace CoreNavigationCommands { } })); - export const CursorBottomSelect: CoreEditorCommand = registerEditorCommand(new BottomCommand({ + export const CursorBottomSelect: CoreEditorCommand = registerEditorCommand(new BottomCommand({ inSelectionMode: true, id: 'cursorBottomSelect', precondition: undefined, @@ -1227,7 +1271,9 @@ export namespace CoreNavigationCommands { } })); - export class EditorScrollImpl extends CoreEditorCommand { + export type EditorScrollCommandOptions = EditorScroll_.RawArguments & BaseCommandOptions; + + export class EditorScrollImpl extends CoreEditorCommand { constructor() { super({ id: 'editorScroll', @@ -1236,7 +1282,7 @@ export namespace CoreNavigationCommands { }); } - public runCoreEditorCommand(viewModel: IViewModel, args: any): void { + public runCoreEditorCommand(viewModel: IViewModel, args: Partial): void { const parsed = EditorScroll_.parse(args); if (!parsed) { // illegal arguments @@ -1307,7 +1353,7 @@ export namespace CoreNavigationCommands { export const EditorScroll: EditorScrollImpl = registerEditorCommand(new EditorScrollImpl()); - export const ScrollLineUp: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand { + export const ScrollLineUp: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand { constructor() { super({ id: 'scrollLineUp', @@ -1321,7 +1367,7 @@ export namespace CoreNavigationCommands { }); } - runCoreEditorCommand(viewModel: IViewModel, args: any): void { + runCoreEditorCommand(viewModel: IViewModel, args: Partial): void { EditorScroll._runEditorScroll(viewModel, args.source, { direction: EditorScroll_.Direction.Up, unit: EditorScroll_.Unit.WrappedLine, @@ -1332,7 +1378,7 @@ export namespace CoreNavigationCommands { } }); - export const ScrollPageUp: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand { + export const ScrollPageUp: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand { constructor() { super({ id: 'scrollPageUp', @@ -1347,7 +1393,7 @@ export namespace CoreNavigationCommands { }); } - runCoreEditorCommand(viewModel: IViewModel, args: any): void { + runCoreEditorCommand(viewModel: IViewModel, args: Partial): void { EditorScroll._runEditorScroll(viewModel, args.source, { direction: EditorScroll_.Direction.Up, unit: EditorScroll_.Unit.Page, @@ -1358,7 +1404,7 @@ export namespace CoreNavigationCommands { } }); - export const ScrollEditorTop: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand { + export const ScrollEditorTop: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand { constructor() { super({ id: 'scrollEditorTop', @@ -1370,7 +1416,7 @@ export namespace CoreNavigationCommands { }); } - runCoreEditorCommand(viewModel: IViewModel, args: any): void { + runCoreEditorCommand(viewModel: IViewModel, args: Partial): void { EditorScroll._runEditorScroll(viewModel, args.source, { direction: EditorScroll_.Direction.Up, unit: EditorScroll_.Unit.Editor, @@ -1381,7 +1427,7 @@ export namespace CoreNavigationCommands { } }); - export const ScrollLineDown: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand { + export const ScrollLineDown: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand { constructor() { super({ id: 'scrollLineDown', @@ -1395,7 +1441,7 @@ export namespace CoreNavigationCommands { }); } - runCoreEditorCommand(viewModel: IViewModel, args: any): void { + runCoreEditorCommand(viewModel: IViewModel, args: Partial): void { EditorScroll._runEditorScroll(viewModel, args.source, { direction: EditorScroll_.Direction.Down, unit: EditorScroll_.Unit.WrappedLine, @@ -1406,7 +1452,7 @@ export namespace CoreNavigationCommands { } }); - export const ScrollPageDown: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand { + export const ScrollPageDown: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand { constructor() { super({ id: 'scrollPageDown', @@ -1421,7 +1467,7 @@ export namespace CoreNavigationCommands { }); } - runCoreEditorCommand(viewModel: IViewModel, args: any): void { + runCoreEditorCommand(viewModel: IViewModel, args: Partial): void { EditorScroll._runEditorScroll(viewModel, args.source, { direction: EditorScroll_.Direction.Down, unit: EditorScroll_.Unit.Page, @@ -1432,7 +1478,7 @@ export namespace CoreNavigationCommands { } }); - export const ScrollEditorBottom: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand { + export const ScrollEditorBottom: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand { constructor() { super({ id: 'scrollEditorBottom', @@ -1444,7 +1490,7 @@ export namespace CoreNavigationCommands { }); } - runCoreEditorCommand(viewModel: IViewModel, args: any): void { + runCoreEditorCommand(viewModel: IViewModel, args: Partial): void { EditorScroll._runEditorScroll(viewModel, args.source, { direction: EditorScroll_.Direction.Down, unit: EditorScroll_.Unit.Editor, @@ -1455,7 +1501,11 @@ export namespace CoreNavigationCommands { } }); - class WordCommand extends CoreEditorCommand { + export interface WordCommandOptions extends BaseCommandOptions { + position: IPosition; + } + + class WordCommand extends CoreEditorCommand { private readonly _inSelectionMode: boolean; @@ -1464,7 +1514,10 @@ export namespace CoreNavigationCommands { this._inSelectionMode = opts.inSelectionMode; } - public runCoreEditorCommand(viewModel: IViewModel, args: any): void { + public runCoreEditorCommand(viewModel: IViewModel, args: Partial): void { + if (!args.position) { + return; + } viewModel.model.pushStackElement(); viewModel.setCursorStates( args.source, @@ -1477,19 +1530,19 @@ export namespace CoreNavigationCommands { } } - export const WordSelect: CoreEditorCommand = registerEditorCommand(new WordCommand({ + export const WordSelect: CoreEditorCommand = registerEditorCommand(new WordCommand({ inSelectionMode: false, id: '_wordSelect', precondition: undefined })); - export const WordSelectDrag: CoreEditorCommand = registerEditorCommand(new WordCommand({ + export const WordSelectDrag: CoreEditorCommand = registerEditorCommand(new WordCommand({ inSelectionMode: true, id: '_wordSelectDrag', precondition: undefined })); - export const LastCursorWordSelect: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand { + export const LastCursorWordSelect: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand { constructor() { super({ id: 'lastCursorWordSelect', @@ -1497,7 +1550,10 @@ export namespace CoreNavigationCommands { }); } - public runCoreEditorCommand(viewModel: IViewModel, args: any): void { + public runCoreEditorCommand(viewModel: IViewModel, args: Partial): void { + if (!args.position) { + return; + } const lastAddedCursorIndex = viewModel.getLastAddedCursorIndex(); const states = viewModel.getCursorStates(); @@ -1514,7 +1570,7 @@ export namespace CoreNavigationCommands { } }); - class LineCommand extends CoreEditorCommand { + class LineCommand extends CoreEditorCommand { private readonly _inSelectionMode: boolean; constructor(opts: ICommandOptions & { inSelectionMode: boolean }) { @@ -1522,7 +1578,10 @@ export namespace CoreNavigationCommands { this._inSelectionMode = opts.inSelectionMode; } - public runCoreEditorCommand(viewModel: IViewModel, args: any): void { + public runCoreEditorCommand(viewModel: IViewModel, args: Partial): void { + if (!args.position) { + return; + } viewModel.model.pushStackElement(); viewModel.setCursorStates( args.source, @@ -1535,19 +1594,19 @@ export namespace CoreNavigationCommands { } } - export const LineSelect: CoreEditorCommand = registerEditorCommand(new LineCommand({ + export const LineSelect: CoreEditorCommand = registerEditorCommand(new LineCommand({ inSelectionMode: false, id: '_lineSelect', precondition: undefined })); - export const LineSelectDrag: CoreEditorCommand = registerEditorCommand(new LineCommand({ + export const LineSelectDrag: CoreEditorCommand = registerEditorCommand(new LineCommand({ inSelectionMode: true, id: '_lineSelectDrag', precondition: undefined })); - class LastCursorLineCommand extends CoreEditorCommand { + class LastCursorLineCommand extends CoreEditorCommand { private readonly _inSelectionMode: boolean; constructor(opts: ICommandOptions & { inSelectionMode: boolean }) { @@ -1555,7 +1614,10 @@ export namespace CoreNavigationCommands { this._inSelectionMode = opts.inSelectionMode; } - public runCoreEditorCommand(viewModel: IViewModel, args: any): void { + public runCoreEditorCommand(viewModel: IViewModel, args: Partial): void { + if (!args.position) { + return; + } const lastAddedCursorIndex = viewModel.getLastAddedCursorIndex(); const states = viewModel.getCursorStates(); @@ -1571,19 +1633,19 @@ export namespace CoreNavigationCommands { } } - export const LastCursorLineSelect: CoreEditorCommand = registerEditorCommand(new LastCursorLineCommand({ + export const LastCursorLineSelect: CoreEditorCommand = registerEditorCommand(new LastCursorLineCommand({ inSelectionMode: false, id: 'lastCursorLineSelect', precondition: undefined })); - export const LastCursorLineSelectDrag: CoreEditorCommand = registerEditorCommand(new LastCursorLineCommand({ + export const LastCursorLineSelectDrag: CoreEditorCommand = registerEditorCommand(new LastCursorLineCommand({ inSelectionMode: true, id: 'lastCursorLineSelectDrag', precondition: undefined })); - export const CancelSelection: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand { + export const CancelSelection: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand { constructor() { super({ id: 'cancelSelection', @@ -1597,7 +1659,7 @@ export namespace CoreNavigationCommands { }); } - public runCoreEditorCommand(viewModel: IViewModel, args: any): void { + public runCoreEditorCommand(viewModel: IViewModel, args: Partial): void { viewModel.model.pushStackElement(); viewModel.setCursorStates( args.source, @@ -1610,7 +1672,7 @@ export namespace CoreNavigationCommands { } }); - export const RemoveSecondaryCursors: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand { + export const RemoveSecondaryCursors: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand { constructor() { super({ id: 'removeSecondaryCursors', @@ -1624,7 +1686,7 @@ export namespace CoreNavigationCommands { }); } - public runCoreEditorCommand(viewModel: IViewModel, args: any): void { + public runCoreEditorCommand(viewModel: IViewModel, args: Partial): void { viewModel.model.pushStackElement(); viewModel.setCursorStates( args.source, @@ -1638,7 +1700,9 @@ export namespace CoreNavigationCommands { } }); - export const RevealLine: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand { + export type RevealLineCommandOptions = RevealLine_.RawArguments & BaseCommandOptions; + + export const RevealLine: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand { constructor() { super({ id: 'revealLine', @@ -1647,8 +1711,8 @@ export namespace CoreNavigationCommands { }); } - public runCoreEditorCommand(viewModel: IViewModel, args: any): void { - const revealLineArg = args; + public runCoreEditorCommand(viewModel: IViewModel, args: Partial): void { + const revealLineArg = args; const lineNumberArg = revealLineArg.lineNumber || 0; let lineNumber = typeof lineNumberArg === 'number' ? (lineNumberArg + 1) : (parseInt(lineNumberArg) + 1); if (lineNumber < 1) { @@ -1699,7 +1763,7 @@ export namespace CoreNavigationCommands { document.execCommand('selectAll'); } - public runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void { + public runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, args: unknown): void { const viewModel = editor._getViewModel(); if (!viewModel) { // the editor has no view => has no cursors @@ -1707,7 +1771,7 @@ export namespace CoreNavigationCommands { } this.runCoreEditorCommand(viewModel, args); } - public runCoreEditorCommand(viewModel: IViewModel, args: any): void { + public runCoreEditorCommand(viewModel: IViewModel, args: unknown): void { viewModel.model.pushStackElement(); viewModel.setCursorStates( 'keyboard', @@ -1719,7 +1783,11 @@ export namespace CoreNavigationCommands { } }(); - export const SetSelection: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand { + export interface SetSelectionCommandOptions extends BaseCommandOptions { + selection: ISelection; + } + + export const SetSelection: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand { constructor() { super({ id: 'setSelection', @@ -1727,7 +1795,10 @@ export namespace CoreNavigationCommands { }); } - public runCoreEditorCommand(viewModel: IViewModel, args: any): void { + public runCoreEditorCommand(viewModel: IViewModel, args: Partial): void { + if (!args.selection) { + return; + } viewModel.model.pushStackElement(); viewModel.setCursorStates( args.source, @@ -1768,7 +1839,7 @@ function registerCommand(command: T): T { export namespace CoreEditingCommands { export abstract class CoreEditingCommand extends EditorCommand { - public runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void { + public runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, args: unknown): void { const viewModel = editor._getViewModel(); if (!viewModel) { // the editor has no view => has no cursors @@ -1777,7 +1848,7 @@ export namespace CoreEditingCommands { this.runCoreEditingCommand(editor, viewModel, args || {}); } - public abstract runCoreEditingCommand(editor: ICodeEditor, viewModel: IViewModel, args: any): void; + public abstract runCoreEditingCommand(editor: ICodeEditor, viewModel: IViewModel, args: unknown): void; } export const LineBreakInsert: EditorCommand = registerEditorCommand(new class extends CoreEditingCommand { @@ -1794,7 +1865,7 @@ export namespace CoreEditingCommands { }); } - public runCoreEditingCommand(editor: ICodeEditor, viewModel: IViewModel, args: any): void { + public runCoreEditingCommand(editor: ICodeEditor, viewModel: IViewModel, args: unknown): void { editor.pushUndoStop(); editor.executeCommands(this.id, TypeOperations.lineBreakInsert(viewModel.cursorConfig, viewModel.model, viewModel.getCursorStates().map(s => s.modelState.selection))); } @@ -1816,7 +1887,7 @@ export namespace CoreEditingCommands { }); } - public runCoreEditingCommand(editor: ICodeEditor, viewModel: IViewModel, args: any): void { + public runCoreEditingCommand(editor: ICodeEditor, viewModel: IViewModel, args: unknown): void { editor.pushUndoStop(); editor.executeCommands(this.id, TypeOperations.outdent(viewModel.cursorConfig, viewModel.model, viewModel.getCursorStates().map(s => s.modelState.selection))); editor.pushUndoStop(); @@ -1839,7 +1910,7 @@ export namespace CoreEditingCommands { }); } - public runCoreEditingCommand(editor: ICodeEditor, viewModel: IViewModel, args: any): void { + public runCoreEditingCommand(editor: ICodeEditor, viewModel: IViewModel, args: unknown): void { editor.pushUndoStop(); editor.executeCommands(this.id, TypeOperations.tab(viewModel.cursorConfig, viewModel.model, viewModel.getCursorStates().map(s => s.modelState.selection))); editor.pushUndoStop(); @@ -1861,7 +1932,7 @@ export namespace CoreEditingCommands { }); } - public runCoreEditingCommand(editor: ICodeEditor, viewModel: IViewModel, args: any): void { + public runCoreEditingCommand(editor: ICodeEditor, viewModel: IViewModel, args: unknown): void { const [shouldPushStackElementBefore, commands] = DeleteOperations.deleteLeft(viewModel.getPrevEditOperationType(), viewModel.cursorConfig, viewModel.model, viewModel.getCursorStates().map(s => s.modelState.selection), viewModel.getCursorAutoClosedCharacters()); if (shouldPushStackElementBefore) { editor.pushUndoStop(); @@ -1885,7 +1956,7 @@ export namespace CoreEditingCommands { }); } - public runCoreEditingCommand(editor: ICodeEditor, viewModel: IViewModel, args: any): void { + public runCoreEditingCommand(editor: ICodeEditor, viewModel: IViewModel, args: unknown): void { const [shouldPushStackElementBefore, commands] = DeleteOperations.deleteRight(viewModel.getPrevEditOperationType(), viewModel.cursorConfig, viewModel.model, viewModel.getCursorStates().map(s => s.modelState.selection)); if (shouldPushStackElementBefore) { editor.pushUndoStop(); @@ -1902,7 +1973,7 @@ export namespace CoreEditingCommands { public runDOMCommand(): void { document.execCommand('undo'); } - public runEditorCommand(accessor: ServicesAccessor | null, editor: ICodeEditor, args: any): void | Promise { + public runEditorCommand(accessor: ServicesAccessor | null, editor: ICodeEditor, args: unknown): void | Promise { if (!editor.hasModel() || editor.getOption(EditorOption.readOnly) === true) { return; } @@ -1917,7 +1988,7 @@ export namespace CoreEditingCommands { public runDOMCommand(): void { document.execCommand('redo'); } - public runEditorCommand(accessor: ServicesAccessor | null, editor: ICodeEditor, args: any): void | Promise { + public runEditorCommand(accessor: ServicesAccessor | null, editor: ICodeEditor, args: unknown): void | Promise { if (!editor.hasModel() || editor.getOption(EditorOption.readOnly) === true) { return; } @@ -1942,7 +2013,7 @@ class EditorHandlerCommand extends Command { this._handlerId = handlerId; } - public runCommand(accessor: ServicesAccessor, args: any): void { + public runCommand(accessor: ServicesAccessor, args: unknown): void { const editor = accessor.get(ICodeEditorService).getFocusedCodeEditor(); if (!editor) { return; diff --git a/src/vs/editor/common/cursor/cursorMoveCommands.ts b/src/vs/editor/common/cursor/cursorMoveCommands.ts index 992c8c6ffd4..4c51a670f85 100644 --- a/src/vs/editor/common/cursor/cursorMoveCommands.ts +++ b/src/vs/editor/common/cursor/cursorMoveCommands.ts @@ -173,7 +173,7 @@ export class CursorMoveCommands { )); } - public static line(viewModel: IViewModel, cursor: CursorState, inSelectionMode: boolean, _position: IPosition, _viewPosition: IPosition): PartialCursorState { + public static line(viewModel: IViewModel, cursor: CursorState, inSelectionMode: boolean, _position: IPosition, _viewPosition: IPosition | undefined): PartialCursorState { const position = viewModel.model.validatePosition(_position); const viewPosition = ( _viewPosition @@ -251,7 +251,7 @@ export class CursorMoveCommands { )); } - public static moveTo(viewModel: IViewModel, cursor: CursorState, inSelectionMode: boolean, _position: IPosition, _viewPosition: IPosition): PartialCursorState { + public static moveTo(viewModel: IViewModel, cursor: CursorState, inSelectionMode: boolean, _position: IPosition, _viewPosition: IPosition | undefined): PartialCursorState { const position = viewModel.model.validatePosition(_position); const viewPosition = ( _viewPosition @@ -680,7 +680,7 @@ export namespace CursorMove { value?: number; } - export function parse(args: RawArguments): ParsedArguments | null { + export function parse(args: Partial): ParsedArguments | null { if (!args.to) { // illegal arguments return null; From dfc8776b46579a578c120f4135217119d5560cc2 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Wed, 21 Sep 2022 09:42:57 +0200 Subject: [PATCH 4/5] First scroll and then update the selection when dragging (#40890) --- .../editor/browser/controller/mouseHandler.ts | 201 ++++++++++++++---- .../browser/controller/pointerHandler.ts | 4 +- src/vs/editor/browser/coreCommands.ts | 54 +++-- src/vs/editor/browser/view.ts | 3 + src/vs/editor/browser/view/viewController.ts | 74 +++---- .../browser/viewParts/lines/viewLines.ts | 13 +- 6 files changed, 240 insertions(+), 109 deletions(-) diff --git a/src/vs/editor/browser/controller/mouseHandler.ts b/src/vs/editor/browser/controller/mouseHandler.ts index f8960556738..089558e76c1 100644 --- a/src/vs/editor/browser/controller/mouseHandler.ts +++ b/src/vs/editor/browser/controller/mouseHandler.ts @@ -5,12 +5,11 @@ import * as dom from 'vs/base/browser/dom'; import { StandardWheelEvent, IMouseWheelEvent } from 'vs/base/browser/mouseEvent'; -import { TimeoutTimer } from 'vs/base/common/async'; import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; import * as platform from 'vs/base/common/platform'; import { HitTestContext, MouseTarget, MouseTargetFactory, PointerHandlerLastRenderData } from 'vs/editor/browser/controller/mouseTarget'; -import { IMouseTarget, IMouseTargetViewZoneData, MouseTargetType } from 'vs/editor/browser/editorBrowser'; -import { ClientCoordinates, EditorMouseEvent, EditorMouseEventFactory, GlobalEditorPointerMoveMonitor, createEditorPagePosition, createCoordinatesRelativeToEditor } from 'vs/editor/browser/editorDom'; +import { IMouseTarget, IMouseTargetOutsideEditor, IMouseTargetViewZoneData, MouseTargetType } from 'vs/editor/browser/editorBrowser'; +import { ClientCoordinates, EditorMouseEvent, EditorMouseEventFactory, GlobalEditorPointerMoveMonitor, createEditorPagePosition, createCoordinatesRelativeToEditor, PageCoordinates } from 'vs/editor/browser/editorDom'; import { ViewController } from 'vs/editor/browser/view/viewController'; import { EditorZoom } from 'vs/editor/common/config/editorZoom'; import { Position } from 'vs/editor/common/core/position'; @@ -20,6 +19,7 @@ import { ViewContext } from 'vs/editor/common/viewModel/viewContext'; import * as viewEvents from 'vs/editor/common/viewEvents'; import { ViewEventHandler } from 'vs/editor/common/viewEventHandler'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; +import { NavigationCommandRevealType } from 'vs/editor/browser/coreCommands'; export interface IPointerHandlerHelper { viewDomNode: HTMLElement; @@ -34,6 +34,11 @@ export interface IPointerHandlerHelper { */ getLastRenderData(): PointerHandlerLastRenderData; + /** + * Render right now + */ + renderNow(): void; + shouldSuppressMouseDownOnViewZone(viewZoneId: string): boolean; shouldSuppressMouseDownOnWidget(widgetId: string): boolean; @@ -69,6 +74,7 @@ export class MouseHandler extends ViewEventHandler { this._context, this.viewController, this.viewHelper, + this.mouseTargetFactory, (e, testEventTarget) => this._createMouseTarget(e, testEventTarget), (e) => this._getMouseColumn(e) )); @@ -177,10 +183,6 @@ export class MouseHandler extends ViewEventHandler { public override onFocusChanged(e: viewEvents.ViewFocusChangedEvent): boolean { return false; } - public override onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean { - this._mouseDownOperation.onScrollChanged(); - return false; - } // --- end event handlers public getTargetAtClientPoint(clientX: number, clientY: number): IMouseTarget | null { @@ -313,14 +315,11 @@ export class MouseHandler extends ViewEventHandler { class MouseDownOperation extends Disposable { - private readonly _context: ViewContext; - private readonly _viewController: ViewController; - private readonly _viewHelper: IPointerHandlerHelper; private readonly _createMouseTarget: (e: EditorMouseEvent, testEventTarget: boolean) => IMouseTarget; private readonly _getMouseColumn: (e: EditorMouseEvent) => number; private readonly _mouseMoveMonitor: GlobalEditorPointerMoveMonitor; - private readonly _onScrollTimeout: TimeoutTimer; + private readonly _topBottomDragScrolling: TopBottomDragScrolling; private readonly _mouseState: MouseDownState; private _currentSelection: Selection; @@ -328,21 +327,24 @@ class MouseDownOperation extends Disposable { private _lastMouseEvent: EditorMouseEvent | null; constructor( - context: ViewContext, - viewController: ViewController, - viewHelper: IPointerHandlerHelper, + private readonly _context: ViewContext, + private readonly _viewController: ViewController, + private readonly _viewHelper: IPointerHandlerHelper, + private readonly _mouseTargetFactory: MouseTargetFactory, createMouseTarget: (e: EditorMouseEvent, testEventTarget: boolean) => IMouseTarget, getMouseColumn: (e: EditorMouseEvent) => number ) { super(); - this._context = context; - this._viewController = viewController; - this._viewHelper = viewHelper; this._createMouseTarget = createMouseTarget; this._getMouseColumn = getMouseColumn; this._mouseMoveMonitor = this._register(new GlobalEditorPointerMoveMonitor(this._viewHelper.viewDomNode)); - this._onScrollTimeout = this._register(new TimeoutTimer()); + this._topBottomDragScrolling = this._register(new TopBottomDragScrolling( + this._context, + this._viewHelper, + this._mouseTargetFactory, + (position, inSelectionMode, revealType) => this._dispatchMouse(position, inSelectionMode, revealType) + )); this._mouseState = new MouseDownState(); this._currentSelection = new Selection(1, 1, 1, 1); @@ -374,7 +376,12 @@ class MouseDownOperation extends Disposable { target: position }); } else { - this._dispatchMouse(position, true); + if (position.type === MouseTargetType.OUTSIDE_EDITOR) { + this._topBottomDragScrolling.start(position, e); + } else { + this._topBottomDragScrolling.stop(); + this._dispatchMouse(position, true, NavigationCommandRevealType.Minimal); + } } } @@ -436,7 +443,7 @@ class MouseDownOperation extends Disposable { } this._mouseState.isDragAndDrop = false; - this._dispatchMouse(position, e.shiftKey); + this._dispatchMouse(position, e.shiftKey, NavigationCommandRevealType.Minimal); if (!this._isActive) { this._isActive = true; @@ -452,7 +459,7 @@ class MouseDownOperation extends Disposable { private _stop(): void { this._isActive = false; - this._onScrollTimeout.cancel(); + this._topBottomDragScrolling.stop(); } public onHeightChanged(): void { @@ -463,27 +470,6 @@ class MouseDownOperation extends Disposable { this._mouseMoveMonitor.stopMonitoring(); } - public onScrollChanged(): void { - if (!this._isActive) { - return; - } - this._onScrollTimeout.setIfNotSet(() => { - if (!this._lastMouseEvent) { - return; - } - const position = this._findMousePosition(this._lastMouseEvent, false); - if (!position) { - // Ignoring because position is unknown - return; - } - if (this._mouseState.isDragAndDrop) { - // Ignoring because users are dragging the text - return; - } - this._dispatchMouse(position, true); - }, 10); - } - public onCursorStateChanged(e: viewEvents.ViewCursorStateChangedEvent): void { this._currentSelection = e.selections[0]; } @@ -578,7 +564,7 @@ class MouseDownOperation extends Disposable { return null; } - private _dispatchMouse(position: IMouseTarget, inSelectionMode: boolean): void { + private _dispatchMouse(position: IMouseTarget, inSelectionMode: boolean, revealType: NavigationCommandRevealType): void { if (!position.position) { return; } @@ -586,6 +572,7 @@ class MouseDownOperation extends Disposable { position: position.position, mouseColumn: position.mouseColumn, startedOnLineNumbers: this._mouseState.startedOnLineNumbers, + revealType, inSelectionMode: inSelectionMode, mouseDownCount: this._mouseState.count, @@ -602,6 +589,134 @@ class MouseDownOperation extends Disposable { } } +class TopBottomDragScrolling extends Disposable { + + private _operation: TopBottomDragScrollingOperation | null; + + constructor( + private readonly _context: ViewContext, + private readonly _viewHelper: IPointerHandlerHelper, + private readonly _mouseTargetFactory: MouseTargetFactory, + private readonly _dispatchMouse: (position: IMouseTarget, inSelectionMode: boolean, revealType: NavigationCommandRevealType) => void, + ) { + super(); + this._operation = null; + } + + public override dispose(): void { + super.dispose(); + this.stop(); + } + + public start(position: IMouseTargetOutsideEditor, mouseEvent: EditorMouseEvent): void { + if (this._operation) { + this._operation.setPosition(position, mouseEvent); + } else { + this._operation = new TopBottomDragScrollingOperation(this._context, this._viewHelper, this._mouseTargetFactory, this._dispatchMouse, position, mouseEvent); + } + } + + public stop(): void { + if (this._operation) { + this._operation.dispose(); + this._operation = null; + } + } +} + +class TopBottomDragScrollingOperation extends Disposable { + + private _position: IMouseTargetOutsideEditor; + private _mouseEvent: EditorMouseEvent; + private _lastTime: number; + private _animationFrameDisposable: IDisposable; + + constructor( + private readonly _context: ViewContext, + private readonly _viewHelper: IPointerHandlerHelper, + private readonly _mouseTargetFactory: MouseTargetFactory, + private readonly _dispatchMouse: (position: IMouseTarget, inSelectionMode: boolean, revealType: NavigationCommandRevealType) => void, + position: IMouseTargetOutsideEditor, + mouseEvent: EditorMouseEvent + ) { + super(); + this._position = position; + this._mouseEvent = mouseEvent; + this._lastTime = Date.now(); + this._animationFrameDisposable = dom.scheduleAtNextAnimationFrame(() => this._execute()); + } + + public override dispose(): void { + this._animationFrameDisposable.dispose(); + } + + public setPosition(position: IMouseTargetOutsideEditor, mouseEvent: EditorMouseEvent): void { + this._position = position; + this._mouseEvent = mouseEvent; + } + + /** + * update internal state and return elapsed ms since last time + */ + private _tick(): number { + const now = Date.now(); + const elapsed = now - this._lastTime; + this._lastTime = now; + return elapsed; + } + + /** + * get the number of lines per second to auto-scroll + */ + private _getScrollSpeed(): number { + const lineHeight = this._context.configuration.options.get(EditorOption.lineHeight); + const viewportInLines = this._context.configuration.options.get(EditorOption.layoutInfo).height / lineHeight; + const outsideDistanceInLines = this._position.outsideDistance / lineHeight; + + if (outsideDistanceInLines <= 1.5) { + return Math.max(30, viewportInLines * (1 + outsideDistanceInLines)); + } + if (outsideDistanceInLines <= 3) { + return Math.max(60, viewportInLines * (2 + outsideDistanceInLines)); + } + return Math.max(200, viewportInLines * (7 + outsideDistanceInLines)); + } + + private _execute(): void { + const lineHeight = this._context.configuration.options.get(EditorOption.lineHeight); + const scrollSpeedInLines = this._getScrollSpeed(); + const elapsed = this._tick(); + const scrollInPixels = scrollSpeedInLines * (elapsed / 1000) * lineHeight; + const scrollValue = (this._position.outsidePosition === 'above' ? -scrollInPixels : scrollInPixels); + + this._context.viewModel.viewLayout.deltaScrollNow(0, scrollValue); + this._viewHelper.renderNow(); + + const viewportData = this._context.viewLayout.getLinesViewportData(); + const edgeLineNumber = (this._position.outsidePosition === 'above' ? viewportData.startLineNumber : viewportData.endLineNumber); + + // First, try to find a position that matches the horizontal position of the mouse + let mouseTarget: IMouseTarget; + { + const editorPos = createEditorPagePosition(this._viewHelper.viewDomNode); + const horizontalScrollbarHeight = this._context.configuration.options.get(EditorOption.layoutInfo).horizontalScrollbarHeight; + const pos = new PageCoordinates(this._mouseEvent.pos.x, editorPos.y + editorPos.height - horizontalScrollbarHeight - 0.1); + const relativePos = createCoordinatesRelativeToEditor(this._viewHelper.viewDomNode, editorPos, pos); + mouseTarget = this._mouseTargetFactory.createMouseTarget(this._viewHelper.getLastRenderData(), editorPos, pos, relativePos, null); + } + if (!mouseTarget.position || mouseTarget.position.lineNumber !== edgeLineNumber) { + if (this._position.outsidePosition === 'above') { + mouseTarget = MouseTarget.createOutsideEditor(this._position.mouseColumn, new Position(edgeLineNumber, 1), 'above', this._position.outsideDistance); + } else { + mouseTarget = MouseTarget.createOutsideEditor(this._position.mouseColumn, new Position(edgeLineNumber, this._context.viewModel.getLineMaxColumn(edgeLineNumber)), 'below', this._position.outsideDistance); + } + } + + this._dispatchMouse(mouseTarget, true, NavigationCommandRevealType.None); + this._animationFrameDisposable = dom.scheduleAtNextAnimationFrame(() => this._execute()); + } +} + class MouseDownState { private static readonly CLEAR_MOUSE_DOWN_COUNT_TIME = 400; // ms diff --git a/src/vs/editor/browser/controller/pointerHandler.ts b/src/vs/editor/browser/controller/pointerHandler.ts index 1fd1525a4c2..25155f1336d 100644 --- a/src/vs/editor/browser/controller/pointerHandler.ts +++ b/src/vs/editor/browser/controller/pointerHandler.ts @@ -14,6 +14,7 @@ import { ViewController } from 'vs/editor/browser/view/viewController'; import { ViewContext } from 'vs/editor/common/viewModel/viewContext'; import { BrowserFeatures } from 'vs/base/browser/canIUse'; import { TextAreaSyntethicEvents } from 'vs/editor/browser/controller/textAreaInput'; +import { NavigationCommandRevealType } from 'vs/editor/browser/coreCommands'; /** * Currently only tested on iOS 13/ iPadOS. @@ -66,6 +67,7 @@ export class PointerEventHandler extends MouseHandler { position: target.position, mouseColumn: target.position.column, startedOnLineNumbers: false, + revealType: NavigationCommandRevealType.Minimal, mouseDownCount: event.tapCount, inSelectionMode: false, altKey: false, @@ -120,7 +122,7 @@ class TouchHandler extends MouseHandler { event.initEvent(TextAreaSyntethicEvents.Tap, false, true); this.viewHelper.dispatchTextAreaEvent(event); - this.viewController.moveTo(target.position); + this.viewController.moveTo(target.position, NavigationCommandRevealType.Minimal); } } diff --git a/src/vs/editor/browser/coreCommands.ts b/src/vs/editor/browser/coreCommands.ts index de59a8b7f6e..6fa113c75ee 100644 --- a/src/vs/editor/browser/coreCommands.ts +++ b/src/vs/editor/browser/coreCommands.ts @@ -33,7 +33,7 @@ import { ISelection } from 'vs/editor/common/core/selection'; const CORE_WEIGHT = KeybindingWeight.EditorCore; export abstract class CoreEditorCommand extends EditorCommand { - public runEditorCommand(accessor: ServicesAccessor | null, editor: ICodeEditor, args?: T | null): void { + public runEditorCommand(accessor: ServicesAccessor | null, editor: ICodeEditor, args?: Partial | null): void { const viewModel = editor._getViewModel(); if (!viewModel) { // the editor has no view => has no cursors @@ -331,6 +331,21 @@ abstract class EditorOrNativeTextInputCommand { public abstract runEditorCommand(accessor: ServicesAccessor | null, editor: ICodeEditor, args: unknown): void | Promise; } +export const enum NavigationCommandRevealType { + /** + * Do regular revealing. + */ + Regular = 0, + /** + * Do only minimal revealing. + */ + Minimal = 1, + /** + * Do not reveal the position. + */ + None = 2 +} + export namespace CoreNavigationCommands { export interface BaseCommandOptions { @@ -340,16 +355,15 @@ export namespace CoreNavigationCommands { export interface MoveCommandOptions extends BaseCommandOptions { position: IPosition; viewPosition?: IPosition; + revealType: NavigationCommandRevealType; } class BaseMoveToCommand extends CoreEditorCommand { - private readonly _minimalReveal: boolean; private readonly _inSelectionMode: boolean; - constructor(opts: ICommandOptions & { minimalReveal: boolean; inSelectionMode: boolean }) { + constructor(opts: ICommandOptions & { inSelectionMode: boolean }) { super(opts); - this._minimalReveal = opts.minimalReveal; this._inSelectionMode = opts.inSelectionMode; } @@ -365,22 +379,20 @@ export namespace CoreNavigationCommands { CursorMoveCommands.moveTo(viewModel, viewModel.getPrimaryCursorState(), this._inSelectionMode, args.position, args.viewPosition) ] ); - if (cursorStateChanged) { - viewModel.revealPrimaryCursor(args.source, true, this._minimalReveal); + if (cursorStateChanged && args.revealType !== NavigationCommandRevealType.None) { + viewModel.revealPrimaryCursor(args.source, true, true); } } } export const MoveTo: CoreEditorCommand = registerEditorCommand(new BaseMoveToCommand({ id: '_moveTo', - minimalReveal: true, inSelectionMode: false, precondition: undefined })); export const MoveToSelect: CoreEditorCommand = registerEditorCommand(new BaseMoveToCommand({ id: '_moveToSelect', - minimalReveal: false, inSelectionMode: true, precondition: undefined })); @@ -415,8 +427,8 @@ export namespace CoreNavigationCommands { export interface ColumnSelectCommandOptions extends BaseCommandOptions { position: IPosition; viewPosition: IPosition; - doColumnSelect: boolean; mouseColumn: number; + doColumnSelect: boolean; } export const ColumnSelect: CoreEditorCommand = registerEditorCommand(new class extends ColumnSelectCommand { @@ -1501,11 +1513,7 @@ export namespace CoreNavigationCommands { } }); - export interface WordCommandOptions extends BaseCommandOptions { - position: IPosition; - } - - class WordCommand extends CoreEditorCommand { + class WordCommand extends CoreEditorCommand { private readonly _inSelectionMode: boolean; @@ -1514,7 +1522,7 @@ export namespace CoreNavigationCommands { this._inSelectionMode = opts.inSelectionMode; } - public runCoreEditorCommand(viewModel: IViewModel, args: Partial): void { + public runCoreEditorCommand(viewModel: IViewModel, args: Partial): void { if (!args.position) { return; } @@ -1526,23 +1534,25 @@ export namespace CoreNavigationCommands { CursorMoveCommands.word(viewModel, viewModel.getPrimaryCursorState(), this._inSelectionMode, args.position) ] ); - viewModel.revealPrimaryCursor(args.source, true); + if (args.revealType !== NavigationCommandRevealType.None) { + viewModel.revealPrimaryCursor(args.source, true, true); + } } } - export const WordSelect: CoreEditorCommand = registerEditorCommand(new WordCommand({ + export const WordSelect: CoreEditorCommand = registerEditorCommand(new WordCommand({ inSelectionMode: false, id: '_wordSelect', precondition: undefined })); - export const WordSelectDrag: CoreEditorCommand = registerEditorCommand(new WordCommand({ + export const WordSelectDrag: CoreEditorCommand = registerEditorCommand(new WordCommand({ inSelectionMode: true, id: '_wordSelectDrag', precondition: undefined })); - export const LastCursorWordSelect: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand { + export const LastCursorWordSelect: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand { constructor() { super({ id: 'lastCursorWordSelect', @@ -1550,7 +1560,7 @@ export namespace CoreNavigationCommands { }); } - public runCoreEditorCommand(viewModel: IViewModel, args: Partial): void { + public runCoreEditorCommand(viewModel: IViewModel, args: Partial): void { if (!args.position) { return; } @@ -1590,7 +1600,9 @@ export namespace CoreNavigationCommands { CursorMoveCommands.line(viewModel, viewModel.getPrimaryCursorState(), this._inSelectionMode, args.position, args.viewPosition) ] ); - viewModel.revealPrimaryCursor(args.source, false); + if (args.revealType !== NavigationCommandRevealType.None) { + viewModel.revealPrimaryCursor(args.source, false, true); + } } } diff --git a/src/vs/editor/browser/view.ts b/src/vs/editor/browser/view.ts index a05fae66338..6ee27a31b3f 100644 --- a/src/vs/editor/browser/view.ts +++ b/src/vs/editor/browser/view.ts @@ -245,6 +245,9 @@ export class View extends ViewEventHandler { const lastTextareaPosition = this._textAreaHandler.getLastRenderData(); return new PointerHandlerLastRenderData(lastViewCursorsRenderData, lastTextareaPosition); }, + renderNow: (): void => { + this.render(true, false); + }, shouldSuppressMouseDownOnViewZone: (viewZoneId: string) => { return this._viewZones.shouldSuppressMouseDownOnViewZone(viewZoneId); }, diff --git a/src/vs/editor/browser/view/viewController.ts b/src/vs/editor/browser/view/viewController.ts index 41d9b58a129..b6b8ebdd698 100644 --- a/src/vs/editor/browser/view/viewController.ts +++ b/src/vs/editor/browser/view/viewController.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; -import { CoreNavigationCommands } from 'vs/editor/browser/coreCommands'; +import { CoreNavigationCommands, NavigationCommandRevealType } from 'vs/editor/browser/coreCommands'; import { IEditorMouseEvent, IPartialEditorMouseEvent } from 'vs/editor/browser/editorBrowser'; import { ViewUserInputEvents } from 'vs/editor/browser/view/viewUserInputEvents'; import { Position } from 'vs/editor/common/core/position'; @@ -21,6 +21,7 @@ export interface IMouseDispatchData { * Desired mouse column (e.g. when position.column gets clamped to text length -- clicking after text on a line). */ mouseColumn: number; + revealType: NavigationCommandRevealType; startedOnLineNumbers: boolean; inSelectionMode: boolean; @@ -138,15 +139,15 @@ export class ViewController { // If the dragging started on the gutter, then have operations work on the entire line if (this._hasMulticursorModifier(data)) { if (data.inSelectionMode) { - this._lastCursorLineSelect(data.position); + this._lastCursorLineSelect(data.position, data.revealType); } else { this._createCursor(data.position, true); } } else { if (data.inSelectionMode) { - this._lineSelectDrag(data.position); + this._lineSelectDrag(data.position, data.revealType); } else { - this._lineSelect(data.position); + this._lineSelect(data.position, data.revealType); } } } else if (data.mouseDownCount >= 4) { @@ -154,26 +155,26 @@ export class ViewController { } else if (data.mouseDownCount === 3) { if (this._hasMulticursorModifier(data)) { if (data.inSelectionMode) { - this._lastCursorLineSelectDrag(data.position); + this._lastCursorLineSelectDrag(data.position, data.revealType); } else { - this._lastCursorLineSelect(data.position); + this._lastCursorLineSelect(data.position, data.revealType); } } else { if (data.inSelectionMode) { - this._lineSelectDrag(data.position); + this._lineSelectDrag(data.position, data.revealType); } else { - this._lineSelect(data.position); + this._lineSelect(data.position, data.revealType); } } } else if (data.mouseDownCount === 2) { if (!data.onInjectedText) { if (this._hasMulticursorModifier(data)) { - this._lastCursorWordSelect(data.position); + this._lastCursorWordSelect(data.position, data.revealType); } else { if (data.inSelectionMode) { - this._wordSelectDrag(data.position); + this._wordSelectDrag(data.position, data.revealType); } else { - this._wordSelect(data.position); + this._wordSelect(data.position, data.revealType); } } } @@ -185,7 +186,7 @@ export class ViewController { } else { // Do multi-cursor operations only when purely alt is pressed if (data.inSelectionMode) { - this._lastCursorMoveToSelect(data.position); + this._lastCursorMoveToSelect(data.position, data.revealType); } else { this._createCursor(data.position, false); } @@ -199,31 +200,32 @@ export class ViewController { if (columnSelection) { this._columnSelect(data.position, data.mouseColumn, true); } else { - this._moveToSelect(data.position); + this._moveToSelect(data.position, data.revealType); } } } else { - this.moveTo(data.position); + this.moveTo(data.position, data.revealType); } } } } - private _usualArgs(viewPosition: Position) { + private _usualArgs(viewPosition: Position, revealType: NavigationCommandRevealType): CoreNavigationCommands.MoveCommandOptions { viewPosition = this._validateViewColumn(viewPosition); return { source: 'mouse', position: this._convertViewToModelPosition(viewPosition), - viewPosition: viewPosition + viewPosition, + revealType }; } - public moveTo(viewPosition: Position): void { - CoreNavigationCommands.MoveTo.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition)); + public moveTo(viewPosition: Position, revealType: NavigationCommandRevealType): void { + CoreNavigationCommands.MoveTo.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition, revealType)); } - private _moveToSelect(viewPosition: Position): void { - CoreNavigationCommands.MoveToSelect.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition)); + private _moveToSelect(viewPosition: Position, revealType: NavigationCommandRevealType): void { + CoreNavigationCommands.MoveToSelect.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition, revealType)); } private _columnSelect(viewPosition: Position, mouseColumn: number, doColumnSelect: boolean): void { @@ -247,36 +249,36 @@ export class ViewController { }); } - private _lastCursorMoveToSelect(viewPosition: Position): void { - CoreNavigationCommands.LastCursorMoveToSelect.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition)); + private _lastCursorMoveToSelect(viewPosition: Position, revealType: NavigationCommandRevealType): void { + CoreNavigationCommands.LastCursorMoveToSelect.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition, revealType)); } - private _wordSelect(viewPosition: Position): void { - CoreNavigationCommands.WordSelect.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition)); + private _wordSelect(viewPosition: Position, revealType: NavigationCommandRevealType): void { + CoreNavigationCommands.WordSelect.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition, revealType)); } - private _wordSelectDrag(viewPosition: Position): void { - CoreNavigationCommands.WordSelectDrag.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition)); + private _wordSelectDrag(viewPosition: Position, revealType: NavigationCommandRevealType): void { + CoreNavigationCommands.WordSelectDrag.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition, revealType)); } - private _lastCursorWordSelect(viewPosition: Position): void { - CoreNavigationCommands.LastCursorWordSelect.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition)); + private _lastCursorWordSelect(viewPosition: Position, revealType: NavigationCommandRevealType): void { + CoreNavigationCommands.LastCursorWordSelect.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition, revealType)); } - private _lineSelect(viewPosition: Position): void { - CoreNavigationCommands.LineSelect.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition)); + private _lineSelect(viewPosition: Position, revealType: NavigationCommandRevealType): void { + CoreNavigationCommands.LineSelect.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition, revealType)); } - private _lineSelectDrag(viewPosition: Position): void { - CoreNavigationCommands.LineSelectDrag.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition)); + private _lineSelectDrag(viewPosition: Position, revealType: NavigationCommandRevealType): void { + CoreNavigationCommands.LineSelectDrag.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition, revealType)); } - private _lastCursorLineSelect(viewPosition: Position): void { - CoreNavigationCommands.LastCursorLineSelect.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition)); + private _lastCursorLineSelect(viewPosition: Position, revealType: NavigationCommandRevealType): void { + CoreNavigationCommands.LastCursorLineSelect.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition, revealType)); } - private _lastCursorLineSelectDrag(viewPosition: Position): void { - CoreNavigationCommands.LastCursorLineSelectDrag.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition)); + private _lastCursorLineSelectDrag(viewPosition: Position, revealType: NavigationCommandRevealType): void { + CoreNavigationCommands.LastCursorLineSelectDrag.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition, revealType)); } private _selectAll(): void { diff --git a/src/vs/editor/browser/viewParts/lines/viewLines.ts b/src/vs/editor/browser/viewParts/lines/viewLines.ts index 805395c190b..8ca24cfe42b 100644 --- a/src/vs/editor/browser/viewParts/lines/viewLines.ts +++ b/src/vs/editor/browser/viewParts/lines/viewLines.ts @@ -102,7 +102,6 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost, private _typicalHalfwidthCharacterWidth: number; private _isViewportWrapping: boolean; private _revealHorizontalRightPadding: number; - private _horizontalScrollbarHeight: number; private _cursorSurroundingLines: number; private _cursorSurroundingLinesStyle: 'default' | 'all'; private _canUseLayerHinting: boolean; @@ -131,13 +130,11 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost, const options = this._context.configuration.options; const fontInfo = options.get(EditorOption.fontInfo); const wrappingInfo = options.get(EditorOption.wrappingInfo); - const layoutInfo = options.get(EditorOption.layoutInfo); this._lineHeight = options.get(EditorOption.lineHeight); this._typicalHalfwidthCharacterWidth = fontInfo.typicalHalfwidthCharacterWidth; this._isViewportWrapping = wrappingInfo.isViewportWrapping; this._revealHorizontalRightPadding = options.get(EditorOption.revealHorizontalRightPadding); - this._horizontalScrollbarHeight = layoutInfo.horizontalScrollbarHeight; this._cursorSurroundingLines = options.get(EditorOption.cursorSurroundingLines); this._cursorSurroundingLinesStyle = options.get(EditorOption.cursorSurroundingLinesStyle); this._canUseLayerHinting = !options.get(EditorOption.disableLayerHinting); @@ -194,13 +191,11 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost, const options = this._context.configuration.options; const fontInfo = options.get(EditorOption.fontInfo); const wrappingInfo = options.get(EditorOption.wrappingInfo); - const layoutInfo = options.get(EditorOption.layoutInfo); this._lineHeight = options.get(EditorOption.lineHeight); this._typicalHalfwidthCharacterWidth = fontInfo.typicalHalfwidthCharacterWidth; this._isViewportWrapping = wrappingInfo.isViewportWrapping; this._revealHorizontalRightPadding = options.get(EditorOption.revealHorizontalRightPadding); - this._horizontalScrollbarHeight = layoutInfo.horizontalScrollbarHeight; this._cursorSurroundingLines = options.get(EditorOption.cursorSurroundingLines); this._cursorSurroundingLinesStyle = options.get(EditorOption.cursorSurroundingLinesStyle); this._canUseLayerHinting = !options.get(EditorOption.disableLayerHinting); @@ -697,9 +692,11 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost, paddingTop = this._lineHeight; } } - if (verticalType === viewEvents.VerticalRevealType.Simple || verticalType === viewEvents.VerticalRevealType.Bottom) { - // Reveal one line more when the last line would be covered by the scrollbar - arrow down case or revealing a line explicitly at bottom - paddingBottom += (minimalReveal ? this._horizontalScrollbarHeight : this._lineHeight); + if (!minimalReveal) { + if (verticalType === viewEvents.VerticalRevealType.Simple || verticalType === viewEvents.VerticalRevealType.Bottom) { + // Reveal one line more when the last line would be covered by the scrollbar - arrow down case or revealing a line explicitly at bottom + paddingBottom += this._lineHeight; + } } boxStartY -= paddingTop; From bc2fe74dae661af460a5a7bb9faf12a6e4f7522b Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 21 Sep 2022 13:34:45 +0200 Subject: [PATCH 5/5] tactical fix #161334 (#161389) --- src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts index 985972ee280..1417a565a30 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts @@ -835,7 +835,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo icon: Codicon.stopCircle, menu: { id: MenuId.ViewContainerTitle, - when: ContextKeyExpr.and(CONTEXT_SYNC_STATE.notEqualsTo(SyncStatus.Uninitialized), CONTEXT_SYNC_ENABLEMENT.toNegated(), CONTEXT_ACCOUNT_STATE.notEqualsTo(AccountStatus.Uninitialized), CONTEXT_TURNING_ON_STATE, ContextKeyExpr.equals('viewContainer', SYNC_VIEW_CONTAINER_ID)), + when: ContextKeyExpr.and(CONTEXT_TURNING_ON_STATE, ContextKeyExpr.equals('viewContainer', SYNC_VIEW_CONTAINER_ID)), group: 'navigation', order: 1 } @@ -1057,7 +1057,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo when }, { id: MenuId.ViewContainerTitle, - when: ContextKeyExpr.and(when, ContextKeyExpr.equals('viewContainer', SYNC_VIEW_CONTAINER_ID)), + when: ContextKeyExpr.and(CONTEXT_SYNC_ENABLEMENT, ContextKeyExpr.equals('viewContainer', SYNC_VIEW_CONTAINER_ID)), group: 'navigation', order: 2 }]