Add cursor position conversions
This commit is contained in:
parent
a2c51a9d5d
commit
5deb10ab8b
4 changed files with 176 additions and 0 deletions
|
|
@ -0,0 +1,43 @@
|
|||
import { lineAndColumnToPosition } from "./line-and-column-to-position";
|
||||
|
||||
describe("lineAndColumnToPosition", () => {
|
||||
it("should return the correct position for the first line", () => {
|
||||
const text = "Hello\nWorld";
|
||||
const position = lineAndColumnToPosition(text, 0, 3);
|
||||
expect(position).toBe(3);
|
||||
});
|
||||
|
||||
it("should return the correct position for the second line", () => {
|
||||
const text = "Hello\nWorld";
|
||||
const position = lineAndColumnToPosition(text, 1, 2);
|
||||
expect(position).toBe(8);
|
||||
});
|
||||
|
||||
it("should return the correct position for an empty string", () => {
|
||||
const text = "";
|
||||
const position = lineAndColumnToPosition(text, 0, 0);
|
||||
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("should handle multi-line strings with varying lengths", () => {
|
||||
const text = "Line1\nLongerLine2\nShort3";
|
||||
const position = lineAndColumnToPosition(text, 2, 4);
|
||||
expect(position).toBe(22);
|
||||
});
|
||||
|
||||
it("should throw an error if the line number is out of range", () => {
|
||||
const text = "Line1\nLine2";
|
||||
expect(() => lineAndColumnToPosition(text, 3, 0)).toThrow();
|
||||
});
|
||||
|
||||
it("should throw an error if the column number is out of range", () => {
|
||||
const text = "Line1\nLine2";
|
||||
expect(() => lineAndColumnToPosition(text, 1, 10)).toThrow();
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
/**
|
||||
* Converts line and column coordinates to an absolute character position in a text string.
|
||||
*
|
||||
* @param line - The zero-based line number
|
||||
* @param column - The zero-based column number
|
||||
* @param text - The text string to calculate position in
|
||||
* @returns The absolute character position (zero-based index) in the text string
|
||||
* @throws Error if line number is out of range
|
||||
* @throws Error if column number is out of range
|
||||
*/
|
||||
export function lineAndColumnToPosition(
|
||||
text: string,
|
||||
line: number,
|
||||
column: number
|
||||
): number {
|
||||
const lines = text.split("\n");
|
||||
|
||||
if (line >= lines.length) {
|
||||
throw new Error(`Line number ${line} is out of range.`);
|
||||
}
|
||||
|
||||
if (column > lines[line].length) {
|
||||
throw new Error(`Column number ${column} is out of range.`);
|
||||
}
|
||||
|
||||
let position = 0;
|
||||
for (let i = 0; i < line; i++) {
|
||||
position += lines[i].length + 1;
|
||||
}
|
||||
|
||||
position += column;
|
||||
|
||||
return position;
|
||||
}
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
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";
|
||||
expect(positionToLineAndColumn(text, 0)).toEqual({
|
||||
line: 0,
|
||||
column: 1
|
||||
});
|
||||
expect(positionToLineAndColumn(text, 10)).toEqual({
|
||||
line: 0,
|
||||
column: 11
|
||||
});
|
||||
expect(positionToLineAndColumn(text, 15)).toEqual({
|
||||
line: 1,
|
||||
column: 5
|
||||
});
|
||||
expect(positionToLineAndColumn(text, 26)).toEqual({
|
||||
line: 2,
|
||||
column: 4
|
||||
});
|
||||
});
|
||||
|
||||
test("handles positions at line breaks", () => {
|
||||
const text = "Line\nBreak";
|
||||
expect(positionToLineAndColumn(text, 4)).toEqual({
|
||||
line: 0,
|
||||
column: 5
|
||||
});
|
||||
expect(positionToLineAndColumn(text, 5)).toEqual({
|
||||
line: 1,
|
||||
column: 1
|
||||
});
|
||||
});
|
||||
|
||||
test("handles empty input", () => {
|
||||
expect(positionToLineAndColumn("", 0)).toEqual({ line: 0, column: 1 });
|
||||
});
|
||||
|
||||
test("handles positions at the end of text", () => {
|
||||
const text = "End";
|
||||
expect(positionToLineAndColumn(text, 3)).toEqual({
|
||||
line: 0,
|
||||
column: 4
|
||||
});
|
||||
});
|
||||
|
||||
test("throws error for position out of range", () => {
|
||||
const text = "Short text";
|
||||
expect(() => positionToLineAndColumn(text, 15)).toThrow();
|
||||
expect(() => positionToLineAndColumn(text, -1)).toThrow();
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
/**
|
||||
* Converts a character position in text to line and column numbers.
|
||||
*
|
||||
* @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)
|
||||
* @throws Will throw an error if the position is negative or exceeds the text length
|
||||
*/
|
||||
export function positionToLineAndColumn(
|
||||
text: string,
|
||||
position: number
|
||||
): { line: number; column: number } {
|
||||
if (position < 0) {
|
||||
throw new Error("Position cannot be negative");
|
||||
}
|
||||
|
||||
if (position > text.length) {
|
||||
throw new Error(
|
||||
`Position ${position} exceeds text length ${text.length}`
|
||||
);
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
return { line, column };
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue