Interactive Line Editor

Introduction

erbsland::cterm::ReadLine provides styled interactive text editing on a full-control terminal. It supports blocking and polling lifecycles, multiline input, history, inactivity timeouts, and deterministic cleanup. See Input for complete usage and behavior.

Usage

Create the editor with erbsland::cterm::ReadLine::create(), a erbsland::cterm::TerminalPtr, and erbsland::cterm::ReadLineOptions. Use erbsland::cterm::ReadLine::waitForInput() for a blocking prompt, or combine erbsland::cterm::ReadLine::start(), erbsland::cterm::ReadLine::update(), and erbsland::cterm::ReadLine::stop() with an application loop.

Only erbsland::cterm::ReadLineStatus::Committed is successful and carries entered text. The polling-only erbsland::cterm::ReadLineStatus::Idle, cancellation, and timeout statuses carry an empty string. An active editor exclusively owns terminal output until it stops. Horizontal input padding is represented by erbsland::block::MarginPair; negative leading or trailing values are clamped to zero.

Protected Secret Entry

erbsland::cterm::ReadSecret is the parallel API for passwords and tokens. It accepts the appearance and lifecycle parts of ReadLineOptions, forces one logical and display line, rejects history and initial text, and caps input at 1024 Unicode code points. It renders a fixed bullet mask and transports a marked String through ReadLineResult.

Interface

class ReadLine

An interactive terminal line editor.

A read-line operation exclusively owns terminal output between start() and stop().

See: Input

Subclassed by erbsland::cterm::impl::ReadLine

Public Functions

virtual void start() = 0

Start a non-blocking read-line operation.

Throws:

err::RuntimeError – if already active or interactive full-control output is unavailable.

virtual ReadLineResult update() = 0

Poll and update an active read-line operation.

Terminal results remain latched until stop() is called.

Throws:

err::RuntimeError – if no operation is active.

Returns:

Idle, Committed, Cancelled, or Timeout.

virtual ReadLineResult waitForInput() = 0

Run a complete blocking read-line operation.

This method never returns Idle and always stops the operation before returning or propagating an exception.

Throws:

err::RuntimeError – if already active or interactive full-control output is unavailable.

Returns:

Committed, Cancelled, or Timeout.

virtual void stop() noexcept = 0

Stop the operation and restore or retain the rendered input area according to the cleanup option.

Calling this method while inactive has no effect.

virtual bool isActive() const noexcept = 0

Test if an operation is active.

Public Static Functions

static ReadLinePtr create(TerminalPtr terminal, ReadLineOptions options = {})

Create an interactive terminal line editor.

Text and history are copied and normalized to the configured limits.

Parameters:
  • terminal – The terminal retained for the lifetime of this object.

  • options – The appearance and editing options.

Throws:

err::ParameterError – if terminal is null or options is structurally invalid.

Returns:

The new line editor.

using erbsland::cterm::ReadLinePtr = std::shared_ptr<ReadLine>

A shared pointer to an interactive terminal line editor.

enum class erbsland::cterm::ReadLineDisplayStyle : std::uint8_t

The layout used to display an interactive read-line area.

Values:

enumerator Compact

Title and input rows without trailing spacing or a frame.

enumerator HorizontalSpace

Compact layout followed by one empty row.

enumerator HorizontalFrame

Title in a top horizontal border and a bottom horizontal border.

enumerator Frame

A complete frame around the title and input rows.

class ReadLineOptions

Options for an interactive read-line operation.

Text limits are applied to private copies when a ReadLine is constructed, making setter order irrelevant.

Public Functions

ReadLineOptions()

Create options with the standard interactive read-line appearance.

inline const BlockStyle &backgroundStyle() const noexcept

Get the input-area background style.

ReadLineOptions &setBackgroundStyle(BlockStyle style) noexcept

Set the input-area background style.

inline const BlockStyle &titleStyle() const noexcept

Get the title style.

ReadLineOptions &setTitleStyle(BlockStyle style) noexcept

Set the title style.

inline const BlockStyle &promptStyle() const noexcept

Get the prompt style.

ReadLineOptions &setPromptStyle(BlockStyle style) noexcept

Set the prompt style.

inline const BlockStyle &placeholderStyle() const noexcept

Get the placeholder style.

ReadLineOptions &setPlaceholderStyle(BlockStyle style) noexcept

Set the placeholder style.

inline const BlockStyle &textStyle() const noexcept

Get the entered-text style.

ReadLineOptions &setTextStyle(BlockStyle style) noexcept

Set the entered-text style.

inline const BlockStyle &cursorStyle() const noexcept

Get the cursor style used over visible text.

ReadLineOptions &setCursorStyle(BlockStyle style) noexcept

Set the cursor style used over visible text.

inline ReadLineDisplayStyle displayStyle() const noexcept

Get the display layout.

ReadLineOptions &setDisplayStyle(ReadLineDisplayStyle style) noexcept

Set the display layout.

inline const FrameBorder &frameBorder() const noexcept

Get the frame border.

ReadLineOptions &setFrameBorder(FrameBorder border) noexcept

Set the frame border.

inline const block::MarginPair &padding() const noexcept

Get the horizontal input padding.

ReadLineOptions &setPadding(block::MarginPair padding) noexcept

Set the input padding.

Negative values are clamped to zero.

inline const BlockString &title() const noexcept

Get the title.

ReadLineOptions &setTitle(BlockString title) noexcept

Set the title.

ReadLineOptions &setTitle(const text::String &title)

Set the title from plain text.

inline const BlockString &prompt() const noexcept

Get the prompt.

ReadLineOptions &setPrompt(BlockString prompt) noexcept

Set the prompt.

ReadLineOptions &setPrompt(const text::String &prompt)

Set the prompt from plain text.

inline const BlockString &placeholder() const noexcept

Get the placeholder.

ReadLineOptions &setPlaceholder(BlockString placeholder) noexcept

Set the placeholder.

ReadLineOptions &setPlaceholder(const text::String &placeholder)

Set the placeholder from plain text.

inline unit::CpLength maximumLength() const noexcept

Get the maximum entered-text length in code points.

ReadLineOptions &setMaximumLength(unit::CpLength maximumLength) noexcept

Set the maximum entered-text length in code points.

inline unit::LineCount maximumLines() const noexcept

Get the maximum logical line count.

ReadLineOptions &setMaximumLines(unit::LineCount maximumLines)

Set the maximum logical line count.

Throws:

err::ParameterError – if the count is zero.

inline unit::LineCount maximumDisplayLines() const noexcept

Get the maximum displayed edit-row count.

ReadLineOptions &setMaximumDisplayLines(unit::LineCount maximumDisplayLines)

Set the maximum displayed edit-row count.

Throws:

err::ParameterError – if the count is zero.

inline const text::StringList &history() const noexcept

Get the history entries.

ReadLineOptions &setHistory(text::StringList history) noexcept

Replace the history entries.

inline const text::String &currentText() const noexcept

Get the initial text.

ReadLineOptions &setCurrentText(text::String currentText) noexcept

Set the initial text.

inline time::Seconds timeout() const noexcept

Get the inactivity timeout.

Zero disables the timeout.

ReadLineOptions &setTimeout(time::Seconds timeout)

Set the inactivity timeout.

Throws:

err::ParameterError – if the timeout is negative.

inline time::Seconds timeoutDisplayThreshold() const noexcept

Get the remaining-time threshold for displaying the timeout countdown.

Zero disables the countdown display.

ReadLineOptions &setTimeoutDisplayThreshold(time::Seconds timeoutDisplayThreshold)

Set the remaining-time threshold for displaying the timeout countdown.

Parameters:

timeoutDisplayThreshold – The non-negative display threshold.

Throws:

err::ParameterError – if the threshold is negative.

Returns:

This options object.

inline time::Milliseconds blinkInterval() const noexcept

Get the cursor blink interval.

ReadLineOptions &setBlinkInterval(time::Milliseconds blinkInterval)

Set the cursor blink interval.

Throws:

err::ParameterError – if the interval is not positive.

inline const Block &cursorBlock() const noexcept

Get the cursor block used over empty space.

ReadLineOptions &setCursorBlock(Block cursorBlock)

Set the cursor block used over empty space.

Throws:

err::ParameterError – if the block does not occupy exactly one terminal cell.

inline const Key &commitKey() const noexcept

Get the key that commits entered text.

ReadLineOptions &setCommitKey(Key commitKey) noexcept

Set the key that commits entered text.

inline const Key &newLineKey() const noexcept

Get the key that inserts a logical line break.

ReadLineOptions &setNewLineKey(Key newLineKey) noexcept

Set the key that inserts a logical line break.

inline const Key &cancelKey() const noexcept

Get the key that cancels input.

ReadLineOptions &setCancelKey(Key cancelKey) noexcept

Set the key that cancels input.

inline bool cleanupEnabled() const noexcept

Test if the input area is removed when the operation stops.

ReadLineOptions &setCleanupEnabled(bool cleanupEnabled) noexcept

Enable or disable removal of the input area when the operation stops.

using erbsland::cterm::ReadLineResult = util::ResultWithData<text::String, ReadLineStatus>

An interactive read-line result with committed text.

Only ReadLineStatus::Committed transports text; all other states transport an empty string.

class ReadLineStatus : public erbsland::util::Result

The status of an interactive read-line operation.

Only Committed is a successful util::Result; all other states carry no caller-visible text.

Public Functions

inline constexpr bool operator==(const ReadLineStatus &other) const noexcept

Compare two read-line status values.

inline constexpr bool isCommitted() const noexcept

Test if text was committed.

inline constexpr bool isIdle() const noexcept

Test if a non-blocking update found no terminal result.

inline constexpr bool isCancelled() const noexcept

Test if the user cancelled the operation.

inline constexpr bool isTimeout() const noexcept

Test if the inactivity timeout expired.

inline constexpr Result(const Value value)

Create a new result.

Parameters:

value – The value of the result.

Public Static Attributes

static const ReadLineStatus Committed = Value::success<0>()

The user committed the entered text.

static const ReadLineStatus Idle = Value::failure<0>()

No terminal result is available yet.

static const ReadLineStatus Cancelled = Value::failure<1>()

The user cancelled the operation.

static const ReadLineStatus Timeout = Value::failure<2>()

The inactivity timeout expired.

class ReadSecret

An interactive, securely erased single-line secret editor.

Entered code points are retained in fixed protected storage and only a fixed bullet mask is rendered.

See: Input

Subclassed by erbsland::cterm::impl::ReadSecret

Public Functions

virtual void start() = 0

Start interactive secret input.

virtual ReadLineResult update() = 0

Process available terminal input and return its result.

virtual ReadLineResult waitForInput() = 0

Wait for input, process it, and return its result.

virtual void stop() noexcept = 0

Stop interactive secret input.

virtual bool isActive() const noexcept = 0

Test if secret input is active.

Public Static Functions

static ReadSecretPtr create(TerminalPtr terminal, ReadLineOptions options = {})

Create a protected single-line terminal editor.

The requested maximum length is capped at 1024 code points. History and initial text must be empty.

Throws:

err::ParameterError – If the terminal is null or unsupported options contain history or initial text.