import type { Position } from "./buffer.js"; export type MarkTransform = { readonly start: Position; readonly end: Position; readonly insertedText: string; }; /** Named vi marks with deterministic same-line edit transforms. */ export class ViMarks { readonly #marks = new Map(); set(name: string, position: Position): void { if (!/^[a-z]$/.test(name)) throw new RangeError("Vi mark name must be a lowercase letter"); this.#marks.set(name, { ...position }); } get(name: string): Position | undefined { const position = this.#marks.get(name); return position === undefined ? undefined : { ...position }; } transform(edit: MarkTransform): void { if (edit.start.line !== edit.end.line || edit.insertedText.includes("\n")) return; const removedLength = edit.end.column - edit.start.column; const delta = edit.insertedText.length - removedLength; for (const [name, position] of this.#marks) { if ( position.line !== edit.start.line || position.column < edit.start.column ) continue; const column = position.column < edit.end.column ? edit.start.column : position.column + delta; this.#marks.set(name, { line: position.line, column }); } } }