Skip to content

Commit

Permalink
Fix movePrimaryCursorIntoVisibleRange
Browse files Browse the repository at this point in the history
  • Loading branch information
whitphx committed Dec 11, 2024
1 parent 254888f commit f5da56e
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 3 deletions.
17 changes: 16 additions & 1 deletion src/commands/move.ts
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,22 @@ export function movePrimaryCursorIntoVisibleRange(
let newPrimaryActive: vscode.Position;
if (primaryActive.isBefore(visibleRange.start)) {
newPrimaryActive = visibleRange.start.with(undefined, 0);
} else if (primaryActive.isAfter(visibleRange.end)) {
} else if (
// This method is called in the `onDidChangeTextEditorVisibleRanges` callback,
// and it is called when the user edits the document maybe because the edit moves the cursor.
// When executing the `deleteLeft` command for example, the document is shortened by 1 character
// and the cursor is moved to 1 character left, which is correct. However, in this case,
// the `onDidChangeTextEditorVisibleRanges` is called before `textEditor.selection` is updated,
// so we can't compare `visibleRange` with `editor.selection.active` directly in this method,
// which causes the issue like https://github.com/whitphx/vscode-emacs-mcx/issues/2113.
// * To solve the issue https://github.com/whitphx/vscode-emacs-mcx/issues/2113, we compare the lines instead of the positions.
// * Also, we compare the primaryActive.line with visibleRange.end.line + 1
// because, for example, when the cursor is at [lastLine, 0] and the `deleteLeft` command is executed,
// `visibleRange.end.line` becomes `lastLine - 1` but the cursor position is still [lastLine, 0] when this method is called form the callback due to the problem stated above,
// in which case the cursor is considered out of the visible range, which is incorrect.
primaryActive.line >
visibleRange.end.line + 1
) {
newPrimaryActive = visibleRange.end.with(undefined, 0);
} else {
return;
Expand Down
22 changes: 20 additions & 2 deletions src/test/suite/keep-cursor-range.test.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import assert from "assert";
import * as vscode from "vscode";
import { EmacsEmulator } from "../../emulator";
import { cleanUpWorkspace, setupWorkspace, setEmptyCursors } from "./utils";
import { cleanUpWorkspace, setupWorkspace, setEmptyCursors, assertCursorsEqual, delay } from "./utils";
import { Configuration } from "../../configuration/configuration";

suite("onDidChangeTextEditorVisibleRanges event listener with strictEmacsMove", () => {
let activeTextEditor: vscode.TextEditor;
let emulator: EmacsEmulator;

setup(async () => {
const initialText = "x\n".repeat(1000);
const initialText = "xxxx\n".repeat(1000).slice(0, -1); // Delete the last newline
activeTextEditor = await setupWorkspace(initialText);
emulator = new EmacsEmulator(activeTextEditor); // `EmacsEmulator`'s constructor registers the event listener
});
Expand Down Expand Up @@ -47,4 +47,22 @@ suite("onDidChangeTextEditorVisibleRanges event listener with strictEmacsMove",

Configuration.reload();
});

test("backspace works correctly keeping the cursor at the right position, when strictEmacsMove = true and the cursor is in the last line", async () => {
Configuration.instance.strictEmacsMove = true;

const lastLine = activeTextEditor.document.lineCount - 1;
const lastChar = activeTextEditor.document.lineAt(lastLine).text.length;

setEmptyCursors(activeTextEditor, [lastLine, lastChar]);
activeTextEditor.revealRange(new vscode.Range(lastLine, lastChar, lastLine, lastChar));

await vscode.commands.executeCommand("deleteLeft");

await delay(10); // Wait for the event listeners are called after the edit.

assertCursorsEqual(activeTextEditor, [lastLine, lastChar - 1]);

Configuration.reload();
});
});

0 comments on commit f5da56e

Please sign in to comment.