Buffer

The buffer classes represent rendered terminal content in memory before it is written to the screen.

ReadableBuffer provides a read-only inspection API, WritableBuffer extends this with mutation and drawing operations, and Buffer is the concrete 2D storage type used in most applications.

For more specialized use cases, RemappedBuffer adds efficient row- and column-based reordering. This is ideal for editors, scrollback views, or any workload that frequently inserts, deletes, or moves whole lines.

Building on top of that, CursorBuffer provides a VT-style cursor-writing interface via CursorWriter.

Use these types whenever you want to build frames off-screen, compare frames, copy content between buffers, or derive masks from rendered characters.

Usage

Reading and Writing Through Buffer Interfaces

ReadableBuffer and WritableBuffer allow helper functions to operate on terminal content without depending on a specific implementation.

auto renderStatusPanel(WritableBuffer &target, Rectangle panel) -> void {
    target.fill(panel, Char{" ", Color{fg::Inherited, bg::Blue}});
    target.drawText(
        "Status",
        panel.insetBy(Margins{1}),
        Alignment::TopLeft,
        Color{fg::BrightWhite, bg::Blue});
}

auto screen = Buffer{Size{80, 24}};
renderStatusPanel(screen, Rectangle{2, 2, 24, 8});

Use ReadableBuffer when your function only needs to inspect content, count differences, or derive masks.

Use WritableBuffer when your function should modify the target buffer without caring whether it operates on a standalone Buffer or another writable implementation.

Cloning, Copying, and Resizing

Buffer supports the typical frame-management tasks required by interactive terminal applications: creating new frames, cloning the current state, and resizing buffers when the terminal size changes.

auto current = Buffer{Size{80, 24}};
current.fill(Char{" ", Color{fg::Inherited, bg::Black}});

const auto previous = current.clone();
current.resize(Size{100, 30}, true, Char::space());
current.setFrom(*previous, Char{" ", Color{fg::Inherited, bg::Black}});

clone() returns a writable copy through the abstract interface. This makes it easy to store previous frames for diffing, animation steps, or rollback logic.

When resizing a concrete Buffer, use the reorder overload if you want to preserve existing content while expanding or cropping the canvas.

Working with Remapped Buffers

RemappedBuffer is designed for workloads where the content remains logically grid-based, but rows or columns are frequently reshuffled.

Instead of rewriting every affected cell, the buffer maintains remapping tables and only updates rows or columns that become newly visible. This keeps operations like scrolling or line insertion efficient, even for large buffers.

auto history = RemappedBuffer{Size{80, 2'000}, Orientation::Vertical};
history.fill(Char::space());

history.eraseRows(0, Char::space(), 1);      // Scroll everything up by one row.
history.set(Position{0, 1'999}, String{"new log line"});

history.resize(Size{100, 2'000}, true, Char::space());

Use the plain RemappedBuffer::resize() overload when you want maximum performance and plan to redraw the content anyway.

Use the reorder overload when the visible order must remain stable while expanding or cropping the buffer.

Streaming Scrollback with CursorBuffer

CursorBuffer is the right choice when text is appended over time, as if it were written directly to a terminal.

It tracks a cursor position, maintains an active color, and supports streaming writes via CursorWriter. When the cursor reaches the bottom edge, it can wrap, scroll, or grow vertically depending on the configured overflow mode.

Newly created cells are initialized using fillChar(), allowing you to keep a consistent background color or placeholder glyph as the buffer grows.

auto logHistory = CursorBuffer{
    Size{120, 10},
    CursorBuffer::OverflowMode::ExpandThenShift,
    Size{120, 500},
    Char{" ", Color{fg::Default, bg::Black}}};

logHistory.setColor(Color{fg::BrightBlue, bg::Black});
logHistory.printParagraph("2026-03-26 09:02:23 INF Request completed in 43 ms");

logHistory.setColor(Color{fg::BrightYellow, bg::Black});
logHistory.printParagraph("2026-03-26 09:03:04 WRN Cache refresh is still pending");

const auto visibleTop = std::max(0, logHistory.size().height() - 20);
auto view = BufferConstRefView{logHistory, Rectangle{0, visibleTop, 120, 20}};
terminal.updateScreen(view);

This pattern works especially well for log viewers, REPL-style tools, dashboards, or any application that needs a growing history buffer with a live viewport onto the most recent content.

If your fill strategy changes later, update it with CursorBuffer::setFillChar.

For details about the streaming API itself—such as print(), printLine(), and cursor movement—see Cursor Output.

Important

For an efficient render loop, keep a persistent instance of Buffer and simply resize it when the terminal size changes.

Reusing the same buffer avoids unnecessary memory allocations and helps keep rendering predictable and fast.

A typical render loop might look like this:

struct MyApp {
    void renderLoop() {
        for (;;) {
            _terminal.testScreenSize();
            _buffer.resize(_terminal.size());

            // Render the current frame into the buffer.
            _terminal.updateScreen(_buffer);

            // Handle key presses or other input.
        }
    }

    Terminal _terminal;
    Buffer _buffer;
};

Building Buffers from Text Lines

For status panels, generated reports, or static UI elements, Buffer can be constructed directly from line-oriented text.

const auto help = Buffer::fromLinesInString(String{
    "Q  Quit\n"
    "R  Refresh\n"
    "H  Toggle help"});

auto screen = Buffer{Size{40, 12}};
screen.setFrom(help, Char::space());

This is often the fastest way to turn preformatted terminal text into a buffer that can later be positioned within a larger layout.

Comparing Frames and Deriving Masks

ReadableBuffer also provides analysis helpers that are useful for tests, animation pipelines, and bitmap-based effects.

const auto changedCells = previous->countDifferencesTo(current);
const auto frameMask = current.toMask({U'|', U'-', U'+', U'┌', U'┐', U'└', U'┘'});

if (changedCells > 0 && frameMask.size().contains(Position{0, 0})) {
    // React to the changed frame content.
}

Use toMask() when you want to reason about the structure of rendered content (for example, line art or borders) instead of raw character or color data.

Interface

class ReadableBuffer

A readable buffer.

Subclassed by erbsland::cterm::BufferViewBase, erbsland::cterm::WritableBuffer

Public Functions

virtual Size size() const noexcept = 0

Get the configured size of the buffer.

Returns:

The width and height of the buffer.

virtual Rectangle rect() const noexcept = 0

Get a rectangle representing this buffer.

Returns:

The rectangle for this buffer.

virtual const Char &get(Position pos) const noexcept = 0

Read the block stored at the given position.

Parameters:

pos – The coordinates within the buffer.

Returns:

A reference to the stored block.

virtual WritableBufferPtr clone() const = 0

Create a writeable copy of this buffer.

This will copy every block from this buffer into a new independent instance.

virtual std::size_t countDifferencesTo(const ReadableBuffer &other) const noexcept

Count the differences from this to another buffer.

If the size of other is smaller or larger than this buffer, the size change counts to the difference.

Parameters:

other – The other buffer to compare with.

Returns:

The number of blocks that differ between the two buffers.

Bitmap toMask(const std::u32string &characters, bool invert = false)

Create a mask from this buffer.

All characters that match one of the given characters result in a pixel set in the mask.

Parameters:
  • characters – The characters to match. Only one code-point characters are supported.

  • invert – If true, not-matching characters result in a pixel set in the mask.

Returns:

A bitmap mask with the same size as this buffer.

Bitmap toMask(std::initializer_list<char32_t> characters, bool invert = false)

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

class WritableBuffer : public erbsland::cterm::ReadableBuffer

Abstract writable terminal buffer interface.

This base class combines the read-only ReadableBuffer API with mutation and higher-level drawing helpers such as frames, text, and bitmap rendering. Concrete implementations like Buffer provide the actual storage.

Subclassed by erbsland::cterm::Buffer, erbsland::cterm::RemappedBuffer

Public Functions

virtual void resize(Size newSize) = 0

Resize this buffer in a memory-efficient way.

The content of the resized buffer is undefined and must be filled with new content.

Parameters:

newSize – The new size for the buffer.

virtual void set(Position pos, const Char &block) noexcept = 0

Write a block at the given position.

Note

Writes outside the buffer are ignored.

Parameters:
  • pos – The coordinates within the buffer.

  • block – The block value to store.

virtual void setAndResizeFrom(const ReadableBuffer &other)

Copy the content from another buffer and match its size.

This buffer is completely overwritten and resized to the size of other.

Parameters:

other – The buffer to copy from.

virtual void set(Position pos, const Char &block, const CharCombinationStylePtr &combinationStyle) noexcept

Write a block at the given position using a combination style.

Note

Writes outside the buffer are ignored.

Parameters:
  • pos – The coordinates within the buffer.

  • block – The block value to store.

  • combinationStyle – The combination style for overwriting existing characters.

virtual void set(Position pos, const String &str) noexcept

Write a string at the given position.

NL jumps to the next row. Other control and zero-width characters are ignored. Color (even inherited) overwrites the existing characters. Use drawText(pos, text) for a color overlay.

Parameters:
  • pos – The coordinates within the buffer.

  • str – The string to write.

void setFrom(const ReadableBuffer &other, Char fillChar = Char::space())

Copy the content from another buffer into this one.

This buffer is completely overwritten but not resized. If there is a size mismatch, the contents are either cut off or filled using fillChar.

Parameters:
  • other – The buffer to copy from.

  • fillChar – The character to use for filling if the sizes differ.

virtual void fill(const Char &fillBlock) noexcept

Fill/clear the buffer with the given character.

Parameters:

fillBlock – The block to use to fill the buffer.

void fill(Rectangle rect, const Char &fillBlock, const CharCombinationStylePtr &combinationStyle = {}) noexcept

Fill the given rectangle.

Positions outside the buffer are ignored.

Parameters:
  • rect – The rectangle to be filled.

  • fillBlock – The block for filling.

  • combinationStyle – The combination style for overwriting existing characters.

void fill(Rectangle rect, const Tile9StylePtr &style, Color baseColor = {}, const CharCombinationStylePtr &combinationStyle = {}) noexcept

Fill the given rectangle using a repeating 9-tile style.

Positions outside the buffer are ignored.

Parameters:
  • rect – The rectangle to be filled.

  • style – The tile style to repeat across the rectangle.

  • baseColor – The base color underneath the style colors.

  • combinationStyle – The combination style for overwriting existing characters.

void drawFrame(Rectangle rect, const Char &frameBlock, const CharCombinationStylePtr &combinationStyle = {}) noexcept

Draw a frame inside a given rectangle This will set all blocks at the edge, inside the given rectangle.

Parameters:
  • rect – The rectangle for the frame.

  • frameBlock – The block for the frame.

  • combinationStyle – The combination style for overwriting existing characters.

void drawFrame(Rectangle rect, const Char16StylePtr &frameStyle, const CharCombinationStylePtr &combinationStyle = {}, Color frameColor = {}) noexcept

Draw a frame inside a given rectangle This will set all blocks at the edge, inside the given rectangle.

Parameters:
  • rect – The rectangle for the frame.

  • frameStyle – A custom frame style.

  • combinationStyle – The combination style for overwriting existing characters.

  • frameColor – The base frame color. Any color from the frame style overlays this base color.

void drawFrame(Rectangle rect, const Tile9StylePtr &style, Color frameColor = {}, const CharCombinationStylePtr &combinationStyle = {}) noexcept

Draw a frame inside a given rectangle using a repeating 9-tile style.

This will set all blocks at the edge, inside the given rectangle.

Parameters:
  • rect – The rectangle for the frame.

  • style – The tile style for the frame.

  • frameColor – The base frame color. Any color from the style overlays this base color.

  • combinationStyle – The combination style for overwriting existing characters.

void drawFrame(Rectangle rect, FrameStyle frameStyle, Color frameColor = {}) noexcept

Draw a frame inside a given rectangle This will set all blocks at the edge, inside the given rectangle.

Parameters:
  • rect – The rectangle for the frame.

  • frameStyle – The predefined frame style.

  • frameColor – The base frame color. Any color from the frame style overlays this base color.

void drawFrame(Rectangle rect, const FrameDrawOptions &options = FrameDrawOptions::defaultOptions(), std::size_t animationCycle = 0) noexcept

Draw a frame inside a given rectangle with configurable style, fill, and animated colors.

This will set all blocks at the edge, inside the given rectangle. If options.fillBlock() is empty and no Tile9Style is active, the interior is left unchanged.

Parameters:
  • rect – The rectangle for the frame.

  • options – Frame drawing options.

  • animationCycle – Animation cycle for frame and fill color animations.

void drawFilledFrame(Rectangle rect, const Char &frameBlock, const Char &fillBlock, const CharCombinationStylePtr &combinationStyle = {}) noexcept

Draw a box and fill it.

Parameters:
  • rect – The rectangle for the frame.

  • frameBlock – The block for the frame.

  • fillBlock – The block for filling.

  • combinationStyle – The combination style for overwriting existing characters.

void drawFilledFrame(Rectangle rect, const Char16StylePtr &frameStyle, const Char &fillBlock, const CharCombinationStylePtr &combinationStyle = {}, Color frameColor = {}) noexcept

Draw a box and fill it.

Parameters:
  • rect – The rectangle for the frame.

  • frameStyle – A custom frame style.

  • fillBlock – The block for filling.

  • combinationStyle – The combination style for overwriting existing characters.

  • frameColor – The base frame color. Any color from the frame style overlays this base color.

void drawFilledFrame(Rectangle rect, const Tile9StylePtr &style, const Char &fillBlock, const CharCombinationStylePtr &combinationStyle = {}, Color frameColor = {}) noexcept

Draw a box and fill it using a repeating 9-tile style for the frame.

Parameters:
  • rect – The rectangle for the frame.

  • style – The tile style for the frame.

  • fillBlock – The block for filling.

  • combinationStyle – The combination style for overwriting existing characters.

  • frameColor – The base frame color. Any color from the style overlays this base color.

void drawFilledFrame(Rectangle rect, FrameStyle frameStyle, const Char &fillBlock, Color frameColor = {}) noexcept

Draw a box and fill it.

Parameters:
  • rect – The rectangle for the frame.

  • frameStyle – The predefined frame style.

  • fillBlock – The block for filling.

  • frameColor – The base frame color. Any color from the frame style overlays this base color.

virtual void drawText(Position pos, const String &str)

Draw a text without warping from the given position.

A newline breaks to the next line, starting at pos.x. Characters outside this buffer are cut off.

Parameters:
  • pos – The start position (top-left corner).

  • str – The text to draw on this buffer.

void drawText(const Text &text, std::size_t animationCycle = 0)

If fg or bg is set to Inherited, the current color from the buffer is used.

Draw simple text into a rectangle. If fg or bg is set to Inherited, the current color from the buffer is used.

Parameters:
  • text – The text description.

  • animationCycle – Animation cycle for animated text.

void drawText(std::string_view text, Rectangle rect, Alignment alignment = Alignment::TopLeft, Color color = {}, std::size_t animationCycle = 0)

Draw simple text into a rectangle.

If fg or bg is set to Inherited, the current color from the buffer is used.

Parameters:
  • text – The text to render.

  • rect – The target rectangle.

  • alignment – The alignment inside the rectangle.

  • color – The text color.

  • animationCycle – Animation cycle for animated text.

void drawText(String text, Rectangle rect, Alignment alignment = Alignment::TopLeft, Color color = {}, std::size_t animationCycle = 0)

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

void drawBitmap(const Bitmap &bitmap, Position pos, const BitmapDrawOptions &options = BitmapDrawOptions::defaultOptions(), std::size_t animationCycle = 0) noexcept

Draw a bitmap at a given position.

The bitmap is rendered according to options.scaleMode(). If options.char16Style() is set, it overrides the scale mode and renders one terminal cell per bitmap pixel. Pixels or rendered cells outside the buffer are ignored.

Parameters:
  • bitmap – The bitmap to draw.

  • pos – The position of the top left corner.

  • optionsBitmap drawing options.

  • animationCycle – Animation cycle for color animations.

void drawBitmap(const Bitmap &bitmap, Rectangle rect, Alignment alignment = Alignment::TopLeft, const BitmapDrawOptions &options = BitmapDrawOptions::defaultOptions(), std::size_t animationCycle = 0) noexcept

Draw a bitmap into the given rectangle.

The rendered bitmap is aligned inside rect. If it is larger than rect, it is cropped according to the alignment.

Note

For half-block drawing mode, alignment and cropping happen at rendered cell boundaries, not per pixel.

Parameters:
  • bitmap – The bitmap to draw.

  • rect – The rectangle to draw the bitmap into.

  • alignment – Alignment of the bitmap within the rectangle.

  • optionsBitmap drawing options.

  • animationCycle – Animation cycle for color animations.

void drawBuffer(const ReadableBuffer &buffer, Position targetPos = Position{})

Draw the contents of another buffer into this one.

Resulting positions outside the target rectangle are clipped.

Parameters:
  • buffer – The buffer to draw.

  • targetPos – The target position where to draw the top-left corner of the buffer.

Throws:

std::invalid_argument – if buffer is this buffer.

void drawBuffer(const ReadableBuffer &buffer, Rectangle targetRect, Alignment alignment = Alignment::TopLeft)

Draw the contents of another buffer into this one.

Resulting positions outside the target rectangle are clipped.

Parameters:
  • buffer – The buffer to draw.

  • targetRect – The target rectangle where to draw the buffer. Clips buffer if larger.

  • alignment – The alignment of the buffer within the target rectangle.

Throws:

std::invalid_argument – if buffer is this buffer.

virtual void drawBuffer(const ReadableBuffer &buffer, const BufferDrawOptions &options)

Draw the contents of another buffer into this one.

Parameters:
  • buffer – The buffer to draw.

  • options – The options for drawing the buffer.

Throws:

std::invalid_argument – if buffer is this buffer.

class Buffer : public erbsland::cterm::WritableBuffer

A mutable 2D buffer storing characters and colors for rendering.

Handling of non-1-width blocks:

  • Blocks with zero display width are ignored.

  • Blocks with a display width of 2 will overwrite two adjacent cells.

    • The first cell will contain the set character, the next cell a zero-width (empty) character.

    • Both cells will have the same color.

    • A 2-width block at the right edge is ignored.

  • Blocks with a display width > 2 are ignored.

Public Functions

Buffer()

Creates a 1x1 buffer filled with a space.

Usually only used as a placeholder until resized.

explicit Buffer(Size size, Char fillChar = Char::space())

Construct a buffer with the given size and fill it with an initial block.

Parameters:
  • size – The dimensions of the buffer. Size must be at least 1x1.

  • fillChar – The optional fill character for the buffer.

Throws:

std::invalid_argument – if size is invalid

virtual Size size() const noexcept override

Get the configured size of the buffer.

Returns:

The width and height of the buffer.

virtual Rectangle rect() const noexcept override

Get a rectangle representing this buffer.

Returns:

The rectangle for this buffer.

virtual const Char &get(Position pos) const noexcept override

Read the block stored at the given position.

Parameters:

pos – The coordinates within the buffer.

Returns:

A reference to the stored block.

virtual WritableBufferPtr clone() const override

Create a writeable copy of this buffer.

This will copy every block from this buffer into a new independent instance.

virtual void resize(Size newSize) override

Resize this buffer in a memory-efficient way.

The content of the resized buffer is undefined and must be filled with new content.

Parameters:

newSize – The new size for the buffer.

virtual void set(Position pos, const Char &block) noexcept override

Write a block at the given position.

Note

Writes outside the buffer are ignored.

Parameters:
  • pos – The coordinates within the buffer.

  • block – The block value to store.

virtual void setAndResizeFrom(const ReadableBuffer &other) override

Copy the content from another buffer and match its size.

This buffer is completely overwritten and resized to the size of other.

Parameters:

other – The buffer to copy from.

void resize(Size size, bool reorder, Char fillChar = Char::space())

Resize this buffer.

Resizing the buffer will not clear it. If reorder is true, the content will either be expanded with space blocks or cropped. If reorder is false, the state of the resized buffer is undefined (you must clear it yourself).

Parameters:
  • size – The new size.

  • reorder – Whether to reorder the content when resizing.

  • fillChar – The character to fill the new space with.

Throws:

std::invalid_argument – if size is invalid

virtual void fill(const Char &fillBlock) noexcept override

Fill/clear the buffer with the given character.

Parameters:

fillBlock – The block to use to fill the buffer.

void drawText(std::string_view text, Alignment alignment, Rectangle rect, Color color = {}, std::size_t animationCycle = 0)

Draw text into a rectangle using the legacy parameter order.

Deprecated:

Use drawText(std::string_view, Rectangle, ...) instead.

Parameters:
  • text – The text to render.

  • alignment – The alignment inside the rectangle.

  • rect – The target rectangle.

  • color – The text color.

  • animationCycle – Animation cycle for animated text.

void drawBitmap(const Bitmap &bitmap, Position pos, const BitmapDrawOptions &options = BitmapDrawOptions::defaultOptions(), std::size_t animationCycle = 0) noexcept

Draw a bitmap at a given position.

The bitmap is rendered according to options.scaleMode(). If options.char16Style() is set, it overrides the scale mode and renders one terminal cell per bitmap pixel. Pixels or rendered cells outside the buffer are ignored.

Parameters:
  • bitmap – The bitmap to draw.

  • pos – The position of the top left corner.

  • optionsBitmap drawing options.

  • animationCycle – Animation cycle for color animations.

void drawBitmap(const Bitmap &bitmap, Rectangle rect, Alignment alignment = Alignment::TopLeft, const BitmapDrawOptions &options = BitmapDrawOptions::defaultOptions(), std::size_t animationCycle = 0) noexcept

Draw a bitmap into the given rectangle.

The rendered bitmap is aligned inside rect. If it is larger than rect, it is cropped according to the alignment.

Note

For half-block drawing mode, alignment and cropping happen at rendered cell boundaries, not per pixel.

Parameters:
  • bitmap – The bitmap to draw.

  • rect – The rectangle to draw the bitmap into.

  • alignment – Alignment of the bitmap within the rectangle.

  • optionsBitmap drawing options.

  • animationCycle – Animation cycle for color animations.

virtual void drawText(Position pos, const String &str)

Draw a text without warping from the given position.

A newline breaks to the next line, starting at pos.x. Characters outside this buffer are cut off.

Parameters:
  • pos – The start position (top-left corner).

  • str – The text to draw on this buffer.

void drawText(const Text &text, std::size_t animationCycle = 0)

If fg or bg is set to Inherited, the current color from the buffer is used.

Draw simple text into a rectangle. If fg or bg is set to Inherited, the current color from the buffer is used.

Parameters:
  • text – The text description.

  • animationCycle – Animation cycle for animated text.

void drawText(std::string_view text, Rectangle rect, Alignment alignment = Alignment::TopLeft, Color color = {}, std::size_t animationCycle = 0)

Draw simple text into a rectangle.

If fg or bg is set to Inherited, the current color from the buffer is used.

Parameters:
  • text – The text to render.

  • rect – The target rectangle.

  • alignment – The alignment inside the rectangle.

  • color – The text color.

  • animationCycle – Animation cycle for animated text.

void drawText(String text, Rectangle rect, Alignment alignment = Alignment::TopLeft, Color color = {}, std::size_t animationCycle = 0)

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

virtual void fill(const Char &fillBlock) noexcept

Fill/clear the buffer with the given character.

Parameters:

fillBlock – The block to use to fill the buffer.

void fill(Rectangle rect, const Char &fillBlock, const CharCombinationStylePtr &combinationStyle = {}) noexcept

Fill the given rectangle.

Positions outside the buffer are ignored.

Parameters:
  • rect – The rectangle to be filled.

  • fillBlock – The block for filling.

  • combinationStyle – The combination style for overwriting existing characters.

void fill(Rectangle rect, const Tile9StylePtr &style, Color baseColor = {}, const CharCombinationStylePtr &combinationStyle = {}) noexcept

Fill the given rectangle using a repeating 9-tile style.

Positions outside the buffer are ignored.

Parameters:
  • rect – The rectangle to be filled.

  • style – The tile style to repeat across the rectangle.

  • baseColor – The base color underneath the style colors.

  • combinationStyle – The combination style for overwriting existing characters.

virtual void resize(Size newSize) = 0

Resize this buffer in a memory-efficient way.

The content of the resized buffer is undefined and must be filled with new content.

Parameters:

newSize – The new size for the buffer.

virtual void set(Position pos, const Char &block) noexcept = 0

Write a block at the given position.

Note

Writes outside the buffer are ignored.

Parameters:
  • pos – The coordinates within the buffer.

  • block – The block value to store.

virtual void set(Position pos, const Char &block, const CharCombinationStylePtr &combinationStyle) noexcept

Write a block at the given position using a combination style.

Note

Writes outside the buffer are ignored.

Parameters:
  • pos – The coordinates within the buffer.

  • block – The block value to store.

  • combinationStyle – The combination style for overwriting existing characters.

virtual void set(Position pos, const String &str) noexcept

Write a string at the given position.

NL jumps to the next row. Other control and zero-width characters are ignored. Color (even inherited) overwrites the existing characters. Use drawText(pos, text) for a color overlay.

Parameters:
  • pos – The coordinates within the buffer.

  • str – The string to write.

Public Static Functions

static Buffer fromLinesInString(const String &text)

Creates a buffer from the lines in a string.

This function splits the given string into lines and creates a buffer with a matching size.

Parameters:

text – The string to split into lines and create a buffer from. Must not be empty.

Returns:

A buffer containing the lines from the input string.

static Buffer fromLines(const StringLines &lines)

Creates a buffer from the lines in a string.

Parameters:

lines – The lines to create the buffer from. Must not be empty.

Returns:

A buffer containing the lines from the input string.

Public Static Attributes

static constexpr auto cMaximumSize = Size{10'000, 10'000}

Largest buffer size accepted for this buffer.

static constexpr auto cMinimumSize = Size{1, 1}

Smallest valid buffer size.

class RemappedBuffer : public erbsland::cterm::WritableBuffer

A buffer that allows fast remapping/shifting/inserting/deleting of rows and columns.

This buffer is useful if you have a large buffer that requires frequent row- or column-based manipulations. It is designed for fast insert/delete/move and shift operations.

This buffer also knows two orientations: vertical and horizontal.

  • In the vertical orientation, the buffer can efficiently grow vertically, keeping the existing data intact.

  • In the horizontal orientation, the buffer can efficiently grow horizontally, keeping the existing data intact.

  • When growing the buffer, memory reallocation may be necessary. Use reserve to reserve enough memory to avoid frequent reallocations.

  • Use resize(size, true, fillChar) when you need to preserve the visible order while resizing.

Subclassed by erbsland::cterm::CursorBuffer

Public Types

using CoordinateMap = std::vector<Coordinate>

A vector mapping one coordinate to another.

Public Functions

RemappedBuffer()

Creates a 1x1 vertical buffer filled with a space.

Usually only used as a placeholder until resized.

explicit RemappedBuffer(Size size, Orientation orientation = Orientation::Vertical, Char fillChar = Char::space())

Construct a buffer with the given size and fill it with an initial block.

Parameters:
  • size – The dimensions of the buffer. Size must be at least 1x1.

  • orientation – The orientation of the buffer. Cannot be changed after creation.

  • fillChar – The optional fill character for the buffer.

Throws:

std::invalid_argument – if size is invalid

virtual Size size() const noexcept override

Get the current size of the buffer.

Returns:

The configured width and height.

virtual Rectangle rect() const noexcept override

Get the rectangle covering the whole buffer.

Returns:

A rectangle with origin (0,0) and the current size.

virtual const Char &get(Position pos) const noexcept override

Read the block stored at the given logical position.

Parameters:

pos – The logical coordinates inside the buffer.

Returns:

A reference to the stored block, or a shared space block for invalid positions.

virtual WritableBufferPtr clone() const override

Create an independent writable copy of this buffer.

Returns:

A shared pointer to the cloned buffer.

virtual void resize(Size newSize) override

Resize this buffer.

This is the fast resize path. The internal mapping is rebuilt and the visible content order is undefined after the operation. Use resize(size, true, fillChar) if you need to preserve the visible order.

Parameters:

newSize – The new size of the buffer.

Throws:

std::invalid_argument – if newSize is invalid.

virtual void set(Position pos, const Char &block) noexcept override

Write a block at the given logical position.

This mirrors the wide-character handling from Buffer: zero-width blocks are ignored, width-2 blocks occupy the next logical cell as an empty continuation cell, and width-2 blocks at the right edge are ignored.

Parameters:
  • pos – The logical coordinates within the buffer.

  • block – The block to write.

void resize(Size size, bool reorder, Char fillChar = Char::space())

Resize this buffer and optionally keep the visible content order.

Parameters:
  • size – The new size.

  • reorder – If true, keep the visible order and fill new cells with fillChar. If false, resize using the fast path and leave the visible order undefined.

  • fillChar – The fill character for newly created cells in reordered mode. In fast mode it is only used to initialize newly appended storage cells.

Throws:

std::invalid_argument – if size is invalid.

void reserve(Size size) noexcept

Reserve memory for the given buffer size.

Parameters:

size – The size whose capacity should be reserved.

void shift(Direction direction, Char fillChar, int count = 1)

Shift the buffer in the given direction, fill new cells with a given character.

Parameters:
  • direction – The direction of the shift.

  • fillChar – The character to fill new cells with.

  • count – The number of cells to shift.

Throws:

std::invalid_argument – if count is negative or exceeds buffer size.

inline void shift(const Direction direction, const int count = 1)

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

void rotate(Direction direction, int count = 1)

Rotate the buffer in the given direction.

Cells are shifted in a circular manner, wrapping around to the other end of the buffer.

Parameters:
  • direction – The direction in which to rotate.

  • count – The number of cells to rotate.

Throws:

std::invalid_argument – if count is negative or exceeds buffer size.

void eraseRows(Coordinate startRow, Char fillChar, int count = 1)

Erase rows in the buffer.

This will erase count rows, starting from startRow, and insert empty ones at the end. If you like to actually shrink the buffer, use resize after this call.

Parameters:
  • startRow – The first row to delete.

  • fillChar – The character to fill new cells with.

  • count – The number of rows to delete.

Throws:

std::invalid_argument – if startRow is out of bounds or count is negative or exceeds buffer size.

inline void eraseRows(const Coordinate startRow, const int count = 1)

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

void eraseColumns(Coordinate startColumn, Char fillChar, int count = 1)

Erase columns in the buffer.

This will erase count columns, starting from startColumn, and insert empty ones at the end. If you like to actually shrink the buffer, use resize after this call.

Parameters:
  • startColumn – The first column to delete.

  • fillChar – The character to fill new cells with.

  • count – The number of columns to delete.

Throws:

std::invalid_argument – if startColumn is out of bounds or count is negative or exceeds buffer size.

inline void eraseColumns(const Coordinate startColumn, const int count = 1)

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

void insertRows(Coordinate startRow, Char fillChar, int count = 1)

Insert rows in the buffer.

The rows at the bottom of the buffer will be erased to make room for the new rows. If you like to actually grow the buffer, use resize before this call.

Parameters:
  • startRow – The first row to insert.

  • fillChar – The character to fill the new rows with.

  • count – The number of rows to insert.

Throws:

std::invalid_argument – if startRow is out of bounds or count is negative or exceeds buffer size.

inline void insertRows(const Coordinate startRow, const int count = 1)

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

void insertColumns(Coordinate startColumn, Char fillChar, int count = 1)

Insert columns in the buffer.

The columns on the right side of the buffer will be erased to make room for the new columns. If you like to actually grow the buffer, use resize before this call.

Parameters:
  • startColumn – The first column to insert.

  • fillChar – The character to fill the new columns with.

  • count – The number of columns to insert.

Throws:

std::invalid_argument – if startColumn is out of bounds or count is negative or exceeds buffer size.

inline void insertColumns(const Coordinate startColumn, const int count = 1)

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

void moveRows(Coordinate startRow, int count, Coordinate delta, Char fillChar)

Move rows in the buffer by a given delta.

A positive delta moves rows down, a negative delta moves rows up. This reshuffles the moved rows, but rows that get moved out of the buffer area are deleted and replaced by empty cells using the fillChar.

Parameters:
  • startRow – The first row to move.

  • count – The number of rows to move.

  • delta – The number of positions to move (positive = down, negative = up).

  • fillChar – The character to fill vacated cells with.

Throws:

std::invalid_argument – if startRow is out of bounds or count is negative or exceeds buffer size.

inline void moveRows(const Coordinate startRow, const int count, const Coordinate delta)

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

void moveColumns(Coordinate startColumn, int count, Coordinate delta, Char fillChar)

Move columns in the buffer by a given delta.

A positive delta moves columns right, a negative delta moves columns left. This reshuffles the moved columns, but columns that get moved out of the buffer area are deleted and replaced by empty cells using the fillChar.

Parameters:
  • startColumn – The first column to move.

  • count – The number of columns to move.

  • delta – The number of positions to move (positive = right, negative = left).

  • fillChar – The character to fill vacated cells with.

Throws:

std::invalid_argument – if startColumn is out of bounds or count is negative or exceeds buffer size.

inline void moveColumns(const Coordinate startColumn, const int count, const Coordinate delta)

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

virtual void fill(const Char &fillBlock) noexcept override

Fill/clear the buffer with the given character.

Note

This will also reset the internal remapping indexes.

Parameters:

fillBlock – The block to use to fill the buffer.

void drawBitmap(const Bitmap &bitmap, Position pos, const BitmapDrawOptions &options = BitmapDrawOptions::defaultOptions(), std::size_t animationCycle = 0) noexcept

Draw a bitmap at a given position.

The bitmap is rendered according to options.scaleMode(). If options.char16Style() is set, it overrides the scale mode and renders one terminal cell per bitmap pixel. Pixels or rendered cells outside the buffer are ignored.

Parameters:
  • bitmap – The bitmap to draw.

  • pos – The position of the top left corner.

  • optionsBitmap drawing options.

  • animationCycle – Animation cycle for color animations.

void drawBitmap(const Bitmap &bitmap, Rectangle rect, Alignment alignment = Alignment::TopLeft, const BitmapDrawOptions &options = BitmapDrawOptions::defaultOptions(), std::size_t animationCycle = 0) noexcept

Draw a bitmap into the given rectangle.

The rendered bitmap is aligned inside rect. If it is larger than rect, it is cropped according to the alignment.

Note

For half-block drawing mode, alignment and cropping happen at rendered cell boundaries, not per pixel.

Parameters:
  • bitmap – The bitmap to draw.

  • rect – The rectangle to draw the bitmap into.

  • alignment – Alignment of the bitmap within the rectangle.

  • optionsBitmap drawing options.

  • animationCycle – Animation cycle for color animations.

virtual void drawText(Position pos, const String &str)

Draw a text without warping from the given position.

A newline breaks to the next line, starting at pos.x. Characters outside this buffer are cut off.

Parameters:
  • pos – The start position (top-left corner).

  • str – The text to draw on this buffer.

void drawText(const Text &text, std::size_t animationCycle = 0)

If fg or bg is set to Inherited, the current color from the buffer is used.

Draw simple text into a rectangle. If fg or bg is set to Inherited, the current color from the buffer is used.

Parameters:
  • text – The text description.

  • animationCycle – Animation cycle for animated text.

void drawText(std::string_view text, Rectangle rect, Alignment alignment = Alignment::TopLeft, Color color = {}, std::size_t animationCycle = 0)

Draw simple text into a rectangle.

If fg or bg is set to Inherited, the current color from the buffer is used.

Parameters:
  • text – The text to render.

  • rect – The target rectangle.

  • alignment – The alignment inside the rectangle.

  • color – The text color.

  • animationCycle – Animation cycle for animated text.

void drawText(String text, Rectangle rect, Alignment alignment = Alignment::TopLeft, Color color = {}, std::size_t animationCycle = 0)

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

virtual void fill(const Char &fillBlock) noexcept

Fill/clear the buffer with the given character.

Parameters:

fillBlock – The block to use to fill the buffer.

void fill(Rectangle rect, const Char &fillBlock, const CharCombinationStylePtr &combinationStyle = {}) noexcept

Fill the given rectangle.

Positions outside the buffer are ignored.

Parameters:
  • rect – The rectangle to be filled.

  • fillBlock – The block for filling.

  • combinationStyle – The combination style for overwriting existing characters.

void fill(Rectangle rect, const Tile9StylePtr &style, Color baseColor = {}, const CharCombinationStylePtr &combinationStyle = {}) noexcept

Fill the given rectangle using a repeating 9-tile style.

Positions outside the buffer are ignored.

Parameters:
  • rect – The rectangle to be filled.

  • style – The tile style to repeat across the rectangle.

  • baseColor – The base color underneath the style colors.

  • combinationStyle – The combination style for overwriting existing characters.

virtual void resize(Size newSize) = 0

Resize this buffer in a memory-efficient way.

The content of the resized buffer is undefined and must be filled with new content.

Parameters:

newSize – The new size for the buffer.

virtual void set(Position pos, const Char &block) noexcept = 0

Write a block at the given position.

Note

Writes outside the buffer are ignored.

Parameters:
  • pos – The coordinates within the buffer.

  • block – The block value to store.

virtual void set(Position pos, const Char &block, const CharCombinationStylePtr &combinationStyle) noexcept

Write a block at the given position using a combination style.

Note

Writes outside the buffer are ignored.

Parameters:
  • pos – The coordinates within the buffer.

  • block – The block value to store.

  • combinationStyle – The combination style for overwriting existing characters.

virtual void set(Position pos, const String &str) noexcept

Write a string at the given position.

NL jumps to the next row. Other control and zero-width characters are ignored. Color (even inherited) overwrites the existing characters. Use drawText(pos, text) for a color overlay.

Parameters:
  • pos – The coordinates within the buffer.

  • str – The string to write.

Public Static Attributes

static constexpr auto cMaximumSize = Size{10'000, 10'000}

Largest buffer size accepted for this buffer.

static constexpr auto cMinimumSize = Size{1, 1}

Smallest valid buffer size.

class CursorBuffer : public erbsland::cterm::RemappedBuffer, public erbsland::cterm::CursorWriter

A buffer that can be used to write text using a cursor.

Cursor movement emulates VT100 terminals:

  • Cursor movements are bound to the buffer (they do not wrap around).

  • Printing characters do wrap around if wrap mode is enabled (it’s enabled by default.)

  • Printing a character in the last column is special:

    • A 1-width character is printed in the last column, but the cursor isn’t moved yet. A wrapOnNextChar is set instead of the cursor movement.

    • As soon as the next character is printed, the cursor is moved to the next line first; then the character is printed.

    • When a 2-width character is printed in the last column, the cursor is moved to the next line first; then the character is printed (not VT100, it didn’t have 2-width characters).

    • If the wrapOnNextChar is set, and the cursor is moved, the flag is cleared.

    • If the wrapOnNextChar is set, and a line-break is printed, the flag is cleared first before moving the cursor to the next line.

Public Types

enum class OverflowMode : uint8_t

The overflow mode determines what happens when the cursor gets a line-break in the last line.

Values:

enumerator Shift

Shift the buffer content one line up, exposing a new blank line at the bottom.

enumerator Wrap

The cursor wraps back to the first line of the buffer.

enumerator ExpandThenShift

Expand the buffer by one line, keeping the content. Up to maximumSize(), then scroll.

enumerator ExpandThenWrap

Expand the buffer by one line, keeping the content. Up to maximumSize(), then wrap.

Public Functions

inline explicit CursorBuffer(const Size startSize, const OverflowMode overflowMode = OverflowMode::Shift, const Size maximumSize = cMaximumSize, const Char fillChar = Char::space())

Create a new cursor buffer with the given startSize.

Parameters:
  • startSize – The start size of the buffer.

  • overflowMode – The overflow mode of the buffer.

  • maximumSize – The maximum size of the buffer. Only height is used.

  • fillChar – The character used to initialize and refill empty cells.

Throws:

std::invalid_argument – if startSize exceeds the maximum or fillChar is not a single-width character.

inline CursorBuffer()

Create a new cursor buffer with a default size of 80x25 and overflow mode Shift.

Size maximumSize() const noexcept

Get the maximum size.

void setMaximumSize(Size maximumSize) noexcept

Change the maximum size.

Changing the maximum size will not affect the current content.

Parameters:

maximumSize – The new maximum size.

OverflowMode overflowMode() const noexcept

Get the overflow mode for this buffer.

void setOverflowMode(OverflowMode mode) noexcept

Set the overflow mode for this buffer.

Parameters:

mode – The new overflow mode.

const Char &fillChar() const noexcept

Get the character used for newly exposed or empty cells.

Returns:

The current fill character.

void setFillChar(Char fillChar)

Set the character used for newly exposed or empty cells.

The character should have a display width of one cell.

Parameters:

fillChar – The new fill character.

Throws:

std::invalid_argument – if fillChar is not a single-width character.

inline virtual Size size() const noexcept override

Get the configured size of the buffer.

Returns:

The width and height of the buffer.

virtual Color color() const noexcept override

Get the current color.

Returns:

The currently tracked terminal color state.

virtual CharAttributes charAttributes() const noexcept override

Get the current character attributes.

Returns:

The currently tracked character attribute state.

virtual void setColor(Color color) noexcept override

Set foreground and background color.

Note

Inherited colors are converted to Default colors.

Parameters:

color – The new combined color.

virtual void setCharAttributes(CharAttributes attributes) noexcept override

Set all character attributes.

Unspecified attributes are treated as disabled.

Parameters:

attributes – The new character attributes.

virtual void setForeground(Foreground color) noexcept override

Set the foreground color.

Note

Inherited colors are converted to Default colors.

Parameters:

color – The new foreground color.

virtual void setBackground(Background color) noexcept override

Set the background color.

Note

Inherited colors are converted to Default colors.

Parameters:

color – The new background color.

virtual CharAttributes supportedCharAttributes() const noexcept override

Get the character attributes supported by this writer.

Returns:

The supported character attributes.

virtual void moveCursor(Position posOrDelta, MoveMode mode) noexcept override

Move the cursor absolute or relative.

If the resulting position is out of bounds, the result is undefined.

Parameters:
  • posOrDelta – The absolute position or delta for the move.

  • mode – The move mode, either absolute or relative.

virtual void setAutoWrap(bool enabled) noexcept override

Enabled/disable auto-wrap.

Auto wrap controls if the cursor automatically wraps to the next line when reaching the right margin. This is a feature that can be enabled or disabled. Do not confuse this with line wrapping, which is a different feature.

Parameters:

enabled – Whether to enable or disable auto-wrap.

virtual void clearScreen() noexcept override

Clears the screen/writing area.

virtual void write(const Char &character) noexcept override

Write a character at the current cursor position.

Inherited color components resolve against the currently active color. Overwrites the character under the cursor.

Parameters:

character – The character to write.

virtual void write(const String &str) noexcept override

Write a string at the current cursor position.

Inherited color components in each character resolve against the currently active color. Overwrites the characters under the cursor.

Parameters:

str – The string to write.

virtual void write(const ReadableBuffer &buffer) noexcept override

Write a buffer at the current cursor position.

This will not perform any additional formatting, clipping, or processing. Each line of the buffer will be written, and a line-break added after each line.

Parameters:

buffer – The buffer to write.

virtual void writeLineBreak() noexcept override

Write a line-break.

This will move the cursor to the beginning of the next line.

virtual void setColor(Color color) noexcept = 0

Set foreground and background color.

Note

Inherited colors are converted to Default colors.

Parameters:

color – The new combined color.

inline void setColor(const Foreground foregroundColor, const Background backgroundColor) noexcept

Set foreground and background color.

Note

Inherited colors are converted to Default colors.

Parameters:
  • foregroundColor – The new foreground color.

  • backgroundColor – The new background color.

virtual void write(const Char &character) noexcept = 0

Write a character at the current cursor position.

Inherited color components resolve against the currently active color. Overwrites the character under the cursor.

Parameters:

character – The character to write.

virtual void write(const String &str) noexcept = 0

Write a string at the current cursor position.

Inherited color components in each character resolve against the currently active color. Overwrites the characters under the cursor.

Parameters:

str – The string to write.

inline void write(std::string_view text) noexcept

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

virtual void write(const ReadableBuffer &buffer) noexcept = 0

Write a buffer at the current cursor position.

This will not perform any additional formatting, clipping, or processing. Each line of the buffer will be written, and a line-break added after each line.

Parameters:

buffer – The buffer to write.

virtual void writeLineBreak() noexcept = 0

Write a line-break.

This will move the cursor to the beginning of the next line.