Modules

Text_Buffer

moduleSource
macOSLinuxWindowswasm

since 0.31.0

#import "Extensions/Text_Buffer";

An editable UTF-8 text buffer with undo, for editors. A jaic extension, not official Jai: other Jai compilers have no such module, and it may change between jaic releases. See docs/extensions/text-buffer.md.

The text lives in a piece table: the loaded file is never copied or modified, typed text is appended to a second buffer, and the document is a list of pieces pointing into the two. Editing splits and trims pieces, so inserting or deleting in a large file costs the number of pieces, not the size of the file. Line starts are kept in a sorted array, so lines are found by binary search.

ExampleOpen in playground ↗
#import "Extensions/Text_Buffer";

buffer: Text_Buffer;
defer free_buffer(*buffer);
set_text(*buffer, "hello\nworld");
insert(*buffer, 5, ", there");        // "hello, there\nworld"
erase(*buffer, 0, 1);                  // "ello, there\nworld"
line := line_text(*buffer, 1);         // "world", a view into the buffer
undo(*buffer);                         // back to "hello, there\nworld"
Show moreShow less

Offsets are byte offsets. Positions inside a UTF-8 sequence are the caller's concern: use next_grapheme and previous_grapheme (graphemes.jai) to move on character boundaries.

Procedures#

General#

set_textsince 0.31.0
(buffer: *Text_Buffer, text: string)

Replace the whole text (and forget undo history). The text is copied.

line_countsince 0.31.0
(buffer: *Text_Buffer) -> int

Number of lines: one more than the newlines, so an empty buffer has one empty line.

line_startsince 0.31.0
(buffer: *Text_Buffer, line: int) -> int

Offset of the first byte of line (clamped to the last line).

line_endsince 0.31.0
(buffer: *Text_Buffer, line: int) -> int

Offset just past the last byte of line, before its newline.

line_of_offsetsince 0.31.0
(buffer: *Text_Buffer, offset: int) -> int

The line that contains offset (the last line for an offset at the end).

byte_atsince 0.31.0
(buffer: *Text_Buffer, offset: int) -> u8

The byte at offset, or 0 outside the text.

line_textsince 0.31.0
(buffer: *Text_Buffer, line: int) -> string

The text of line without its line break. It points into the buffer when the line lies within one piece, and is a copy in temporary storage otherwise; either way it is valid only until the next edit.

text_rangesince 0.31.0
(buffer: *Text_Buffer, start: int, end: int) -> string

The bytes start to end (exclusive). Points into the buffer when the range lies within one piece, otherwise a copy in temporary storage; valid until the next edit.

copy_rangesince 0.31.0
(buffer: *Text_Buffer, start: int, end: int, allocator: Allocator) -> string

A copy of the bytes start to end (exclusive) made with allocator.

buffer_to_stringsince 0.31.0
(buffer: *Text_Buffer, allocator: Allocator = context.allocator) -> string

The whole text as a new string made with allocator.

insertsince 0.31.0
(buffer: *Text_Buffer, offset: int, text: string)

Insert text at offset (clamped to the text). Recorded for undo; typing one character after another merges into a single undo step.

erasesince 0.31.0
(buffer: *Text_Buffer, offset: int, count: int)

Delete count bytes starting at offset (clamped to the text). Recorded for undo.

replacesince 0.31.0
(buffer: *Text_Buffer, offset: int, count: int, text: string)

Replace count bytes at offset with text as one undo step.

find_textsince 0.31.0
(buffer: *Text_Buffer, needle: string, from: int = 0) -> int

Search for needle from from; returns the offset of the first match or -1. Matches across pieces are found.

Graphemes#

next_graphemesince 0.31.0
(text: string, index: int) -> int

The byte offset after the grapheme cluster that starts at index in text. Returns text.count at the end, and index itself when it is already there.

previous_graphemesince 0.31.0
(text: string, index: int) -> int

The byte offset where the grapheme cluster that ends at index starts. Returns 0 at the start.

word_classsince 0.31.0
(c: u32) -> Word_Class

The class of a code point for word movement: runs of one class are a word.

next_wordsince 0.31.0
(text: string, index: int) -> int

The byte offset where the word to the right of index ends: spaces are skipped, then a run of word characters or of punctuation. Stops at the end of the text; line breaks are the caller's.

previous_wordsince 0.31.0
(text: string, index: int) -> int

The byte offset where the word to the left of index starts.

grapheme_countsince 0.31.0
(text: string) -> int

Number of grapheme clusters in text.

decode_atsince 0.31.0
(text: string, index: int) -> (code: u32, size: int)

Decode the code point at index: its value and its length in bytes. Malformed bytes decode as U+FFFD, one byte at a time, so scanning always advances.

(text: string, index: int) -> int

Start of the code point that ends at index.

History#

free_historysince 0.31.0
(history: *History)

Release the history's stacks and the text of every edit in them.

begin_groupsince 0.31.0
(buffer: *Text_Buffer)

Start an undo group: every edit until the matching end_group undoes as one step. Groups nest.

seal_undosince 0.31.0
(buffer: *Text_Buffer)

Stop the next typed character from merging into the previous undo step. Call it when the cursor moves, so undo steps follow what the user did.

undosince 0.31.0
(buffer: *Text_Buffer) -> (ok: bool, cursor: int)

Undo the last step. Returns whether anything was undone and the offset the cursor belongs at.

redosince 0.31.0
(buffer: *Text_Buffer) -> (ok: bool, cursor: int)

Redo the last undone step. Returns whether anything was redone and the offset the cursor belongs at.

Types#

Piecestructsince 0.31.0
:: struct

A run of bytes in one of the buffer's two backing arrays; the text is the pieces in order.

Text_Bufferstructsince 0.31.0
:: struct

The text being edited. Zero is an empty buffer; release it with free_buffer.

Word_Classenumsince 0.31.0
:: enum

What a code point counts as when moving by words.

Editstructsince 0.31.0
:: struct

One recorded change: removed was replaced by inserted at offset. Edits with the same group undo together.

Historystructsince 0.31.0
:: struct

A buffer's undo and redo stacks; zero is empty. Use undo, redo, begin_group and end_group rather than reading it.