File: document.ha

package info (click to toggle)
hare-update 0.26.0.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,044 kB
  • sloc: makefile: 37; sh: 14
file content (98 lines) | stat: -rw-r--r-- 2,530 bytes parent folder | download
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)?;
};