From 5328e3b0f624d0a73002d33101ec5ee5e4fab361 Mon Sep 17 00:00:00 2001 From: Andras Schmelczer Date: Thu, 3 Apr 2025 21:44:45 +0100 Subject: [PATCH] Fix cursor movement on Windows --- .../utils/line-and-column-to-position.test.ts | 7 ++- .../src/utils/line-and-column-to-position.ts | 2 +- .../utils/position-to-line-and-column.test.ts | 54 ++++++++----------- .../src/utils/position-to-line-and-column.ts | 7 +-- 4 files changed, 31 insertions(+), 39 deletions(-) diff --git a/frontend/obsidian-plugin/src/utils/line-and-column-to-position.test.ts b/frontend/obsidian-plugin/src/utils/line-and-column-to-position.test.ts index b98f66e5..9c02fbb5 100644 --- a/frontend/obsidian-plugin/src/utils/line-and-column-to-position.test.ts +++ b/frontend/obsidian-plugin/src/utils/line-and-column-to-position.test.ts @@ -19,10 +19,9 @@ describe("lineAndColumnToPosition", () => { expect(position).toBe(0); }); - it("should handle a single-line string correctly", () => { - const text = "SingleLine"; - const position = lineAndColumnToPosition(text, 0, 5); - expect(position).toBe(5); + it("with carrige return", () => { + expect(lineAndColumnToPosition("a\nb", 1, 1)).toBe(3); + expect(lineAndColumnToPosition("a\r\nb", 1, 1)).toBe(3); }); it("should handle multi-line strings with varying lengths", () => { diff --git a/frontend/obsidian-plugin/src/utils/line-and-column-to-position.ts b/frontend/obsidian-plugin/src/utils/line-and-column-to-position.ts index 0bc114c7..670d8cac 100644 --- a/frontend/obsidian-plugin/src/utils/line-and-column-to-position.ts +++ b/frontend/obsidian-plugin/src/utils/line-and-column-to-position.ts @@ -13,7 +13,7 @@ export function lineAndColumnToPosition( line: number, column: number ): number { - const lines = text.split("\n"); + const lines = text.replace("\r", "").split("\n"); if (line >= lines.length) { throw new Error(`Line number ${line} is out of range.`); diff --git a/frontend/obsidian-plugin/src/utils/position-to-line-and-column.test.ts b/frontend/obsidian-plugin/src/utils/position-to-line-and-column.test.ts index e5d3bac5..d5533778 100644 --- a/frontend/obsidian-plugin/src/utils/position-to-line-and-column.test.ts +++ b/frontend/obsidian-plugin/src/utils/position-to-line-and-column.test.ts @@ -1,63 +1,55 @@ import { positionToLineAndColumn } from "./position-to-line-and-column"; describe("positionToLineAndColumn", () => { - test("converts position to line and column in a single line text", () => { - const text = "Hello, world!"; - expect(positionToLineAndColumn(text, 0)).toEqual({ - line: 0, - column: 1 - }); - expect(positionToLineAndColumn(text, 7)).toEqual({ - line: 0, - column: 8 - }); - expect(positionToLineAndColumn(text, 12)).toEqual({ - line: 0, - column: 13 - }); - }); - test("converts position to line and column in multi-line text", () => { - const text = "First line\nSecond line\nThird line"; + const text = "ab\ncd\n"; expect(positionToLineAndColumn(text, 0)).toEqual({ + line: 0, + column: 0 + }); + expect(positionToLineAndColumn(text, 1)).toEqual({ line: 0, column: 1 }); - expect(positionToLineAndColumn(text, 10)).toEqual({ + expect(positionToLineAndColumn(text, 2)).toEqual({ line: 0, - column: 11 + column: 2 }); - expect(positionToLineAndColumn(text, 15)).toEqual({ + expect(positionToLineAndColumn(text, 3)).toEqual({ line: 1, - column: 5 + column: 0 }); - expect(positionToLineAndColumn(text, 26)).toEqual({ + expect(positionToLineAndColumn(text, 4)).toEqual({ + line: 1, + column: 1 + }); + expect(positionToLineAndColumn(text, 6)).toEqual({ line: 2, - column: 4 + column: 0 }); }); - test("handles positions at line breaks", () => { - const text = "Line\nBreak"; - expect(positionToLineAndColumn(text, 4)).toEqual({ - line: 0, - column: 5 + test("with carrige returns", () => { + expect(positionToLineAndColumn("a\nb", 3)).toEqual({ + line: 1, + column: 1 }); - expect(positionToLineAndColumn(text, 5)).toEqual({ + + expect(positionToLineAndColumn("a\r\nb", 3)).toEqual({ line: 1, column: 1 }); }); test("handles empty input", () => { - expect(positionToLineAndColumn("", 0)).toEqual({ line: 0, column: 1 }); + expect(positionToLineAndColumn("", 0)).toEqual({ line: 0, column: 0 }); }); test("handles positions at the end of text", () => { const text = "End"; expect(positionToLineAndColumn(text, 3)).toEqual({ line: 0, - column: 4 + column: 3 }); }); diff --git a/frontend/obsidian-plugin/src/utils/position-to-line-and-column.ts b/frontend/obsidian-plugin/src/utils/position-to-line-and-column.ts index a9c81881..3c35fb6e 100644 --- a/frontend/obsidian-plugin/src/utils/position-to-line-and-column.ts +++ b/frontend/obsidian-plugin/src/utils/position-to-line-and-column.ts @@ -3,7 +3,7 @@ * * @param text The text content to analyze * @param position The character position to convert - * @returns An object containing line and column numbers (0-based index for line, 1-based index for column) + * @returns An object containing line and column numbers * @throws Will throw an error if the position is negative or exceeds the text length */ export function positionToLineAndColumn( @@ -20,11 +20,12 @@ export function positionToLineAndColumn( ); } + text = text.replace("\r", ""); const textUpToPosition = text.substring(0, position); const lines = textUpToPosition.split("\n"); - const line = lines.length - 1; // 0-based index - const column = lines[lines.length - 1].length + 1; // 1-based index + const line = lines.length - 1; + const column = lines[lines.length - 1].length; return { line, column }; }