[ API reference ]
Frame
Purpose and header
Section titled “Purpose and header”koto::Frame maintains the front and back cell buffers (m_front_buffer and m_back_buffer), the hit buffer (m_hit_buffer), harvested id bounding boxes (m_tag_bounds), and the differential SGR output stream (m_output).
Header: koto/frame.hpp (included by koto/koto.hpp).
Types and members
Section titled “Types and members”| Member | Signature | Description | Default |
|---|---|---|---|
Frame(Terminal& t) | Frame(Terminal& t) | Constructs a frame sized to t.get_rows() by t.get_cols() attached to t. | Front buffer Cell{U'\xFF'}, hit buffer TAG_NONE |
Frame(int rows, int cols) | Frame(int rows, int cols) | Constructs a headless frame with m_term = nullptr (negative dimensions clamped to 0). | Front buffer Cell{U'\xFF'}, hit buffer TAG_NONE |
handle_resize() | void handle_resize(int rows, int cols) | Reallocates buffers to rows * cols, fills front buffer with U'\xFF', and clears tags and cursor cache. | None |
set_cell() | void set_cell(int row, int col, Cell c, Id tag_id = Id::none()) | Writes c to back buffer with wide-glyph continuation management and stamps tag_id if not Id::none(). | tag_id = Id::none() |
get_cell() | Cell get_cell(int row, int col) const | Returns the back-buffer cell at (row, col), or Cell{} if out of bounds. | None |
operator[] | Cell& operator[](int row, int col) / const Cell& operator[](int row, int col) const | C++23 2D subscript into m_back_buffer (returns dummy/empty Cell if out of bounds). | None |
fill(area, cell, tag_id) | void fill(Area area, Cell c, Id tag_id = Id::none()) | Calls set_cell for every coordinate in area and unions area into m_tag_bounds. | tag_id = Id::none() |
fill(area, ch, fg, bg, tag_id) | void fill(Area area, char32_t ch, uint32_t fg = COLOR_DEFAULT, uint32_t bg = COLOR_DEFAULT, Id tag_id = Id::none()) | Fills area with Cell{ch, fg, bg, 1, false} and optional tag_id. | fg = COLOR_DEFAULT, bg = COLOR_DEFAULT, tag_id = Id::none() |
clear_back_buffer() | void clear_back_buffer() | Fills m_back_buffer with Cell{}, m_hit_buffer with TAG_NONE, clears m_tag_bounds, and hides cursor. | None |
render() | void render(bool flush = true) | Diffs m_back_buffer against m_front_buffer, populates m_output wrapped in [?2026h..[?2026l, and flushes to STDOUT_FILENO if flush && m_term && m_term->is_tty(). | flush = true |
set_cursor() | void set_cursor(int row, int col) | Marks the hardware cursor visible at (row, col) for the current frame. | Cursor hidden |
area() | Area area() const | Returns Area{0, 0, m_cols, m_rows}. | None |
rows() / height() | int rows() const noexcept / int height() const noexcept | Returns m_rows. | None |
cols() / width() | int cols() const noexcept / int width() const noexcept | Returns m_cols. | None |
tag_cell() | void tag_cell(int row, int col, Id tag_id) | Stamps tag_id at (row, col) in m_hit_buffer and unions Area{row, col, 1, 1} into m_tag_bounds. | None |
tag_area() | void tag_area(Area area, Id tag_id) | Stamps tag_id across area (clipped to frame) and unions area into m_tag_bounds. | None |
hit_at() | Id hit_at(int row, int col) const | Returns the Id at (row, col) in m_hit_buffer, or Id::none() if out of bounds. | Id::none() |
clear_hit_buffer() | void clear_hit_buffer(Id default_tag = Id::none()) | Fills m_hit_buffer with default_tag.value() and clears m_tag_bounds. | default_tag = Id::none() |
bounds_of() | std::optional<Area> bounds_of(Id tag_id) const | Returns the harvested bounding Area for tag_id, or std::nullopt if not drawn/tagged. | std::nullopt |
all_tag_bounds() | const std::unordered_map<uint32_t, Area>& all_tag_bounds() const | Returns the full map of harvested Id values to bounding Areas. | Empty map |
to_plain_text() | std::string to_plain_text() const | Concatenates to_plain_text_row(r) for all rows separated by \n. | None |
to_plain_text_row() | std::string to_plain_text_row(int r) const | Serializes row r to UTF-8, skipping continuation cells and stripping trailing ASCII spaces. | "" if out of bounds |
raw_output() | std::string_view raw_output() const noexcept | Returns the ANSI byte sequence generated by the most recent render() call. | "" |
cursor_row() / cursor_col() / cursor_visible() | int cursor_row() const / int cursor_col() const / bool cursor_visible() const | Inspects the cursor state set by set_cursor(). | -1, -1, false |
Examples
Section titled “Examples”#include <koto/koto.hpp>#include <cassert>
using namespace koto;
int main(){ Frame frame(4, 16); frame.fill(Area(0, 0, 16, 4), U'.', Color::DarkGray, Color::Default, Id("canvas")); frame[1, 2] = Cell{U'X', Color::Cyan, Color::Default};
assert(frame.hit_at(0, 0) == Id("canvas")); assert(frame.bounds_of(Id("canvas")) == Area(0, 0, 16, 4)); assert((frame[1, 2].ch == U'X'));
frame.render(false); assert(!frame.raw_output().empty()); return 0;}Errors and edge cases
Section titled “Errors and edge cases”- Move-only semantics:
Framedeletes its copy constructor and copy assignment operator (Frame(const Frame&) = delete) to prevent accidental full-grid buffer copies. PassFrame&by reference. - Direct
operator[r, c]vs.set_cell(): Mutatingframe[r, c]directly modifiesm_back_bufferin place without running the wide-character continuation cleanup or hit-buffer tagging performed byset_cell(). Useset_cell()whenever writing width-2 glyphs oridtags. - Zero-output clean frames: If no non-continuation cell differs between
m_front_bufferandm_back_bufferand the cursor state has not changed,render()returns immediately without emitting[?2026hor callingwrite_all(). - Write failure recovery: If
write_all(STDOUT_FILENO, m_output)fails duringrender(true),Framefillsm_front_bufferwithCell{U'ÿ'}so the next render pass forces a full screen repaint.