scroll/src/common/document.ts

92 lines
1.7 KiB
JavaScript

import { chars } from './utils.ts';
import Row from './row.ts';
import { getRuntime } from './runtime.ts';
import { Position, SCROLL_TAB_SIZE } from './mod.ts';
export class Document {
#filename: string | null;
#rows: Row[];
dirty: boolean;
private constructor() {
this.#rows = [];
this.#filename = null;
this.dirty = false;
}
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<Document> {
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));
this.#filename = filename;
this.dirty = false;
return this;
}
public async save() {
if (this.#filename === null) {
return;
}
const { file } = await getRuntime();
await file.saveFile(this.#filename, this.rowsToString());
this.dirty = false;
}
public insert(at: Position, c: string): void {
if (at.y === this.numRows) {
this.appendRow(c);
} else {
this.#rows[at.y].insertChar(at.x, c);
this.updateRow(this.#rows[at.y]);
}
this.dirty = true;
}
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]);
this.dirty = true;
}
private updateRow(r: Row): void {
r.render = chars(r.toString().replace('\t', ' '.repeat(SCROLL_TAB_SIZE)));
}
private rowsToString(): string {
return this.#rows.map((r) => r.toString()).join('\n');
}
}
export default Document;