import { chars } from './utils.ts'; import { getRuntime } from './runtime.ts'; import { TAB_SIZE } from './mod.ts'; export class Row { chars: string[] = []; render: string[] = []; constructor(s: string = '') { this.chars = chars(s); this.render = []; } public get size(): number { return this.chars.length; } public get rsize(): number { return this.render.length; } public rstring(offset: number = 0): string { return this.render.slice(offset).join(''); } public cxToRx(cx: number): number { let rx = 0; let j = 0; for (; j < cx; j++) { if (this.chars[j] === '\t') { rx += (TAB_SIZE - 1) - (rx % TAB_SIZE); } rx++; } return rx; } public toString(): string { return this.chars.join(''); } } export class Document { #rows: Row[]; private constructor() { this.#rows = []; } get numRows(): number { return this.#rows.length; } public static empty(): Document { return new Document(); } public isEmpty(): boolean { return this.#rows.length === 0; } public async open(filename: string): Promise { const { file } = await getRuntime(); // Clear any existing rows if (!this.isEmpty()) { this.#rows = []; } const rawFile = await file.openFile(filename); rawFile.split(/\r?\n/) .forEach((row) => this.appendRow(row)); return this; } public row(i: number): Row | null { return this.#rows[i] ?? null; } public appendRow(s: string): void { const at = this.numRows; this.#rows[at] = new Row(s); this.updateRow(this.#rows[at]); } private updateRow(r: Row): void { r.render = chars(r.toString().replace('\t', ' '.repeat(TAB_SIZE))); } } export default Document;