Terminal
The terminal classes provide the runtime connection between your rendered
content and the real console. Terminal manages the application
lifecycle, refresh strategy, cursor control, direct text output, and the
platform backend that ultimately emits text and control sequences.
This section focuses on application-level terminal control. For the
shared streaming output API used by both
Terminal and
CursorBuffer, see
Cursor Output. For custom backend implementations and capability
fallback behavior, see Backend.
Usage
Preparing and Rendering a Screen
Terminal is the high-level entry point for full-screen terminal
applications. It owns the platform backend, manages the visible screen
state, and renders ReadableBuffer objects with clipping and optional
crop marks.
auto terminal = Terminal{Size{90, 28}};
terminal.initializeScreen();
terminal.setRefreshMode(Terminal::RefreshMode::Overwrite);
auto buffer = Buffer{terminal.size()};
buffer.fill(Char{" ", Color{fg::Default, bg::Black}});
buffer.drawText(
"Frame and buffer rendering",
Rectangle{2, 2, buffer.size().width() - 4, 5},
Alignment::Center,
Color{fg::BrightWhite, bg::Blue});
auto settings = UpdateSettings{};
settings.setSwitchToAlternateBuffer(false);
terminal.updateScreen(buffer, settings);
terminal.flush();
terminal.restoreScreen();
Terminal::size() returns the drawable size used by
updateScreen(). By default, this includes a one-column and one-row
compatibility margin so full-screen buffers work out of the box.
Disable that margin with setSafeMarginEnabled(false) if you want to
use the full detected terminal size and rely purely on cursor-based
updates.
For short-lived tools that should leave their output in the normal
terminal history, disable alternate-screen switching via
UpdateSettings as shown above.
Render Loop for Interactive Applications
The following example shows a minimal render loop for an interactive terminal application.
struct MyApp {
void renderFrame() {
_terminal.testScreenSize();
_buffer.resize(_terminal.size());
_buffer.fill(Char{" ", bg::Black});
// Draw the current frame into the buffer.
_terminal.updateScreen(_buffer, _updateSettings);
}
void handleKey(Key key) {
if (key == Key{Key::Character, U'q'}) {
_quitRequested = true;
}
}
void run() {
_terminal.initializeScreen();
_terminal.input().setMode(Input::Mode::Key);
_updateSettings.setMinimumSize(Size{40, 20});
_updateSettings.setMinimumSizeMessage(String("Too Small!"));
while (!_quitRequested) {
const auto key = _terminal.input().read(std::chrono::milliseconds{90});
if (key.valid()) {
handleKey(key);
}
renderFrame();
}
_terminal.restoreScreen();
}
Terminal _terminal;
Buffer _buffer;
UpdateSettings _updateSettings;
bool _quitRequested;
};
Call Terminal::initializeScreen()
once when your application starts, and
Terminal::restoreScreen()
once just before it exits.
After initialization, use
Terminal::isInteractive()
to detect whether a real terminal is attached. This allows you to switch
to a plain-text fallback when output is redirected.
If your application is interrupted (for example via Ctrl+C), the
library restores the terminal state automatically before returning
control to the shell.
Create exactly one Terminal instance
for the lifetime of your application. While multiple instances are
possible, they share the same underlying backend, so a single instance is
simpler and safer.
For interactive programs, switch the input mode to
Input::Mode::Key. This hides the cursor and lets your application
react to individual key presses via input().read(). The timeout also
serves as a natural frame rate control.
Keep a persistent Buffer instance, resize it to the current terminal
size, and reuse it for each frame. After drawing into the buffer, call
updateScreen() to present the new frame.
By default, rendering is optimized to update only the parts of the screen that actually changed. This makes frequent refresh rates practical, as only modified regions are written to the terminal.
Direct Writes, Line Buffering, and Refresh Modes
For simpler tools and status output, you can use
Terminal without a full-screen buffer.
print(), printLine(), and write() send text directly to the
terminal while still applying color handling.
These direct-write functions are part of the shared
CursorWriter interface. This page
focuses on how they behave on a real terminal; the reusable streaming
API itself is documented on Cursor Output.
terminal.setOutputMode(Terminal::OutputMode::FullControl);
terminal.printLine(fg::BrightGreen, "Service started");
terminal.print("Current mode: ", fg::BrightYellow, "interactive");
terminal.writeLineBreak();
terminal.flush();
Line buffering keeps partial lines in memory until a newline is written
or flush() is called. This keeps incremental output clean and avoids
fragmented lines.
For full-screen applications:
RefreshMode::Clearclears the entire screen before each frame.RefreshMode::Overwritemoves to the home position and works with the back buffer for efficient updates.
Controlling Screen Update Settings
UpdateSettings controls how
Terminal::updateScreen()
behaves when content does not fit the terminal or the terminal is too
small.
auto settings = UpdateSettings{};
settings.setMinimumSize(Size{60, 18});
settings.setMinimumSizeBackground(Char{" ", Color{fg::Inherited, bg::Red}});
settings.setMinimumSizeMessage(String{"Please enlarge the terminal"});
settings.setShowCropMarks(true);
terminal.updateScreen(buffer, settings);
Use this to define minimum sizes, customize fallback backgrounds, and control crop indicators when the layout cannot be rendered as intended.
Output Modes
Terminal supports two output modes:
Terminal::OutputMode::FullControl(default) enables colored output, cursor control, refresh handling, back-buffer updates, and terminal-size detection.Terminal::OutputMode::Textkeeps the terminal in plain-text mode. In this mode,write()andprint()still work, but cursor control, refresh handling, screen clearing, size detection, and the back buffer are disabled.
The terminal always owns a backend internally, but most applications can treat it as an implementation detail and rely on the high-level API.
If you need to inject a custom backend or understand capability fallback behavior, continue with Backend.
Interface
-
class UpdateSettings
Settings controlling how
Terminal::updateScreen()renders a buffer.Public Functions
-
UpdateSettings() = default
Create default screen update settings.
-
Size minimumSize() const noexcept
Get the minimum terminal size required for rendering the buffer.
- Returns:
The minimum supported terminal size.
-
void setMinimumSize(Size minimumSize) noexcept
Set the minimum terminal size required for rendering the buffer.
- Parameters:
minimumSize – The minimum supported terminal size.
-
const Char &minimumSizeBackground() const noexcept
Get the background character used if the terminal is too small.
-
void setMinimumSizeBackground(Char character) noexcept
Set the background fill character when the terminal is too small.
- Parameters:
character – The background character
-
const String &minimumSizeMessage() const noexcept
Get the message displayed if the terminal size is too small.
-
void setMinimumSizeMessage(String message) noexcept
Set the message displayed if the terminal is too small.
- Parameters:
message – The displayed message.
-
bool showCropMarks() const noexcept
Check if crop marks are enabled.
-
void setShowCropMarks(bool showCropMarks) noexcept
Enable or disable crop marks.
- Parameters:
showCropMarks –
trueto render crop marks for truncated content.
-
const Char &cropMarkRight() const noexcept
Get the mark rendered when content is cropped on the right.
-
void setCropMarkRight(Char cropMarkRight) noexcept
Set the mark rendered if the content is cropped on the right.
- Parameters:
cropMarkRight – The right crop mark.
-
const Char &cropMarkBottomRight() const noexcept
Get the mark rendered in the bottom right corner when content is cropped.
-
void setCropMarkBottomRight(Char cropMarkBottomRight) noexcept
Set the mark in the bottom right corner if content is cropped on the bottom and right.
- Parameters:
cropMarkBottomRight – The bottom-right crop mark.
-
const Char &cropMarkBottom() const noexcept
Get the mark rendered when content is cropped at the bottom.
-
void setCropMarkBottom(Char cropMarkBottom) noexcept
Set the mark rendered if the content is cropped at the bottom.
- Parameters:
cropMarkBottom – The bottom crop mark.
-
bool switchToAlternateBuffer() const noexcept
Test if the update shall switch to the alternate screen buffer.
-
void setSwitchToAlternateBuffer(bool switchToAlternateBuffer) noexcept
Enable or disable switching to the alternate screen buffer.
- Parameters:
switchToAlternateBuffer –
trueto switch to the alternate screen buffer.
-
void applyTo(BufferViewBase &view) const noexcept
Apply these settings to a BufferView.
-
void setMinimumSizeMark(Char minimumSizeMark) noexcept
Set the minimum-size background character through the legacy name.
- Deprecated:
Use
setMinimumSizeBackground()instead.
- Parameters:
minimumSizeMark – The background character shown when the terminal is too small.
-
const Char &minimumSizeMark() const noexcept
Get the minimum-size background character through the legacy name.
- Deprecated:
Use
minimumSizeBackground()instead.
- Returns:
The background character shown when the terminal is too small.
-
UpdateSettings(Size minimumSize, Char minimumSizeBackground, bool showCropMarks, Char cropMarkRight, Char cropMarkBottom) noexcept
Construct update settings using the deprecated aggregate-style compatibility constructor.
- Deprecated:
Construct
UpdateSettings{}and configure it with setters instead.
- Parameters:
minimumSize – The minimum terminal size required for normal rendering.
minimumSizeBackground – The fill character for the size-too-small background.
showCropMarks –
trueto show crop marks for truncated content.cropMarkRight – The crop mark to draw at the right edge.
cropMarkBottom – The crop mark to draw at the bottom edge.
Public Static Functions
-
static const UpdateSettings &defaultSettings() noexcept
Shared default value.
-
UpdateSettings() = default
-
class Terminal : public erbsland::cterm::CursorWriter
High-level terminal interface for screen control, color output, and key input.
Public Types
-
enum class RefreshMode : uint8_t
Screen clearing strategy used between rendered frames.
Values:
-
enumerator Keep
Do not emit cursor or clear-screen control sequences automatically.
-
enumerator Clear
Clear the full screen before rendering the next frame.
-
enumerator Overwrite
Move the cursor to the top-left corner before rendering the next frame.
-
enumerator Keep
Public Functions
-
explicit Terminal()
Create a new terminal instance with default values.
-
explicit Terminal(TerminalFlags flags = {})
Create a new terminal instance.
- Parameters:
flags – The terminal flags to use.
-
explicit Terminal(Size size = {80, 25}, TerminalFlags flags = {})
Create a new terminal instance.
The size is automatically bounded to the minimum and maximum supported sizes.
- Parameters:
size – The fallback terminal size used when automatic detection is unavailable.
flags – The terminal flags to use.
-
explicit Terminal(BackendPtr backend, Size size = {80, 25})
Create a new terminal instance with a custom backend.
The size is automatically bounded to the minimum and maximum supported sizes.
- Parameters:
backend – The backend to use for the terminal.
size – The fallback terminal size used when automatic detection is unavailable.
-
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
Inheritedcolors are converted toDefaultcolors.- 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
Inheritedcolors are converted toDefaultcolors.- Parameters:
color – The new foreground color.
-
virtual void setBackground(Background color) noexcept override
Set the background color.
Note
Inheritedcolors are converted toDefaultcolors.- 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 moveLeft(Coordinate count) noexcept override
Move the cursor to the left.
If the resulting position is out of bounds, the result is undefined.
- Parameters:
count – The number of terminal cells to move.
-
virtual void moveRight(Coordinate count) noexcept override
Move the cursor to the right.
If the resulting position is out of bounds, the result is undefined.
- Parameters:
count – The number of terminal cells to move.
-
virtual void moveUp(Coordinate count) noexcept override
Move the cursor up.
If the resulting position is out of bounds, the result is undefined.
- Parameters:
count – The number of terminal cells to move.
-
virtual void moveDown(Coordinate count) noexcept override
Move the cursor down.
If the resulting position is out of bounds, the result is undefined.
- Parameters:
count – The number of terminal cells to move.
-
virtual void moveTo(Position pos) noexcept override
Move the cursor to the given position.
If the resulting position is out of bounds, the result is undefined.
- Parameters:
pos – The position to move the cursor to.
-
virtual void moveHome() noexcept override
Moves the cursor to the home position.
-
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 setCursorVisible(bool visible) noexcept override
Make the cursor visible/invisible.
Not all implementations support changing the cursor visibility.
- Parameters:
visible – Whether to make the cursor visible or invisible.
-
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.
-
void setSize(Size size) noexcept
Modify the size of the terminal.
The size is automatically bounded to the minimum and maximum supported sizes. If size detection is enabled, the terminal size will be automatically detected and updated.
- Parameters:
size – The new terminal size.
-
inline RefreshMode refreshMode() const noexcept
Get the refresh mode.
-
inline void setRefreshMode(const RefreshMode mode) noexcept
Set the refresh mode.
- Parameters:
mode – The screen refresh strategy to use.
-
inline OutputMode outputMode() const noexcept
Get the current output mode for the terminal.
-
void setOutputMode(OutputMode outputMode) noexcept
Set the output mode.
Switching to
OutputMode::Textdisables size detection, refresh modes, and back-buffer updates.- Parameters:
outputMode – The output mode to set.
-
bool sizeDetectionEnabled() const noexcept
Check whether dynamic terminal size detection is enabled.
-
void setSizeDetectionEnabled(bool enabled) noexcept
Set if dynamic terminal size detection is enabled.
Can only be enabled while the output mode is
OutputMode::FullControl.- Parameters:
enabled –
trueto enable automatic size detection.
-
bool lineBufferEnabled() const noexcept
Check whether line buffering is enabled for incremental writes.
- Returns:
trueif text output is collected until a newline orflush().
-
void setLineBufferEnabled(bool enabled) noexcept
Enable or disable line buffering for incremental writes.
When enabled, output is accumulated until a newline or
flush()is reached. Line buffering can only be enabled if the backend supports both color and cursor ANSI codes.- Parameters:
enabled –
trueto enable buffered writes.
-
bool safeMarginEnabled() const noexcept
Check whether the compatibility safe margin is enabled.
- Returns:
trueif one column and one row are reserved from the detected terminal size.
-
void setSafeMarginEnabled(bool enabled) noexcept
Enable or disable the compatibility safe margin.
When enabled, the reported drawable size is reduced by one column and one row. Disable this only when the terminal should use its full detected size and newline-free screen updates.
- Parameters:
enabled –
trueto reserve one column and one row from the terminal size.
-
bool backBufferEnabled() const noexcept
Check whether the optional back buffer is enabled for smart overwrite updates.
- Returns:
trueifupdateScreen()keeps the previous rendered frame for diff-based updates.
-
void setBackBufferEnabled(bool enabled) noexcept
Enable or disable the optional back buffer used by smart overwrite updates.
Enabling the back buffer forces the next
updateScreen()call to redraw the full frame once. Can only be enabled while the output mode isOutputMode::FullControl.- Parameters:
enabled –
trueto enable the back buffer.
-
void setBackend(BackendPtr backend) noexcept
Set a custom backend for the terminal.
- Parameters:
backend – The backend to use for the terminal. If
nullptris passed, the default backend is restored.
-
Input &input() noexcept
Access the input interface.
- Returns:
The platform-specific input backend owned by this terminal.
-
void initializeScreen() noexcept
Initialize the console once before the application starts.
Applies platform-specific setup, optionally clears the screen, and tests for the initial screen size. Also hides the cursor by default, as it is usually only made visible when the user makes input. Call this at the start of your application.
-
bool isInteractive() const noexcept
Check whether an interactive terminal is attached to the process.
Call this after
initializeScreen()to see if screen-size detection and terminal control features are active.- Returns:
trueif the backend detected an interactive terminal.
-
void testScreenSize() noexcept
Detect terminal resize changes.
After calling this method,
size()returns a safe size for the terminal.
-
void restoreScreen() noexcept
Restore terminal settings when the application is quit.
Call this at the end of your application. This should restore the terminal to its original state, including cursor visibility and any other settings that were modified during initialization.
-
virtual void clearScreen() noexcept override
Clears the screen.
In
OutputMode::Text, this method has no effect. If you need the screen cleared immediately, callflush()after this method.
-
bool isAlternateScreenActive() const noexcept
Test if the alternate screen is active.
This is no terminal detection, it just returns the internal state.
-
void setAlternateScreen(bool enabled) noexcept
Activate or deactivate the alternate screen.
If activated or deactivated, the buffer is immediately flushed to the terminal.
-
void updateScreen(const ReadableBuffer &buffer, const UpdateSettings &settings = {}) noexcept
Render a buffer onto the terminal.
The buffer is clipped to the drawable area reported by
size()and optionally annotated with crop marks. If the terminal is smaller than the configured minimum size, only the minimum-size marker is rendered. WhenswitchToAlternateBufferistrueand the alternate screen is not active, this call first switches to the alternate screen and then renders the buffer.- Parameters:
buffer – The buffer to render.
settings – Additional rendering settings for crop marks and minimum terminal size handling.
-
void flush() noexcept
Flush the all buffer immediately to the terminal.
-
inline void lineBreak() noexcept
Write a terminal line break.
- Deprecated:
Use
writeLineBreak()instead.
-
inline bool colorEnabled() const noexcept
Test if non-text output mode is active.
- Deprecated:
Use
outputMode()instead.
- Returns:
trueif the terminal is not inOutputMode::Text.
-
void setColorEnabled(bool enabled) noexcept
Enable or disable text-only output mode through the legacy boolean API.
- Deprecated:
Use
setOutputMode()instead.
- Parameters:
enabled –
trueto allow color/control output,falsefor plain text mode.
-
virtual void setColor(Color color) noexcept = 0
Set foreground and background color.
Note
Inheritedcolors are converted toDefaultcolors.- Parameters:
color – The new combined color.
-
inline void setColor(const Foreground foregroundColor, const Background backgroundColor) noexcept
Set foreground and background color.
Note
Inheritedcolors are converted toDefaultcolors.- 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.
-
enum class RefreshMode : uint8_t
-
using erbsland::cterm::TerminalPtr = std::shared_ptr<Terminal>
Shared pointer to a terminal instance.
-
enum class erbsland::cterm::TerminalFlag : uint8_t
A terminal flag.
Values:
-
enumerator NoSignalHandling
Disables signal handling to restore the screen when the application is terminated.
If this flag is set, you must ensure that the
restoreScreen()method is called when the application is terminated by a signal. Otherwise, the terminal will not be restored properly.
-
enumerator NoSignalHandling
-
class TerminalFlags
A set of terminal flags.
Terminal flags control the behavior of the built-in terminal backend. These flags can only be set at construction time and cannot be modified after that.
Public Types
-
using Mask = uint8_t
Unsigned storage type used for the combined flag bits.
-
using Enum = TerminalFlag
The enum type combined by this flag set.
Public Functions
-
template<typename ...tFlags>
inline constexpr TerminalFlags(tFlags... flags) Create a combined set of flags.
-
inline TerminalFlags operator|(const TerminalFlag flag) const
Combine this flag set with one additional flag.
- Parameters:
flag – The flag to add.
- Returns:
The combined flag set.
-
inline bool has(const TerminalFlag flag) const noexcept
Test if a flag is set.
-
inline void set(const TerminalFlag flag, const bool enabled = true)
Set a flag.
-
inline void clear(const TerminalFlag flag)
Clear a flag.
Friends
-
inline friend TerminalFlags operator|(const TerminalFlag flag, const TerminalFlags flags)
Combine one flag with an existing flag set.
- Parameters:
flag – The flag to add.
flags – The existing flag set.
- Returns:
The combined flag set.
-
inline friend TerminalFlags operator|(const TerminalFlags flags1, const TerminalFlags flags2)
Combine two flag sets.
- Parameters:
flags1 – The first flag set.
flags2 – The second flag set.
- Returns:
The combined flag set.
-
using Mask = uint8_t