Skip to content

Commit 9d73778

Browse files
committed
Fix cursor position after undoing/redoing certain actions
In particular, undoing a Visual/VisualBlock operator should now put the cursor in the right place. Refs #6681
1 parent 9091da0 commit 9d73778

File tree

4 files changed

+30
-15
lines changed

4 files changed

+30
-15
lines changed

src/actions/commands/actions.ts

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1523,7 +1523,7 @@ export class CommandInsertAtLastChange extends BaseCommand {
15231523
keys = ['g', 'i'];
15241524

15251525
public async exec(position: Position, vimState: VimState): Promise<void> {
1526-
vimState.cursorStopPosition =
1526+
vimState.cursorStopPosition = vimState.cursorStartPosition =
15271527
vimState.historyTracker.getLastChangeEndPosition() ?? new Position(0, 0);
15281528

15291529
await vimState.setCurrentMode(Mode.Insert);
@@ -1537,10 +1537,8 @@ export class CommandInsertAtFirstCharacter extends BaseCommand {
15371537

15381538
public async exec(position: Position, vimState: VimState): Promise<void> {
15391539
await vimState.setCurrentMode(Mode.Insert);
1540-
vimState.cursorStopPosition = TextEditor.getFirstNonWhitespaceCharOnLine(
1541-
vimState.document,
1542-
position.line
1543-
);
1540+
vimState.cursorStopPosition = vimState.cursorStartPosition =
1541+
TextEditor.getFirstNonWhitespaceCharOnLine(vimState.document, position.line);
15441542
}
15451543
}
15461544

@@ -1552,7 +1550,7 @@ export class CommandInsertAtLineBegin extends BaseCommand {
15521550

15531551
public async exec(position: Position, vimState: VimState): Promise<void> {
15541552
await vimState.setCurrentMode(Mode.Insert);
1555-
vimState.cursorStopPosition = position.getLineBegin();
1553+
vimState.cursorStopPosition = vimState.cursorStartPosition = position.getLineBegin();
15561554
}
15571555
}
15581556

@@ -1563,7 +1561,7 @@ export class CommandInsertAfterCursor extends BaseCommand {
15631561

15641562
public async exec(position: Position, vimState: VimState): Promise<void> {
15651563
await vimState.setCurrentMode(Mode.Insert);
1566-
vimState.cursorStopPosition = position.getRight();
1564+
vimState.cursorStopPosition = vimState.cursorStartPosition = position.getRight();
15671565
}
15681566

15691567
public doesActionApply(vimState: VimState, keysPressed: string[]): boolean {
@@ -1583,7 +1581,7 @@ export class CommandInsertAtLineEnd extends BaseCommand {
15831581

15841582
public async exec(position: Position, vimState: VimState): Promise<void> {
15851583
await vimState.setCurrentMode(Mode.Insert);
1586-
vimState.cursorStopPosition = position.getLineEnd();
1584+
vimState.cursorStopPosition = vimState.cursorStartPosition = position.getLineEnd();
15871585
}
15881586
}
15891587

src/history/historyTracker.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { globalState } from '../state/globalState';
2121
import { Mode } from '../mode/mode';
2222
import { ErrorCode, VimError } from '../error';
2323
import { Logger } from '../util/logger';
24+
import { earlierOf } from '../common/motion/position';
2425

2526
const diffEngine = new DiffMatchPatch.diff_match_patch();
2627
diffEngine.Diff_Timeout = 1; // 1 second
@@ -383,7 +384,7 @@ export class HistoryTracker {
383384
public lastContentChanges: vscode.TextDocumentContentChangeEvent[];
384385
public currentContentChanges: vscode.TextDocumentContentChangeEvent[];
385386

386-
public nextStepStartPosition: Position | undefined;
387+
private nextStepStartPosition: Position | undefined;
387388

388389
private readonly undoStack: UndoStack;
389390

@@ -614,12 +615,16 @@ export class HistoryTracker {
614615
*
615616
* Determines what changed by diffing the document against what it used to look like.
616617
*/
617-
public addChange(cursorPosition = [new Position(0, 0)]): void {
618+
public addChange(): void {
618619
if (this.getDocumentVersion() === this.previousDocumentState.versionNumber) {
619620
return;
620621
}
621622

622-
this.nextStepStartPosition ??= cursorPosition[0];
623+
if (this.nextStepStartPosition === undefined) {
624+
const cursor = this.vimState.cursorsInitialState[0];
625+
this.nextStepStartPosition = earlierOf(cursor.start, cursor.stop);
626+
logger.debug(`Set nextStepStartPosition to ${this.nextStepStartPosition}`);
627+
}
623628

624629
if (this.vimState.currentMode === Mode.Insert || this.vimState.currentMode === Mode.Replace) {
625630
// We can ignore changes while we're in insert/replace mode, since we can't interact with them (via undo, etc.) until we're back to normal mode

src/mode/modeHandler.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -563,7 +563,7 @@ export class ModeHandler implements vscode.Disposable, IModeHandler {
563563
}
564564

565565
// Catch any text change not triggered by us (example: tab completion).
566-
this.vimState.historyTracker.addChange(this.vimState.cursorsInitialState.map((c) => c.stop));
566+
this.vimState.historyTracker.addChange();
567567

568568
this.vimState.keyHistory.push(key);
569569

@@ -842,9 +842,7 @@ export class ModeHandler implements vscode.Disposable, IModeHandler {
842842
this.vimState.alteredHistory = false;
843843
this.vimState.historyTracker.ignoreChange();
844844
} else {
845-
this.vimState.historyTracker.addChange(
846-
this.vimState.cursorsInitialState.map((c) => c.stop)
847-
);
845+
this.vimState.historyTracker.addChange();
848846
}
849847
}
850848

test/mode/normalModeTests/undo.test.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,20 @@ suite('Undo', () => {
8585
keysPressed: 'dwdw2u',
8686
end: ['one |two three four five'],
8787
});
88+
89+
newTest({
90+
title: 'Undo Visual delete',
91+
start: ['one |two three four five'],
92+
keysPressed: 'vww' + 'd' + 'u',
93+
end: ['one |two three four five'],
94+
});
95+
96+
newTest({
97+
title: 'Undo VisualBlock delete',
98+
start: ['one two', 'th|ree four', 'five six', 'seven eight'],
99+
keysPressed: '<C-v>jll' + 'd' + 'u',
100+
end: ['one two', 'th|ree four', 'five six', 'seven eight'],
101+
});
88102
});
89103

90104
suite('U', () => {

0 commit comments

Comments
 (0)