Terminal Document Renderer
Introduction
The terminal document renderer writes text::TextDocument and text::TextNode trees as styled terminal text.
TerminalDocumentStyle describes text style overlays, paragraph layout, decorations, and list markers with selectors
that match text::TextNodeType values directly.
Usage
Use TerminalDocumentRenderer when semantic document nodes should be rendered to a CursorWriter.
The renderer keeps the current style by value, so a renderer can be reused for repeated render calls.
The writer width selects the layout width once at the start of a render. Reported widths of 60 columns or more are used directly. Widths from 1 through 59, an unknown width, and zero select an 80-column layout. A narrower destination may wrap these completed lines naturally. There is no separate narrow-output layout.
Use TerminalDocumentStyle to customize the default text style, base block layout, and selector-specific rules.
Rules use BlockStyle for terminal text style overlays and ParagraphIndents with block::Margins for
layout.
Prefixes, suffixes, and markers are exposed as read-only BlockString values.
Selectors may constrain a rule to nodes below an ancestor node type. Ancestor matching considers the complete parent chain, which allows a diagnostic title inside a block quote to differ from the top-level title.
Container Decorations
For structural containers, prefix and suffix are standalone lines outside the content.
linePrefix is prepended to each logical content line.
Nested containers combine their line prefixes from outermost to innermost, which is useful for reply-style quote
borders.
Structured Fields and Inline Paths
FieldList contains FieldItem nodes made from FieldLabel and FieldContent.
Labels occupy an aligned column while they fit within one quarter of the available width.
Unstacked content begins one column after the widest rendered label, including its trailing colon.
If any label exceeds that threshold, the whole list uses stacked values with an eight-column continuation indent.
Nested field lists add four columns of indentation.
Separator and EscapeSequence are generic inline semantic nodes.
Separators are styled wrapping opportunities that remain on the preceding line; escape sequences remain indivisible.
These semantics are represented as source-relative metadata.
The renderer does not insert hidden Unicode characters into the text.
Consecutive inline children of a list item form one semantic paragraph.
Inline style boundaries such as Strong or Emphasis therefore do not introduce physical line breaks; only block
children and explicit line-break nodes do.
The default system-output style renders cause headings and their frame as non-bold bright black.
When terminal styling is unavailable, the plain renderer preserves diagnostic structure with Error: on the root,
colons on headings, two-space content indentation, nested cause indentation, and │ code gutters.
Implementation Notes
The renderer has one forward data flow:
TextDocument
-> semantic inline content
-> logical blocks
-> styled physical lines
-> CursorWriter
The inline builder traverses each text-bearing node in prefix, direct text, children, suffix order.
Alongside the styled text it records soft-break boundaries for Separator nodes and indivisible source ranges for
EscapeSequence nodes.
The block builder resolves selectors, text styles, margins, paragraph indents, list markers, and the ordered path of active container frames. A logical block stores only these resolved values; it does not retain mutable style rules or output-specific offsets.
The document layout owns width calculation, vertical margin collapse, paragraph wrapping, field columns, and frame
composition.
Paragraph content is wrapped at the width remaining after frame and child margins.
Each finished content line is then composed in this order: outer container spacing, ordered frame prefixes, child
margin, paragraph or list indentation, and content.
Blank lines inside a frame use the active frame prefix, which keeps borders continuous.
Paragraph line construction uses the same internal paragraph Printer as direct cursor paragraph output; buffer
painting remains fragment-based because its colors may depend on target cells.
Only after every physical line has been materialized does the writer adapter emit output. It performs no layout and writes exactly one styled line plus one line break per physical line. New block kinds can therefore extend the block builder and physical-line materializer without adding another sink or traversal mode.
The core invariants are:
layout width is selected once per render;
semantic indices always refer to unmodified inline source text;
frames and margins never participate in paragraph tokenization;
vertical margin collapse occurs only between logical blocks;
output starts only after all physical lines have been built.
Interface
-
class TerminalDocumentRenderer
Render a
text::TextDocumenttree as styled terminal output.A reported writer width of at least 60 cells is used as-is. Widths from 1 through 59, unknown widths, and zero widths use an 80-column layout; a narrow destination may wrap the completed physical lines naturally. The complete document layout is materialized before output begins, so allocation or layout failures do not partially write the document.
Public Functions
-
TerminalDocumentRenderer()
Create a renderer with the plain default style.
-
explicit TerminalDocumentRenderer(TerminalDocumentStyle style)
Create a renderer with the given style sheet.
- Parameters:
style – The document style to use.
-
inline const TerminalDocumentStyle &style() const noexcept
Access the current document style.
- Returns:
The current document style.
-
void setStyle(TerminalDocumentStyle style) noexcept
Replace the current document style.
- Parameters:
style – The new document style.
-
void renderTo(CursorWriter &writer, const text::TextDocument &document) const
Render a document to a cursor writer.
The writer receives one completed styled line followed by one line break for every physical document line.
- Parameters:
writer – The output writer.
document – The document to render.
- Throws:
std::bad_alloc – If intermediate layout storage cannot be allocated. The writer remains unchanged.
-
void renderTo(CursorWriter &writer, const text::TextNode &node) const
Render a node tree to a cursor writer.
The writer receives one completed styled line followed by one line break for every physical document line.
- Parameters:
writer – The output writer.
node – The root node to render.
- Throws:
std::bad_alloc – If intermediate layout storage cannot be allocated. The writer remains unchanged.
-
TerminalDocumentRenderer()
-
class TerminalDocumentStyle
A selector-driven terminal document style sheet.
Public Types
Public Functions
-
TerminalDocumentStyle()
Create the default plain document style.
-
inline BlockStyle baseTextStyle() const noexcept
Get the base text style.
-
void setBaseTextStyle(BlockStyle style)
Replace the base text style.
- Parameters:
style – The new base text style.
-
inline const ParagraphIndents &baseBlockLayout() const noexcept
Get the base block layout.
-
void setBaseBlockLayout(ParagraphIndents layout)
Replace the base block layout.
- Parameters:
layout – The new base block layout.
-
std::optional<std::reference_wrapper<const TerminalDocumentStyleRule>> definition(const TerminalDocumentStyleSelector &selector) const noexcept
Access one exact stored rule definition.
- Parameters:
selector – The selector to query.
- Returns:
The stored rule, if present.
-
TerminalDocumentStyleRule &edit(const TerminalDocumentStyleSelector &selector)
Create or access one exact stored rule definition.
New definitions are initialized from the currently resolved rule for the same selector.
- Parameters:
selector – The selector to edit.
- Returns:
A mutable reference to the stored rule.
-
void erase(const TerminalDocumentStyleSelector &selector) noexcept
Remove one exact stored rule definition.
- Parameters:
selector – The selector to erase.
-
auto resolve(const TerminalDocumentStyleSelector &selector, const TerminalDocumentStyleSelector::TokenList &contextTokens = {}, const std::vector<text::TextNodeType> &ancestors = {}) const -> TerminalDocumentStyleRule
Resolve the best matching rule.
- Parameters:
selector – The requested selector.
contextTokens – Additional style tokens from the current node.
ancestors – Node types in the parent chain, from root to direct parent.
- Returns:
The resolved rule.
Public Static Functions
-
static const TerminalDocumentStyle &defaultStyle(Predefined predefined = Predefined::Plain) noexcept
Access a predefined default style.
- Parameters:
predefined – The predefined style variant.
-
static const TerminalDocumentStyle &defaultPlain() noexcept
Access the plain default style.
-
static const TerminalDocumentStyle &defaultSimple() noexcept
Access the simple default style.
-
static const TerminalDocumentStyle &defaultStyled() noexcept
Access the styled default style.
-
static const TerminalDocumentStyle &defaultSystemOutput() noexcept
Access the application system-output default style.
-
TerminalDocumentStyle()
-
class TerminalDocumentStyleMarker
A visible marker used for bullet and numbered terminal document list items.
Public Types
Public Functions
-
TerminalDocumentStyleMarker() = default
Create an empty marker.
-
inline BlockStyle style() const noexcept
Get the marker style overlay.
-
inline BlockString literal() const noexcept
Get the literal marker text.
-
inline BlockString suffix() const noexcept
Get the ordered-list suffix text.
-
TerminalDocumentStyleMarker &clear() noexcept
Clear the marker.
- Returns:
Reference to this marker.
-
TerminalDocumentStyleMarker &setStyle(BlockStyle style) noexcept
Set the marker style overlay.
- Parameters:
style – The marker style overlay.
- Returns:
Reference to this marker.
-
TerminalDocumentStyleMarker &setLiteral(BlockString literal, BlockStyle style = {}) noexcept
Use a literal marker string.
- Parameters:
literal – The literal marker text.
style – Optional marker style overlay.
- Returns:
Reference to this marker.
-
TerminalDocumentStyleMarker &setLiteral(const text::U32String &literal, BlockStyle style = {})
Use a literal marker string.
- Parameters:
literal – The literal marker text.
style – Optional marker style overlay.
- Returns:
Reference to this marker.
-
TerminalDocumentStyleMarker &setLiteral(const text::String &literal, BlockStyle style = {})
Use a literal marker string.
- Parameters:
literal – The literal marker text.
style – Optional marker style overlay.
- Returns:
Reference to this marker.
-
TerminalDocumentStyleMarker &setOrdered()
Use an ordered marker with the default suffix and style.
- Returns:
Reference to this marker.
-
TerminalDocumentStyleMarker &setOrdered(BlockString suffix, BlockStyle style = {})
Use an ordered marker with the given suffix.
- Parameters:
suffix – The suffix appended after the item number.
style – Optional marker style overlay.
- Returns:
Reference to this marker.
-
TerminalDocumentStyleMarker &setOrdered(const text::U32String &suffix, BlockStyle style = {})
Use an ordered marker with the given suffix.
- Parameters:
suffix – The suffix appended after the item number.
style – Optional marker style overlay.
- Returns:
Reference to this marker.
-
BlockString render(std::size_t number, BlockStyle baseStyle) const
Render this marker for one list item number.
- Parameters:
number – The one-based item number for ordered lists.
baseStyle – The base text style used for marker text.
- Returns:
The rendered marker.
-
TerminalDocumentStyleMarker() = default
-
class TerminalDocumentStyleRule
One terminal document style rule with text, layout, and decoration settings.
Public Functions
-
TerminalDocumentStyleRule() = default
Create an empty style rule.
-
inline BlockStyle textStyle() const noexcept
Get the text style overlay.
-
inline const ParagraphIndents &indents() const noexcept
Get the paragraph indents and margins.
-
std::optional<BlockString> prefix() const noexcept
Get the optional prefix.
-
std::optional<BlockString> suffix() const noexcept
Get the optional suffix.
-
std::optional<BlockString> linePrefix() const noexcept
Get the optional prefix applied to every content line of a container.
-
inline TerminalDocumentStyleMarker &marker() noexcept
Get the marker configuration.
-
inline const TerminalDocumentStyleMarker &marker() const noexcept
Get the marker configuration.
-
TerminalDocumentStyleRule &setTextStyle(BlockStyle style) noexcept
Replace the text style overlay.
- Parameters:
style – The new text style overlay.
- Returns:
Reference to this rule.
-
TerminalDocumentStyleRule &setTextStyle(Color color, BlockAttributes attributes = {}) noexcept
Replace the text style overlay.
- Parameters:
color – The new color overlay.
attributes – The new attribute overlay.
- Returns:
Reference to this rule.
-
TerminalDocumentStyleRule &setIndents(ParagraphIndents indents) noexcept
Replace the indents and margins.
- Parameters:
indents – The new indents and margins.
- Returns:
Reference to this rule.
-
TerminalDocumentStyleRule &setMargins(block::Margins margins) noexcept
Replace the margins.
- Parameters:
margins – The new margins.
- Returns:
Reference to this rule.
-
TerminalDocumentStyleRule &setMargins(int allSides) noexcept
Replace all margins with one value.
- Parameters:
allSides – The value for all sides.
- Returns:
Reference to this rule.
-
TerminalDocumentStyleRule &setMargins(int horizontal, int vertical) noexcept
Replace horizontal and vertical margins.
- Parameters:
horizontal – The left and right margins.
vertical – The top and bottom margins.
- Returns:
Reference to this rule.
-
TerminalDocumentStyleRule &setMargins(int top, int right, int bottom, int left) noexcept
Replace each margin side.
- Parameters:
top – Top margin.
right – Right margin.
bottom – Bottom margin.
left – Left margin.
- Returns:
Reference to this rule.
-
TerminalDocumentStyleRule &setLineIndent(int indent) noexcept
Set the shared line indent.
- Parameters:
indent – The new line indent.
- Returns:
Reference to this rule.
-
TerminalDocumentStyleRule &setFirstLineIndent(int indent) noexcept
Set the first-line indent.
- Parameters:
indent – The new first-line indent.
- Returns:
Reference to this rule.
-
TerminalDocumentStyleRule &setWrappedLineIndent(int indent) noexcept
Set the wrapped-line indent.
- Parameters:
indent – The new wrapped-line indent.
- Returns:
Reference to this rule.
-
TerminalDocumentStyleRule &setPrefix(BlockString prefix) noexcept
Set the optional prefix.
- Parameters:
prefix – The prefix text.
- Returns:
Reference to this rule.
-
TerminalDocumentStyleRule &setPrefix(const text::U32String &prefix, BlockStyle style = {})
Set the optional prefix.
- Parameters:
prefix – The prefix text.
style – The prefix style.
- Returns:
Reference to this rule.
-
TerminalDocumentStyleRule &setPrefix(const text::String &prefix, BlockStyle style = {})
Set the optional prefix.
- Parameters:
prefix – The prefix text.
style – The prefix style.
- Returns:
Reference to this rule.
-
TerminalDocumentStyleRule &clearPrefix() noexcept
Remove the prefix.
- Returns:
Reference to this rule.
-
TerminalDocumentStyleRule &setSuffix(BlockString suffix) noexcept
Set the optional suffix.
- Parameters:
suffix – The suffix text.
- Returns:
Reference to this rule.
-
TerminalDocumentStyleRule &setSuffix(const text::U32String &suffix, BlockStyle style = {})
Set the optional suffix.
- Parameters:
suffix – The suffix text.
style – The suffix style.
- Returns:
Reference to this rule.
-
TerminalDocumentStyleRule &setSuffix(const text::String &suffix, BlockStyle style = {})
Set the optional suffix.
- Parameters:
suffix – The suffix text.
style – The suffix style.
- Returns:
Reference to this rule.
-
TerminalDocumentStyleRule &clearSuffix() noexcept
Remove the suffix.
- Returns:
Reference to this rule.
-
TerminalDocumentStyleRule &setLinePrefix(BlockString prefix) noexcept
Set the prefix applied to every content line of a container.
-
TerminalDocumentStyleRule &setLinePrefix(const text::U32String &prefix, BlockStyle style = {})
Set the styled prefix applied to every content line of a container.
-
TerminalDocumentStyleRule &setLinePrefix(const text::String &prefix, BlockStyle style = {})
Set the styled prefix applied to every content line of a container.
-
TerminalDocumentStyleRule &clearLinePrefix() noexcept
Remove the per-line prefix.
-
TerminalDocumentStyleRule &setLineFill(Block fill) noexcept
Set the line fill character.
- Parameters:
fill – The fill character.
- Returns:
Reference to this rule.
-
TerminalDocumentStyleRule &setLineFill(text::Char codePoint, BlockStyle style = {}) noexcept
Set the line fill character.
- Parameters:
codePoint – The fill code point.
style – The fill style.
- Returns:
Reference to this rule.
-
TerminalDocumentStyleRule &clearLineFill() noexcept
Remove the line fill character.
- Returns:
Reference to this rule.
-
TerminalDocumentStyleRule &setMarker(TerminalDocumentStyleMarker marker) noexcept
Replace the marker.
- Parameters:
marker – The marker configuration.
- Returns:
Reference to this rule.
-
TerminalDocumentStyleRule &setLiteralMarker(BlockString literal, BlockStyle style = {})
Configure a literal marker.
- Parameters:
literal – The marker text.
style – Optional marker style.
- Returns:
Reference to this rule.
-
TerminalDocumentStyleRule &setLiteralMarker(const text::U32String &literal, BlockStyle style = {})
Configure a literal marker.
- Parameters:
literal – The marker text.
style – Optional marker style.
- Returns:
Reference to this rule.
-
TerminalDocumentStyleRule &setOrderedMarker(BlockString suffix, BlockStyle style = {})
Configure an ordered marker.
- Parameters:
suffix – The marker suffix.
style – Optional marker style.
- Returns:
Reference to this rule.
-
TerminalDocumentStyleRule &setOrderedMarker()
Configure the default ordered marker.
- Returns:
Reference to this rule.
-
TerminalDocumentStyleRule &clearMarker() noexcept
Clear the marker.
- Returns:
Reference to this rule.
-
TerminalDocumentStyleRule() = default
-
class TerminalDocumentStyleSelector
A selector used to define or request one terminal document style rule.
Public Types
-
using TokenList = text::StringList
The normalized token list.
Public Functions
-
TerminalDocumentStyleSelector() noexcept = default
Create a paragraph selector.
-
inline explicit TerminalDocumentStyleSelector(text::TextNodeType nodeType) noexcept
Create a selector for the given text node type.
- Parameters:
nodeType – The node type to match.
-
inline TerminalDocumentStyleSelector(text::TextNodeType nodeType, std::optional<int> level) noexcept
Create a selector with an optional level.
- Parameters:
nodeType – The node type to match.
level – The optional heading or list nesting level.
-
TerminalDocumentStyleSelector(text::TextNodeType nodeType, std::initializer_list<text::String> requiredStyleTokens)
Create a selector with required style tokens.
- Parameters:
nodeType – The node type to match.
requiredStyleTokens – Required style tokens parsed from
TextNode::style().
-
TerminalDocumentStyleSelector(text::TextNodeType nodeType, std::optional<int> level, std::initializer_list<text::String> requiredStyleTokens)
Create a selector with an optional level and required style tokens.
- Parameters:
nodeType – The node type to match.
level – The optional heading or list nesting level.
requiredStyleTokens – Required style tokens parsed from
TextNode::style().
-
TerminalDocumentStyleSelector(text::TextNodeType nodeType, std::optional<int> level, std::initializer_list<text::String> requiredStyleTokens, std::optional<text::TextNodeType> ancestorType)
Create a selector with an optional ancestor constraint.
- Parameters:
nodeType – The node type to match.
level – The optional heading or list nesting level.
requiredStyleTokens – Required style tokens.
ancestorType – A type that must occur in the parent chain.
-
inline bool operator==(const TerminalDocumentStyleSelector &other) const
Compare two selectors for exact identity.
-
inline bool operator!=(const TerminalDocumentStyleSelector &other) const
Compare two selectors for exact inequality.
-
inline text::TextNodeType nodeType() const noexcept
Get the node type to match.
-
inline const std::optional<int> &level() const noexcept
Get the optional heading or list nesting level.
-
inline const std::optional<text::TextNodeType> &ancestorType() const noexcept
Get the optional required ancestor type.
Public Static Functions
-
static inline TerminalDocumentStyleSelector node(text::TextNodeType nodeType) noexcept
Create a selector for a node type.
- Parameters:
nodeType – The node type to match.
-
static inline TerminalDocumentStyleSelector document() noexcept
Create a document selector.
-
static inline TerminalDocumentStyleSelector section() noexcept
Create a section selector.
-
static inline TerminalDocumentStyleSelector paragraph() noexcept
Create a paragraph selector.
-
static inline TerminalDocumentStyleSelector heading(int level) noexcept
Create a heading selector.
- Parameters:
level – The one-based heading level.
-
static inline TerminalDocumentStyleSelector bulletList(int level) noexcept
Create a bullet-list selector.
- Parameters:
level – The zero-based nesting level.
-
static inline TerminalDocumentStyleSelector numberedList(int level) noexcept
Create a numbered-list selector.
- Parameters:
level – The zero-based nesting level.
-
static inline TerminalDocumentStyleSelector bulletListItem(int level) noexcept
Create a bullet-list-item selector.
- Parameters:
level – The zero-based nesting level.
-
static inline TerminalDocumentStyleSelector numberedListItem(int level) noexcept
Create a numbered-list-item selector.
- Parameters:
level – The zero-based nesting level.
-
static inline TerminalDocumentStyleSelector definitionList() noexcept
Create a definition-list selector.
-
static inline TerminalDocumentStyleSelector definitionTerm() noexcept
Create a definition-term selector.
-
static inline TerminalDocumentStyleSelector definitionDescription() noexcept
Create a definition-description selector.
-
static inline TerminalDocumentStyleSelector fieldList() noexcept
Create a field-list selector.
-
static inline TerminalDocumentStyleSelector fieldItem() noexcept
Create a field-item selector.
-
static inline TerminalDocumentStyleSelector fieldLabel() noexcept
Create a field-label selector.
-
static inline TerminalDocumentStyleSelector fieldContent() noexcept
Create a field-content selector.
-
static inline TerminalDocumentStyleSelector blockquote() noexcept
Create a blockquote selector.
-
static inline TerminalDocumentStyleSelector codeBlock() noexcept
Create a code-block selector.
-
static inline TerminalDocumentStyleSelector horizontalLine() noexcept
Create a horizontal-line selector.
-
static inline TerminalDocumentStyleSelector emphasis() noexcept
Create an emphasis selector.
-
static inline TerminalDocumentStyleSelector strong() noexcept
Create a strong-text selector.
-
static inline TerminalDocumentStyleSelector underline() noexcept
Create an underline selector.
-
static inline TerminalDocumentStyleSelector span(std::initializer_list<text::String> requiredStyleTokens)
Create a span selector with required style tokens.
- Parameters:
requiredStyleTokens – Required style tokens.
-
static inline TerminalDocumentStyleSelector link() noexcept
Create a link selector.
-
static inline TerminalDocumentStyleSelector code() noexcept
Create an inline-code selector.
-
static inline TerminalDocumentStyleSelector separator() noexcept
Create an inline-separator selector.
-
static inline TerminalDocumentStyleSelector escapeSequence() noexcept
Create an escape-sequence selector.
-
static inline auto descendantOf(text::TextNodeType nodeType, text::TextNodeType ancestorType, std::initializer_list<text::String> requiredStyleTokens = {}) -> TerminalDocumentStyleSelector
Create a selector constrained to descendants of the given type.
- Parameters:
nodeType – The node type to match.
ancestorType – A type that must occur in the parent chain.
requiredStyleTokens – Required style tokens.
-
static void normalizeTokens(TokenList &tokens)
Normalize a token list by sorting and removing duplicates.
- Parameters:
tokens – The tokens to normalize in-place.
-
static TokenList splitStyleTokens(const text::String &value)
Split and normalize a
TextNode::style()value.- Parameters:
value – The raw style value.
- Returns:
The normalized tokens.
-
using TokenList = text::StringList