std/textbuffer

Text being edited, as an editor holds it: a persistent tree of pieces of the first text and of what was inserted since, so an edit, finding a line, and the line and column of a place take logarithmic time however large the text is, and a snapshot takes none.

import "std/textbuffer"

TextBuffer b = text_buffer(read_text("notes.txt"))
b.insert(b.line_start(3), "a new fourth line\n")
print(b.line_text(3), b.line_of(120), b.column_of(120))
b.undo()

Places are byte offsets from 0, and lines are numbered from 0; a line ends at a line feed, and its text leaves out the line feed and a carriage return before it.

Method
b.insert(offset, text), b.remove(start, count), b.replace(start, count, text) edit the text
b.text(), b.slice(start, stop), b.length() its text, a part, and its length in bytes
b.line_count(), b.line_start(line), b.line_text(line) its lines
b.line_of(offset), b.column_of(offset), b.offset_of(line, column) between places and lines and columns
b.undo(), b.redo(), b.can_undo(), b.can_redo() back and forth between versions; an edit after undo drops what redo had
b.begin_group(), b.end_group() the edits between are undone and redone together
b.snapshot() a TextSnapshot of the text now, with the reading methods above, which later edits leave as it is: for work in the background
b.line_ending(), b.set_line_ending(ending) the line ending most lines have, and every line given one, as one edit
b.to_bytes(encoding) the text in an encoding of std/encoding
b.version counts the edits, undos, and redos
Function Result
text_buffer(text) a buffer
text_buffer_from_bytes(data, encoding) a buffer of text in an encoding, detected when it is ""
snapshot_changes(before, after) the line changes between two snapshots, as std/diff gives them
detect_line_ending(text), convert_line_endings(text, ending) the same for plain text: "\n", "\r\n", or "\r"

tools/textbuffer_bench.cz times a text of hundreds of megabytes.