1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
|
use memio;
use io;
use strings;
// A Hare source document together with a set of proposed edits.
export type document = struct {
engine: const *engine,
path: str,
file: io::file,
buffer: []u8,
edits: []edit,
adjust: io::off,
};
// Initializes a [[document]] from a context which has been [[exec]]uted. Takes
// ownership of the context's path, edit, and file fields, as well as the byte
// buffer from its [[memio::stream]].
fn document_init(ctx: *context) document = {
let offs = io::tell(ctx.buffer)!;
defer io::seek(ctx.buffer, offs, io::whence::SET)!;
io::seek(ctx.buffer, 0, io::whence::END)!;
let buffer = memio::buffer(ctx.buffer);
edits_sort(ctx.edits);
return document {
engine = ctx.engine,
path = ctx.path,
file = ctx.file,
buffer = buffer,
edits = ctx.edits,
adjust = 0,
};
};
// Initializes a [[document]] which is a copy of the original file from
// [[exec]].
fn document_clone(ctx: *context) document = {
let offs = io::tell(ctx.buffer)!;
defer io::seek(ctx.buffer, offs, io::whence::SET)!;
io::seek(ctx.buffer, 0, io::whence::END)!;
let buffer = memio::buffer(ctx.buffer);
return document {
engine = ctx.engine,
path = ctx.path,
file = ctx.file,
buffer = alloc(buffer...)!,
edits = [],
adjust = 0,
};
};
// Frees resources associated with a [[document]] and closes the file handle.
export fn close(doc: *document) void = {
io::close(doc.file)!;
finish(doc);
};
// Frees resources associated with a [[document]] (without closing its file
// handle).
fn finish(doc: *document) void = {
for (let edit &.. doc.edits) {
edit_finish(edit);
};
free(doc.edits);
};
// Frees resources associated with a [[document]] created via
// [[document_clone]].
fn document_destroy(doc: *document) void = {
free(doc.buffer);
finish(doc);
};
// Applies an edit to a [[document]]'s internal buffer.
export fn apply(doc: *document, edit: *edit) void = {
if (edit.rem > 0) {
const rem = edit.rem: io::off;
const start = edit.off + doc.adjust;
const end = edit.off + rem + doc.adjust;
delete(doc.buffer[start..end]);
};
if (edit.ins != "") {
const start = edit.off + doc.adjust;
insert(doc.buffer[start], strings::toutf8(edit.ins)...)!;
};
doc.adjust -= edit.rem: io::off;
doc.adjust += len(edit.ins): io::off;
};
// Stores the applied edits to a [[document]]'s original on disk.
export fn save(doc: *document) (void | io::error) = {
io::seek(doc.file, 0, io::whence::SET)?;
io::trunc(doc.file, len(doc.buffer))?;
io::writeall(doc.file, doc.buffer)?;
};
|