Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Commit

Permalink
Fix caret jump when backspacing into empty line at beginning of editor
Browse files Browse the repository at this point in the history
  • Loading branch information
Johennes committed Jun 22, 2023
1 parent d935da2 commit 2117a0f
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 4 deletions.
16 changes: 12 additions & 4 deletions src/editor/caret.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,10 +104,10 @@ export function getLineAndNodePosition(
} {
const { parts } = model;
const partIndex = caretPosition.index;
const lineResult = findNodeInLineForPart(parts, partIndex);
let { offset } = caretPosition;
const lineResult = findNodeInLineForPart(parts, partIndex, offset);
const { lineIndex } = lineResult;
let { nodeIndex } = lineResult;
let { offset } = caretPosition;
// we're at an empty line between a newline part
// and another newline part or end/start of parts.
// set offset to 0 so it gets set to the <br> inside the line container
Expand All @@ -120,7 +120,11 @@ export function getLineAndNodePosition(
return { lineIndex, nodeIndex, offset };
}

function findNodeInLineForPart(parts: Part[], partIndex: number): { lineIndex: number; nodeIndex: number } {
function findNodeInLineForPart(
parts: Part[],
partIndex: number,
offset: number,
): { lineIndex: number; nodeIndex: number } {
let lineIndex = 0;
let nodeIndex = -1;

Expand All @@ -130,6 +134,10 @@ function findNodeInLineForPart(parts: Part[], partIndex: number): { lineIndex: n
for (let i = 0; i <= partIndex; ++i) {
const part = parts[i];
if (part.type === Type.Newline) {
// don't jump over the linebreak if the offset is before it
if (i == partIndex && offset === 0) {
continue;
}
lineIndex += 1;
nodeIndex = -1;
prevPart = undefined;
Expand All @@ -140,7 +148,7 @@ function findNodeInLineForPart(parts: Part[], partIndex: number): { lineIndex: n
}
// only jump over caret node if we're not at our destination node already,
// as we'll assume in moveOutOfUnselectablePart that nodeIndex
// refers to the node corresponding to the part,
// refers to the node corresponding to the part,
// and not an adjacent caret node
if (i < partIndex) {
const nextPart = parts[i + 1];
Expand Down
16 changes: 16 additions & 0 deletions test/editor/caret-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,14 @@ describe("editor/caret: DOM position for caret", function () {
});
});
describe("handling line breaks", function () {
it("at start of first line which is empty", function () {
const pc = createPartCreator();
const model = new EditorModel([pc.newline(), pc.plain("hello world")], pc);
const { offset, lineIndex, nodeIndex } = getLineAndNodePosition(model, { index: 0, offset: 0 });
expect(lineIndex).toBe(0);
expect(nodeIndex).toBe(-1);
expect(offset).toBe(0);
});
it("at end of last line", function () {
const pc = createPartCreator();
const model = new EditorModel([pc.plain("hello"), pc.newline(), pc.plain("world")], pc);
Expand All @@ -62,6 +70,14 @@ describe("editor/caret: DOM position for caret", function () {
expect(nodeIndex).toBe(0);
expect(offset).toBe(0);
});
it("before empty line", function () {
const pc = createPartCreator();
const model = new EditorModel([pc.plain("hello"), pc.newline(), pc.newline(), pc.plain("world")], pc);
const { offset, lineIndex, nodeIndex } = getLineAndNodePosition(model, { index: 0, offset: 5 });
expect(lineIndex).toBe(0);
expect(nodeIndex).toBe(0);
expect(offset).toBe(5);
});
it("in empty line", function () {
const pc = createPartCreator();
const model = new EditorModel([pc.plain("hello"), pc.newline(), pc.newline(), pc.plain("world")], pc);
Expand Down

0 comments on commit 2117a0f

Please sign in to comment.