Text Documents and Rendering
Text Document
Semantic Escaped Text
Use TextNode::addEscapedText() to insert untrusted text into a
document.
The method tolerantly decodes malformed input, groups ordinary characters into Text nodes, and creates one
indivisible EscapeSequence node for every escaped character.
This preserves wrapping and styling semantics while preventing raw control sequences from reaching a renderer.
JSON Values
Value Tree
JsonValue is a copy-on-write value tree for JSON nulls, booleans, signed 64-bit integers, finite floating-point
numbers, Unicode strings, arrays, and objects.
JsonArray and JsonObject use the regular Erbsland Core list and ordered string-map containers.
Copying a tree is inexpensive; the first mutation detaches the changed value.
Parsing and Formatting
fromStringOrThrow() strictly parses one complete RFC 8259 value and reports syntax, duplicate-key, encoding, and
configured-limit failures as ParseError.
fromString() provides the optional-returning form.
Default limits accept 16 MiB documents, 64 container levels, one million values, and 8 MiB decoded strings.
toString() produces deterministic compact JSON with object keys in StringMap order.
JsonFormatOptions can enable space-indented output and non-ASCII escaping.
HTML Parser
Introduction
The HTML parser converts a tolerant subset of HTML fragments or documents into a
TextDocument.
Malformed tags and entities are recovered as text where possible, so user-facing parsers can accept imperfect input.
Usage
Create HtmlParser with an
AnyString compatible value and call parse() for the default
tolerant API.
Use parseOrThrow() when future unrecoverable parser errors should be reported as
ParseError.
Layout Rendering
The layout renderer compiles a deliberately small Jinja-like language into process-local bytecode and caches an
immutable compiled generation for each logical layout name.
The renderer supports exact source text, comments, explicit whitespace control, scalar expressions, conditionals,
lexically scoped list and ordered-map iteration, assignments, static includes, static inheritance, blocks, super()
calls, and registered value filters.
Inserted scalar values are escaped automatically according to the logical layout-name suffix unless this behavior is
disabled in EnvironmentOptions.
Setup and Thread Safety
Create an Environment, add one or more loaders, and optionally enable automatic reload before the first render.
Loader, filter, and syntax setup is not thread-safe and becomes immutable at the first render.
render() and setGlobalContext() are thread-safe.
Register application filters with addFilter() before the first render.
A FilterFn receives one immutable ValueList and returns one Value.
Item zero is the resolved piped value; items one and two, when present, are the optional positional arguments in source
order.
The compiler evaluates those arguments once from left to right, while each application callback validates the list size
and all value types it accepts.
Filter callbacks can run concurrently and must provide their own synchronization for captured mutable state.
Filter names are ASCII identifiers.
Application filters can replace ordinary built-ins, but duplicate application registrations are rejected.
The names escape, e, and safe are reserved output modifiers.
The local Context supplied to render() takes precedence over the current global context snapshot.
Missing names and missing dotted members become null; null renders as empty text and is false.
Rendering a list or map directly is an error.
Loader Contract
A Loader receives a validated logical layout name and returns either one LayoutSource or std::nullopt.
A source contains exact UTF-8 text, a diagnostic origin, and an opaque revision.
Higher-priority loaders are queried first; equal priorities retain addition order.
FileSystemLoader accepts existing absolute directory roots.
It canonicalizes each root, maps layout components below it, rejects symbolic-link traversal below the root and
non-regular files, and reads strict UTF-8. Its revision changes with file content.
ResourceLoader maps a logical name exactly to one compiled-resource key.
For identifier layouts and prefix application, email/body.html resolves to
(layouts, application/email/body.html).
No extension is added and the name is not made relative to the including layout.
The identifier is a portable resource token.
The optional prefix is empty or a normalized relative UTF-8 path with / separators and no empty, . or ..
components.
An explicit resource provider is retained through its shared pointer.
The convenience factory, or a null explicit provider, follows core::application().resources() and therefore the
application lifetime.
Do not create such an application-backed loader during unsafe static initialization.
Missing keys return std::nullopt so later loaders can participate.
Present data is transparently decompressed, must be valid UTF-8, and reports an error rather than being treated as
missing when decoding fails.
Resource origins use resource:<identifier>/<path> and revisions are derived from logical content.
The same layout tree can move from development to deployment without changing include names: use a FileSystemLoader
rooted at <project>/data/layouts while developing, compile that tree as resources for deployment, then use
ResourceLoader with its matching identifier and prefix.
For customization, register both and give the external filesystem loader higher priority.
Loader priority applies independently to the root and every included or inherited layout, so one external partial or
parent can override its embedded counterpart.
Without automatic reload, a layout is loaded and compiled once. With reload enabled, every render recursively checks the current origin, revision, and dependency generations. A successfully compiled source or dependency change replaces the affected cache generations. An optional dependency appearing or disappearing also republishes its parents. A failed change reports an error; renders already holding the previous immutable generation remain valid.
Supported Syntax
Raw text, comments, whitespace markers, and expression, statement, and comment delimiters retain the behavior described for the running framework. Closing delimiters inside quoted expression strings are treated as literal text.
Expressions
Expressions support:
ASCII names and dotted lookup, such as
nameanduser.profile.name;signed decimal integers, finite decimal or scientific floats,
true,false, andnone/null;single- and double-quoted UTF-8 strings;
nested list literals and string-keyed map literals, including empty collections and one trailing comma;
parentheses, unary
+,-, andnot, binary+,-,*,/,~,and, andor;==,!=,>,>=,<,<=,in,not in,is, andis not; andfilter chains with zero, one, or two arguments, such as
values | join(',').
String escapes are \\, \', \", \b, \f, \n, \r, \t, and \uXXXX.
Unicode surrogate escapes must form a valid pair.
Unescaped control characters and invalid Unicode escapes are rejected.
From tightest to loosest binding, precedence is primary/member/collection expressions, filter chains, unary + and
-, * and /, +, -, and ~, comparisons and membership/tests, not, and, then or.
and and or short-circuit and return the selected operand; not and comparisons return booleans.
Only one comparison is accepted in each comparison expression; combine multiple comparisons with and.
Equality supports null, booleans, numbers, and text. Integers and floats compare numerically without first converting the integer to a float. Different scalar types compare unequal. Ordering requires two numbers or two text values; text uses exact decoded-code-point order. Comparing lists or maps is a runtime error.
Arithmetic accepts numbers only.
Integer +, -, *, and / saturate to the signed 64-bit range using the math-domain saturating algorithms.
Integer division truncates toward zero and returns an integer.
Any floating-point operand selects double arithmetic and a floating-point result.
An integer or floating-point zero divisor, including negative zero, produces null.
The ~ operator converts null and scalars using renderer string conversion; containers are errors.
Membership supports text in text, a scalar in a list, and a text key in a map.
The argument-free tests are none /null, true, false, boolean, integer, float, number,
text /string, list /sequence, map /mapping, iterable, scalar, even, and odd.
A test that does not apply to a value returns false.
Statements
if statements support nested elif and else branches and end with endif.
Only conditions on the selected branch are evaluated.
{% set name = expression %} stores a value in private render-local state without changing the supplied local or
global context.
A layout-level assignment is hoisted into that layout’s setup program and runs before body output, regardless of its
source position.
Across inheritance, setup programs run once from the ultimate base to the most-derived layout, so derived assignments
override parent assignments.
Assignments nested in blocks, conditions, or loops retain their normal execution order and lexical scope.
Iteration
{% for item in sequence %} iterates a list and {% for key, value in mapping %} iterates an ordered map.
The iterable expression is evaluated and callbacks are resolved exactly once when the loop starts.
One target requires a list; two distinct targets require a map.
Map entries follow StringMap key order.
Null, scalar values, mismatched target counts, duplicate targets, reserved keywords, and more than two targets are
strict errors.
An optional else branch runs only when the iterable produced no item.
The loop’s private state and scope are removed before that branch executes.
Each iteration has a fresh lexical scope.
Its target names and assignments disappear before the next iteration, and assignments never update an outer binding.
Lookup proceeds through the innermost iteration scope, outer iteration scopes, render-local assignments, the caller’s
local context, and finally the global context.
Nested loops temporarily shadow loop and restore the outer value when the inner loop ends.
The loop name cannot be an iteration or set target while a loop body is being compiled.
The immutable loop map contains:
indexandindex0: the one-based and zero-based current indexes;revindexandrevindex0: the one-based and zero-based remaining indexes;firstandlast: booleans identifying the first and last item; andlength: the collection length.
Blocks and Inheritance
{% extends "layout/name" %} binds one exact static parent while compiling.
The statement accepts one string and no modifiers; dynamic expressions, fallback lists, relative resolution, and added
extensions are not supported.
An extending layout may contain only one extends statement, layout-level set statements, block declarations,
comments, and whitespace outside blocks.
Other output, expressions, includes, or control statements outside a block are syntax errors.
{% block name %} declares an ASCII-identifier block and ends with {% endblock %}.
Block names are unique within one layout, and a name after endblock is not supported.
Blocks can nest inside other blocks and structurally valid control bodies.
The renderer executes the ultimate base layout’s body and dispatches each declaration to the most-derived available
implementation; an unoverridden declaration therefore renders its base fallback.
Dispatched blocks retain visible iteration scopes, loop metadata, render-local values, caller context, and global
context.
Inside a block, super() renders the next implementation in its resolved override chain and super.super() renders
the implementation after that.
A standalone {{ super() }} or {{ super.super() }} writes directly to the current output sink.
When a super call participates in a filter, grouping, comparison, logic expression, or set assignment, its output is
first captured as text and then processed as a normal value.
Arguments, deeper chaining, and calls outside blocks are syntax errors; requesting a depth with no implementation is a
runtime error.
Includes
{% include "layout/name" %} binds one exact static logical layout name while compiling.
Dynamic expressions, relative names, fallback lists, and added extensions are not supported.
ignore missing and either with context or without context may follow the name in either order, but each
modifier is accepted at most once.
The default is with context.
With context, an included layout sees the immediate parent’s active iteration scopes, private assignments, caller context, and global context. Assignments made by the child remain private to that child. Without context, the child sees only the global context and its own private assignments. A nested include always inherits from its immediate parent according to its own context modifier.
ignore missing suppresses only a missing-layout error.
Invalid names, loader and resource failures, invalid UTF-8, syntax and runtime errors, cycles, and limits remain
visible.
A compiled graph can traverse at most the configured static-dependency depth below the root; the default is 32 edges.
Direct, indirect, and mixed include/inheritance cycles are syntax errors.
Compiled generations retain their resolved immutable parents, block chains, include dependencies, and explicit empty descriptors for ignored missing layouts. Nested programs append to one shared output sink and the renderer joins the final output once.
Filters are resolved while compiling a layout, so an unknown filter is a syntax error. Filter chains run from left to right and apply normal callback resolution before and after each filter invocation. Arguments are evaluated once from left to right. A third argument is rejected while compiling.
The ordinary built-ins are:
text:
capitalize,lower,upper,trim([characters]), andreplace(old, new);collections:
first,last,join([separator [, member]]),length/count,reverse,sort([reverse [, case_sensitive]]),keys,values, anditems;numeric:
abs,round([precision [, common|ceil|floor]]),sum([start]),min, andmax; andgeneral/output:
default/d([replacement [, use_false]])andtojson([indent]).
Empty first, last, min, and max produce null.
tojson accepts indentation from zero through 16 and returns ordinary unsafe text; use |tojson|safe for a raw
JSON insertion.
Escaping
Automatic escaping is enabled by default.
.html, .xml, .elcl, .md, and .json select Html, Xml, Config, Markdown, and Json
respectively.
Custom bounded suffix mappings use longest-match selection; unmatched names use None.
The logical name of the program-owning layout selects the format, including included layouts and inherited block
implementations.
All directly emitted scalars pass through Value::toString().toEscaped(selectedFormat).
Null remains empty and containers remain non-renderable.
safe suppresses automatic escaping for one insertion.
escape and its Jinja compatibility alias e force escaping, with an optional canonical format argument.
With no argument they use the suffix-selected format or HTML when no format was selected.
These modifiers are accepted only as the final filter of a direct output expression; they are rejected in conditions,
assignments, arguments, and expressions involving super().
Disabling automatic escaping does not disable explicit escape.
Direct block output and direct super() rendering are already layout-safe.
Capturing and transforming super output turns it into ordinary unsafe text.
Markdown escaping follows the CommonMark backslash-escape rules
for normal Markdown text; it does not protect contexts in which CommonMark disables backslash escaping.
Limits
EnvironmentOptions::renderLimits() configures positive limits for total generated and captured output, executed
instructions, runtime nesting, callback resolution, lexical scopes, call frames, value-stack depth, and static
dependency depth.
Defaults are 64 MiB, 10,000,000 instructions, 128 nesting levels, 32 callback levels, 128 scopes, 128 call frames, 1,024
stack values, and 32 static dependency edges.
Exceeding a limit raises a Limit render error.
Arbitrary function calls, assignments to dotted names, recursive loops, block capture, dynamic dependencies, macros, and persisted bytecode remain unsupported. A whitespace marker removes adjacent ASCII whitespace; no other source whitespace is changed.
Layout names use lowercase ASCII letters, digits, -, _, ., and /.
They are relative, contain no empty, . or .. component, and contain at most 200 characters.
Errors
RenderError reports a category, title, description, logical layout, origin, source location, optional source
snippet, and nested render frames.
A nested failure preserves the leaf layout, origin, and location and records outer include or inheritance call sites in
outermost-first order as one-based layout:line:column frames.
Loading and callback exceptions are kept as nested causes.
Invalid supported operations are strict; only missing value lookup is silent.
Interface
-
struct CodeSnippet
A line-oriented excerpt of source code.
The line index is zero-based; renderers present it in the customary one-based form.
-
class CodeSnippetMarker
A marker range for a line-oriented code snippet.
Public Functions
-
CodeSnippetMarker() = default
Create an empty code-snippet marker.
-
inline CodeSnippetMarker(unit::LineIndex line, unit::ColumnIndex column, unit::ColumnCount length = unit::ColumnCount::one(), String label = {}, String style = {}) noexcept
Create a marker for a snippet line.
- Parameters:
line – The original zero-based line index.
column – The zero-based logical source-code-point column.
length – The marker length in logical source code points, or zero for a point marker.
label – Optional label rendered after the marker.
style – Optional style token for renderers.
-
inline unit::ColumnIndex column() const noexcept
Get the zero-based logical source-code-point column.
-
inline unit::ColumnCount length() const noexcept
Get the marker length in logical source code points.
-
CodeSnippetMarker() = default
-
using erbsland::text::CodeSnippetMarkerList = util::List<CodeSnippetMarker>
A list of code snippet markers.
-
class HtmlParser
A tolerant HTML parser that converts HTML fragments into text documents.
Public Functions
-
explicit HtmlParser(AnyString html)
Create a parser for the given HTML text.
- Parameters:
html – The HTML fragment or document to parse.
-
HtmlParser &operator=(HtmlParser&&) noexcept
Move parser state into this instance.
-
TextDocument parse() noexcept
Parse the HTML text into a document.
- Returns:
The parsed text document, or a best-effort document if a parser error is recovered.
-
TextDocument parseOrThrow()
Parse the HTML text into a document.
- Throws:
err::ParseError – If a future unrecoverable parser condition is detected.
- Returns:
The parsed text document.
-
explicit HtmlParser(AnyString html)
-
class JsonFormatOptions
Options for serializing a JSON value.
Public Functions
-
inline constexpr unit::CpLength indentation() const noexcept
Get the spaces used for each indentation level; zero selects compact output.
-
inline constexpr JsonFormatOptions &setIndentation(const unit::CpLength value) noexcept
Set the spaces used for each indentation level.
-
inline constexpr EscapeAmount escapeAmount() const noexcept
Get the JSON string escape amount.
-
inline constexpr JsonFormatOptions &setEscapeAmount(const EscapeAmount value) noexcept
Set the JSON string escape amount.
Public Static Functions
-
static inline constexpr JsonFormatOptions compact() noexcept
Create compact formatting options.
-
static inline constexpr JsonFormatOptions pretty() noexcept
Create pretty formatting options using two spaces.
-
inline constexpr unit::CpLength indentation() const noexcept
-
class JsonParseOptions
Safety limits for parsing JSON documents.
Public Functions
-
inline constexpr unit::ByteLength maximumInputLength() const noexcept
Get the maximum source length in bytes.
-
inline constexpr JsonParseOptions &setMaximumInputLength(const unit::ByteLength value) noexcept
Set the maximum source length in bytes.
-
inline constexpr unit::ItemCount maximumNesting() const noexcept
Get the maximum number of open container levels.
-
inline constexpr JsonParseOptions &setMaximumNesting(const unit::ItemCount value) noexcept
Set the maximum number of open container levels.
-
inline constexpr unit::ItemCount maximumValueCount() const noexcept
Get the maximum value count, including the root.
-
inline constexpr JsonParseOptions &setMaximumValueCount(const unit::ItemCount value) noexcept
Set the maximum value count, including the root.
-
inline constexpr unit::CpLength maximumStringLength() const noexcept
Get the maximum decoded key or string length in bytes.
-
inline constexpr JsonParseOptions &setMaximumStringLength(const unit::CpLength value) noexcept
Set the maximum decoded key or string length in bytes.
Public Static Attributes
-
static constexpr auto cDefaultMaximumInputLength = unit::ByteLength{16U * 1024U * 1024U}
Input limit.
-
inline constexpr unit::ByteLength maximumInputLength() const noexcept
-
enum class erbsland::text::json::JsonType : uint8_t
The semantic type of a JSON value.
Values:
-
enumerator Null
The null value.
-
enumerator Bool
A boolean value.
-
enumerator Number
An integer or floating-point number.
-
enumerator Text
A Unicode string.
-
enumerator Array
An ordered array.
-
enumerator Object
A string-keyed object.
-
enumerator Null
-
class JsonValue
A copy-on-write JSON value tree.
See: Text Documents and Rendering
Public Functions
-
JsonValue() noexcept = default
Create the null value.
-
JsonValue(bool value)
Create a boolean value.
-
JsonValue(int64_t value)
Create an integer number.
-
JsonValue(double value)
Create a floating-point number.
- Throws:
err::ParameterError – If
valueis not finite.
-
JsonValue(JsonObject value)
Create an object value.
-
template<std::integral T>
inline JsonValue(const T value) Create an integer number from another integral type.
- Throws:
err::ParameterError – If
valuedoes not fit intoint64_t.
-
bool isPrimitive() const noexcept
Test whether this value is null, boolean, number, or text.
-
unit::ItemCount itemCount() const noexcept
Get the number of array elements or object entries, or zero for a primitive.
-
JsonValue get(unit::ItemIndex index) const
Get an array element, or null if this is not an array or the index is invalid.
-
JsonValue getOrThrow(unit::ItemIndex index) const
Get an array element.
- Throws:
err::LogicError – If this is not an array.
err::OutOfRangeError – If the index is invalid.
-
JsonValue get(const String &key) const
Get an object member, or null if this is not an object or the key is missing.
-
JsonValue getOrThrow(const String &key) const
Get an object member.
- Throws:
err::LogicError – If this is not an object.
err::OutOfRangeError – If the key is missing.
-
template<typename T>
T get(T fallback) const Get this value as a supported native type, or return a fallback.
-
template<typename T>
T getOrThrow() const Get this value as a supported native type.
- Throws:
err::LogicError – If the value cannot be represented as
T.
-
std::optional<bool> getBool() const noexcept
Get a boolean value.
-
bool getBool(bool fallback) const noexcept
Get a boolean value or a fallback.
-
bool getBoolOrThrow() const
Get a boolean value.
- Throws:
err::LogicError – If this is not a boolean.
-
std::optional<double> getNumber() const noexcept
Get a number as a double.
-
double getNumber(double fallback) const noexcept
Get a number as a double or a fallback.
-
double getNumberOrThrow() const
Get a number as a double.
- Throws:
err::LogicError – If this is not a number.
-
String getTextOrThrow() const
Get a text value.
- Throws:
err::LogicError – If this is not text.
-
JsonValue &set(unit::ItemIndex index, JsonValue value)
Replace an array element, or append when
index == itemCount().- Throws:
err::LogicError – If this is not an array.
err::OutOfRangeError – If
index > itemCount().
-
JsonValue &set(const String &key, JsonValue value)
Insert or replace an object member.
- Throws:
err::LogicError – If this is not an object.
-
JsonValue &append(JsonValue value)
Append an array element.
- Throws:
err::LogicError – If this is not an array.
-
String toString(JsonFormatOptions options = {}) const
Serialize this value as valid JSON.
Public Static Functions
-
static std::optional<JsonValue> fromString(const String &text, JsonParseOptions options = {}) noexcept
Parse one complete JSON value.
Note
UTF-8 errors are ignored, validate the string before parsing if this is relevant.
-
static JsonValue fromStringOrThrow(const String &text, JsonParseOptions options = {})
Parse one complete JSON value.
Note
UTF-8 errors are ignored, validate the string before parsing if this is relevant.
- Throws:
err::ParseError – If the document is invalid or exceeds configured limits.
-
JsonValue() noexcept = default
-
class PlainTextRenderer
Render a text document as plain UTF-8 text.
Public Functions
-
explicit PlainTextRenderer(const TextDocument &document)
Create a plain-text renderer for a document.
- Parameters:
document – The document to render.
-
~PlainTextRenderer()
Destroy the renderer implementation.
-
String build()
Build a new UTF-8 string from the document.
- Returns:
The rendered plain text string.
-
AnyStringBuilder &appendTo(AnyStringBuilder &builder)
Append the rendered plain text to an existing builder.
- Parameters:
builder – The builder to append to.
- Returns:
The same builder.
-
explicit PlainTextRenderer(const TextDocument &document)
-
class Context
A named collection of values exposed while rendering a layout.
See: Text Documents and Rendering
Public Functions
-
Context() = default
Create an empty context.
-
Context() = default
-
class Delimiters
One configurable pair of layout delimiters.
Public Functions
-
class Environment
A text rendering environment.
layoutis a path like identifier only accepting ASCII lowercase letters, digits, the underscore, minus character and the/as path separator[-._/a-z0-9]. It must never start or end with/, and must not contain two consecutive/. The maximum length is 200 code-points.Multithreading: The setup methods are not thread-safe. The manage and render methods are thread-safe.
See: Text Documents and Rendering
Subclassed by erbsland::text::render::impl::Environment
Public Functions
-
virtual void addLayoutLoader(const LoaderPtr &loader, int priority) = 0
Add a layout loader to this environment.
Loaders are tested in the order of priority, or in the order of addition if priorities are equal.
Note
Not thread-safe. Must not be called after the first manage or render call.
- Parameters:
loader – The loader to add. Must not be null.
priority – The priority of the loader. Higher values have higher priority.
-
inline void addLayoutLoader(const LoaderPtr &loader)
This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.
-
virtual void addFilter(const String &name, FilterFn filter) = 0
Add a value filter to this environment.
Filter names use ASCII identifiers. Registered filters can be invoked concurrently while rendering. The callback list contains the piped value at index zero followed by up to two positional arguments. The callback validates its own accepted list size and value types.
Note
Not thread-safe. Must not be called after the first render call.
- Parameters:
name – The unique filter name.
filter – The filter callback. Must not be empty.
-
virtual void enableAutoReload() = 0
Enable automatic reload of layouts.
This option mainly makes sense while development, as it can impact performance. Each time a layout is rendered, all loaders are queried and the last modification date/time of the found layout is compared with the compiled version. If a newer version is found, the layout is reloaded and compiled. Once enabled, auto reload cannot be disabled.
Note
Not thread-safe. Must not be called after the first manage or render call.
-
virtual void setGlobalContext(Context context) = 0
Replace the global context snapshot.
The global context is the fallback if a variable is not found in the local context, or if no local context is provided.
- Parameters:
context – The new global context.
-
virtual String render(const String &layout, const Context &context) = 0
Renders the given layout using the given context.
- Parameters:
layout – The path to the layout to render. Must not be empty.
context – The local context to use for rendering; it overrides global names.
- Throws:
RenderError – on any failure.
- Returns:
The rendered layout.
Public Static Functions
-
static EnvironmentPtr create(EnvironmentOptions options = {})
Create a new empty environment.
-
virtual void addLayoutLoader(const LoaderPtr &loader, int priority) = 0
-
class EnvironmentOptions
Options controlling layout syntax.
Public Functions
-
EnvironmentOptions()
Create the default environment options.
-
inline const Delimiters &expressionDelimiters() const noexcept
Get the expression delimiters.
-
inline EnvironmentOptions &setExpressionDelimiters(const Delimiters &delimiters) noexcept
Set the expression delimiters.
-
inline const Delimiters &statementDelimiters() const noexcept
Get the statement delimiters.
-
inline EnvironmentOptions &setStatementDelimiters(const Delimiters &delimiters) noexcept
Set the statement delimiters.
-
inline const Delimiters &commentDelimiters() const noexcept
Get the comment delimiters.
-
inline EnvironmentOptions &setCommentDelimiters(const Delimiters &delimiters) noexcept
Set the comment delimiters.
-
inline bool automaticEscapingEnabled() const noexcept
Test if automatic escaping is enabled.
-
EnvironmentOptions &setAutomaticEscapingEnabled(bool enabled) noexcept
Enable or disable automatic escaping.
-
EnvironmentOptions &setEscapeFormatForSuffix(const String &suffix, EscapeFormat format)
Assign an escape format to a layout-name suffix.
-
bool removeEscapeFormatForSuffix(const String &suffix)
Remove the escape format assigned to a suffix.
-
void clearEscapeFormats()
Remove all suffix escape-format assignments.
-
EscapeFormat escapeFormatForLayout(const String &layoutName) const noexcept
Look up the escape format for a logical layout name using longest-suffix matching.
-
inline const RenderLimits &renderLimits() const noexcept
Access the rendering limits.
-
EnvironmentOptions &setRenderLimits(const RenderLimits &limits) noexcept
Replace the rendering limits.
-
EnvironmentOptions()
-
class FileSystemLoader : public erbsland::text::render::Loader
A loader that loads layouts from a directory on the file system.
All directories must be absolute and exist at the time of construction.
It does not follow symlinks.
It does map layout paths 1:1 to relative file paths.
It searches for layouts in the given search directories in the specified order.
See: Text Documents and Rendering
Subclassed by erbsland::text::render::impl::FileSystemLoader
Public Static Functions
-
static LoaderPtr create(path::Path searchPath, FileSystemLoaderOptions options = {})
Create a new file system loader, with a single path and the given options.
- Parameters:
searchPath – The path to the directory to search for layouts.
options – The options for the file system loader.
- Returns:
A new file system loader.
-
static LoaderPtr create(util::List<path::Path> searchPaths, FileSystemLoaderOptions options = {})
Create a new file system loader, with a single path and the given options.
- Parameters:
searchPaths – The search paths to directories to be searched in this order for layouts.
options – The options for the file system loader.
- Returns:
A new file system loader.
-
class FileSystemLoaderOptions
Options for the file system layout loader.
-
class LayoutSource
One loaded layout source and its cache identity.
See: Text Documents and Rendering
-
class Loader
Loads layout sources by logical name.
All methods must be thread-safe.
See: Text Documents and Rendering
Subclassed by erbsland::text::render::FileSystemLoader, erbsland::text::render::ResourceLoader
Public Functions
-
virtual std::optional<LayoutSource> load(const String &layout) = 0
Load a layout.
- Parameters:
layout – The validated logical layout name.
- Returns:
The loaded source, or no value when this loader has no matching layout.
-
virtual std::optional<LayoutSource> load(const String &layout) = 0
-
class RenderError : public erbsland::err::RuntimeError
The primary error type for the layout renderer.
See: Text Documents and Rendering
Public Functions
-
explicit RenderError(RenderErrorContext context, const std::exception_ptr &cause = {})
Create a new render error from the given context.
- Parameters:
context – The context of the error.
cause – The optional cause of the error.
-
inline const RenderErrorContext &context() const noexcept
Access the context of the error.
-
virtual err::DiagnosticConstPtr diagnostic() const override
Create a standard diagnostic view of this render error.
-
explicit RenderError(RenderErrorContext context, const std::exception_ptr &cause = {})
-
enum class erbsland::text::render::RenderErrorCategory : uint8_t
The category of a layout-rendering failure.
Values:
-
enumerator InvalidLayoutName
A logical layout name is invalid.
-
enumerator LayoutNotFound
No loader found the requested layout.
-
enumerator Load
Loading a layout failed.
-
enumerator Syntax
Layout syntax is invalid or unsupported.
-
enumerator Runtime
Program execution failed.
-
enumerator Limit
A renderer safety limit was exceeded.
-
enumerator Internal
Compiled bytecode or an internal invariant is invalid.
-
enumerator InvalidLayoutName
-
class RenderErrorContext
Complete user-facing context for a render error.
Public Functions
-
inline RenderErrorContext(RenderErrorCategory category, String title, String description) noexcept
Create a new error context with a title and description.
-
inline RenderErrorCategory category() const noexcept
Access the error category.
-
inline RenderErrorContext &setLayout(String layout) noexcept
Set the logical layout name.
-
inline RenderErrorContext &setOrigin(String origin) noexcept
Set the source origin.
-
inline const unit::CodeLocation &location() const noexcept
An optional location in the file/resource that caused the error.
-
inline RenderErrorContext &setLocation(const unit::CodeLocation location) noexcept
Set the location in the file/resource that caused the error.
-
inline const std::optional<CodeSnippet> &codeSnippet() const noexcept
Access the optional source snippet.
-
inline RenderErrorContext &setCodeSnippet(CodeSnippet codeSnippet) noexcept
Set the source snippet.
-
inline const StringList &frames() const noexcept
Access the nested layout frames, outermost first.
-
inline RenderErrorContext &addFrame(String frame)
Append a nested layout frame.
-
inline RenderErrorContext &addOuterFrame(String frame)
Prepend an outer nested layout frame.
-
inline RenderErrorContext(RenderErrorCategory category, String title, String description) noexcept
-
class RenderLimits
Limits protecting a rendering operation from excessive resource use.
Public Functions
-
inline uint64_t generatedOutputBytes() const noexcept
Get the maximum combined generated and captured output in bytes.
-
RenderLimits &setGeneratedOutputBytes(uint64_t value)
Set the maximum combined generated and captured output in bytes.
-
inline uint64_t executedInstructions() const noexcept
Get the maximum number of executed instructions.
-
RenderLimits &setExecutedInstructions(uint64_t value)
Set the maximum number of executed instructions.
-
inline uint64_t nestingDepth() const noexcept
Get the maximum runtime nesting depth.
-
RenderLimits &setNestingDepth(uint64_t value)
Set the maximum runtime nesting depth.
-
inline uint64_t callbackDepth() const noexcept
Get the maximum callback resolution depth.
-
RenderLimits &setCallbackDepth(uint64_t value)
Set the maximum callback resolution depth.
-
inline uint64_t lexicalScopeDepth() const noexcept
Get the maximum lexical scope depth.
-
RenderLimits &setLexicalScopeDepth(uint64_t value)
Set the maximum lexical scope depth.
-
inline uint64_t callFrameDepth() const noexcept
Get the maximum call-frame depth.
-
RenderLimits &setCallFrameDepth(uint64_t value)
Set the maximum call-frame depth.
-
inline uint64_t valueStackDepth() const noexcept
Get the maximum value-stack depth.
-
RenderLimits &setValueStackDepth(uint64_t value)
Set the maximum value-stack depth.
-
inline uint64_t staticDependencyDepth() const noexcept
Get the maximum static dependency depth.
-
RenderLimits &setStaticDependencyDepth(uint64_t value)
Set the maximum static dependency depth.
-
inline uint64_t generatedOutputBytes() const noexcept
-
class ResourceLoader : public erbsland::text::render::Loader
A layout loader backed by one compiled-resource identifier and optional path prefix.
A null resource provider selects the application resource manager. Do not create an application-backed loader during unsafe static initialization.
See: Text Documents and Rendering
Subclassed by erbsland::text::render::impl::ResourceLoader
Public Static Functions
-
static LoaderPtr create(String identifier, String pathPrefix = {})
Create a loader using the application resource manager.
- Parameters:
identifier – The exact portable resource identifier.
pathPrefix – The optional normalized relative resource path prefix.
- Returns:
A new resource layout loader.
-
static LoaderPtr create(resource::ResourcesConstPtr resources, String identifier, String pathPrefix = {})
Create a loader retaining an explicit provider, or using application resources when it is null.
- Parameters:
resources – The retained resource provider, or null for application resources.
identifier – The exact portable resource identifier.
pathPrefix – The optional normalized relative resource path prefix.
- Returns:
A new resource layout loader.
-
static LoaderPtr create(String identifier, String pathPrefix = {})
-
class Value
An immutable value exposed to the layout renderer.
See: Text Documents and Rendering
Public Functions
-
Value() noexcept = default
Create a null value.
-
Value(bool value)
Create a boolean value.
-
inline Value(StringLiteral text)
Create a text value from an Erbsland Core string literal.
-
Value(int64_t value)
Create an integer value.
-
template<std::integral T>
inline Value(const T value) Create an integer value from another integral type.
- Throws:
err::ParameterError – If
valuedoes not fit intoint64_t.
-
Value(double value)
Create a float value.
-
template<std::floating_point T>
inline Value(const T value) Create a floating-point value from another floating-point type.
-
Value(ValueCallbackFn value)
Create a lazily evaluated callback value.
-
bool isNull() const noexcept
Test if this is a null value.
-
bool isBoolean() const noexcept
Test if this is a boolean value.
-
bool isInteger() const noexcept
Test if this is an integer value.
-
bool isFloat() const noexcept
Test if this is a floating-point value.
-
bool isText() const noexcept
Test if this is a text value.
-
bool isList() const noexcept
Test if this is a list value.
-
bool isMap() const noexcept
Test if this is a map.
-
bool isCallback() const noexcept
Test if this is a callback.
-
unit::ItemCount itemCount() const noexcept
Get the number of list or map items, or zero for other types.
-
bool isTruthy() const noexcept
Test this value using the renderer truth rules.
-
bool asBoolean() const
Get the stored boolean.
- Throws:
err::LogicError – If this is not a boolean value.
-
int64_t asInteger() const
Get the stored integer.
- Throws:
err::LogicError – If this is not an integer value.
-
double asFloat() const
Get the stored floating-point number.
- Throws:
err::LogicError – If this is not a floating-point value.
-
String asText() const
Get the stored text.
- Throws:
err::LogicError – If this is not a text value.
-
const ValueList &asList() const
Get the stored list.
- Throws:
err::LogicError – If this is not a list value.
-
const ValueMap &asMap() const
Get the stored map.
- Throws:
err::LogicError – If this is not a map value.
-
Value get(unit::ItemIndex index) const
Get a list item, or null if this is not a list or the index is invalid.
-
Value get(const String &name) const
Get a map item, or null if this is not a map or the name is missing.
-
Value() noexcept = default
-
using erbsland::text::render::ValueCallbackFn = std::function<Value()>
A callback that lazily produces a render value.
-
using erbsland::text::render::FilterFn = std::function<Value(const ValueList&)>
An application filter receiving the piped value followed by zero, one, or two positional arguments.
-
enum class erbsland::text::render::ValueType : uint8_t
The semantic type of a render value.
Values:
-
enumerator Null
A null value.
-
enumerator Boolean
A boolean value.
-
enumerator Text
A text value.
-
enumerator Integer
A signed integer value.
-
enumerator Float
A floating point value.
-
enumerator List
A list of values.
-
enumerator Map
A map of values.
-
enumerator Callback
A lazily evaluated callback value.
-
enumerator Null
-
class TextDocument
A mutable text document with a valid document root node.
Public Functions
-
TextDocument()
Create an empty text document.
-
TextNodePtr add(TextNodeType type)
Add a child node with the given type to the document root.
-
TextNodePtr addParagraph()
Add a paragraph to the document root.
-
TextNodePtr addSection()
Add a section to the document root.
-
TextNodePtr addBlockquote()
Add a blockquote to the document root.
-
TextNodePtr addLineBreak()
Add an explicit line break to the document root.
-
TextNodePtr addHeading(TextNode::Level level)
Add a heading to the document root.
- Parameters:
level – The heading level.
-
TextNodePtr addBulletList(TextNode::Level level = 0)
Add a bullet list to the document root.
- Parameters:
level – The nesting level.
-
TextNodePtr addNumberedList(TextNode::Level level = 0)
Add a numbered list to the document root.
- Parameters:
level – The nesting level.
-
TextNodePtr addDefinitionList()
Add a definition list to the document root.
-
TextNodePtr addCodeBlock(String language = {})
Add a code block to the document root.
- Parameters:
language – The optional language identifier.
-
TextNodePtr addCodeSnippet(CodeSnippet snippet, CodeSnippetMarkerList markers = {})
Add a line-oriented code snippet to the document root.
- Parameters:
snippet – The source excerpt to include.
markers – Optional marker ranges.
-
TextNodePtr addHorizontalLine()
Add a horizontal line to the document root.
-
TextNodePtr addText(String text)
Add plain text to the document root.
- Parameters:
text – The text content.
-
TextNodePtr addUnsupported(String text = {})
Add an unsupported-content block to the document root.
- Parameters:
text – The preserved content text.
-
TextNodePtr addError(String text = {})
Add an error-content block to the document root.
- Parameters:
text – The preserved error text.
-
bool isEmpty() const noexcept
Test if the document root has no children.
-
inline TextNodePtr root() noexcept
Access the document root node.
-
inline TextNodePtr root() const noexcept
Access the document root node.
-
TextDocument()
-
class TextNode : public std::enable_shared_from_this<TextNode>
A mutable node in a text document tree.
Public Types
-
using Type = TextNodeType
The node type wrapper.
-
using Level = int
Heading or nesting level.
Public Functions
-
TextNodePtr add(Type type)
Add a child node with the given type.
- Parameters:
type – The child node type.
- Returns:
The added child node.
-
TextNodePtr add(TextNodePtr child)
Add an existing detached child node.
- Parameters:
child – The child node to add. Must not be null.
- Returns:
The added child node.
-
TextNodePtr addParagraph()
Add a paragraph child.
-
TextNodePtr addSection()
Add a section child.
-
TextNodePtr addBlockquote()
Add a blockquote child.
-
TextNodePtr addLineBreak()
Add an explicit line-break child.
-
TextNodePtr addBulletList(Level level = 0)
Add a bullet-list child.
- Parameters:
level – The nesting level.
-
TextNodePtr addNumberedList(Level level = 0)
Add a numbered-list child.
- Parameters:
level – The nesting level.
-
TextNodePtr addListItem()
Add a list-item child matching this list node type.
-
TextNodePtr addBulletListItem()
Add a bullet-list-item child.
-
TextNodePtr addNumberedListItem()
Add a numbered-list-item child.
-
TextNodePtr addDefinitionList()
Add a definition-list child.
-
TextNodePtr addDefinitionTerm()
Add a definition-term child.
-
TextNodePtr addDefinitionDescription()
Add a definition-description child.
-
TextNodePtr addCodeBlock(String language = {})
Add a code-block child.
- Parameters:
language – The optional language identifier.
-
TextNodePtr addCodeSnippet(CodeSnippet snippet, CodeSnippetMarkerList markers = {})
Add a line-oriented code snippet child.
- Parameters:
snippet – The source excerpt to include.
markers – Optional marker ranges.
-
TextNodePtr addHorizontalLine()
Add a horizontal-line child.
-
TextNode &addEscapedText(const String &text, EscapeFormat format, EscapeAmount amount = EscapeAmount::Balanced)
Add safely escaped text as plain-text and escape-sequence children.
- Parameters:
text – The potentially unsafe text to append.
format – The escape format to use.
amount – The amount of text to escape.
- Returns:
This node.
-
TextNodePtr addEmphasis()
Add an emphasis child.
-
TextNodePtr addStrong()
Add a strong-emphasis child.
-
TextNodePtr addUnderline()
Add an underline child.
-
TextNodePtr addSpan()
Add a generic span child.
-
TextNodePtr addCode()
Add an inline-code child.
-
TextNodePtr addUnsupported(String text = {})
Add an unsupported-content child.
- Parameters:
text – The preserved content text.
-
TextNodePtr addError(String text = {})
Add an error-content child.
- Parameters:
text – The preserved error text.
-
bool hasChildren() const noexcept
Test if this node has child nodes.
-
inline const TextNodeList &children() const noexcept
Access the child nodes.
A text node guarantees that this list never contains null pointers. Child pointers can only be added through the node API, and null children are rejected before they can enter the tree.
-
bool hasParent() const noexcept
Test if this node has a parent.
-
TextNodePtr parent() const noexcept
Access the parent node, or an empty pointer for roots.
-
inline const TextNodeDataPtr &data() const noexcept
Access the optional node-specific metadata.
-
template<typename Fn>
TextWalkResult walk(Fn nodeFn) const Walk this node and all descendants in pre-order.
- Parameters:
nodeFn – The function called for every node.
- Returns:
The final walk result.
-
template<typename Fn>
bool anyOf(Fn nodeFn) const Test if any node in this tree matches a predicate.
- Parameters:
nodeFn – The predicate called for every node.
- Returns:
trueif any node matches.
-
bool contains(Type type) const
Test if this node tree contains a node with the given type.
- Parameters:
type – The node type to search for.
- Returns:
trueif this node or any descendant has the given type.
-
TextNodePtr clone() const
Create a deep copy of this node and all descendants.
- Returns:
The cloned node tree.
-
StringTree toDiagnosticTree() const
Convert this node tree into a diagnostic tree.
Public Static Functions
-
static TextNodePtr create(Type type)
Create a node with the given type.
- Parameters:
type – The node type.
- Returns:
The created node.
-
static TextNodePtr createDocument()
Create a document root node.
-
static TextNodePtr createParagraph()
Create a paragraph node.
-
static TextNodePtr createSection()
Create a section node.
-
static TextNodePtr createBlockquote()
Create a blockquote node.
-
static TextNodePtr createLineBreak()
Create an explicit line-break node.
-
static TextNodePtr createHeading(Level level)
Create a heading node.
- Parameters:
level – The heading level.
-
static TextNodePtr createBulletList(Level level)
Create a bullet-list node.
- Parameters:
level – The nesting level.
-
static TextNodePtr createNumberedList(Level level)
Create a numbered-list node.
- Parameters:
level – The nesting level.
-
static TextNodePtr createBulletListItem()
Create a bullet-list-item node.
-
static TextNodePtr createNumberedListItem()
Create a numbered-list-item node.
-
static TextNodePtr createDefinitionList()
Create a definition-list node.
-
static TextNodePtr createDefinitionTerm()
Create a definition-term node.
-
static TextNodePtr createDefinitionDescription()
Create a definition-description node.
-
static TextNodePtr createCodeBlock(String language = {})
Create a code-block node.
- Parameters:
language – The optional language identifier.
-
static TextNodePtr createCodeSnippet(CodeSnippet snippet, CodeSnippetMarkerList markers = {})
Create a line-oriented code snippet node.
- Parameters:
snippet – The source excerpt to include.
markers – Optional marker ranges.
-
static TextNodePtr createHorizontalLine()
Create a horizontal-line node.
-
static TextNodePtr createText(String text)
Create a plain text node.
- Parameters:
text – The text content.
-
static TextNodePtr createEmphasis()
Create an emphasis node.
-
static TextNodePtr createStrong()
Create a strong-emphasis node.
-
static TextNodePtr createUnderline()
Create an underline node.
-
static TextNodePtr createSpan()
Create a generic span node.
-
static TextNodePtr createLink(String url = {})
Create a link node.
- Parameters:
url – The link target.
-
static TextNodePtr createCode()
Create an inline code node.
-
using Type = TextNodeType
-
class TextNodeData
Extensible metadata attached to a text-document node.
Applications may derive their own data types and attach them to nodes with TextNode::setData(). The string representation is used by diagnostic trees.
Subclassed by erbsland::text::impl::CodeBlockData, erbsland::text::impl::CodeLineMarkerData, erbsland::text::impl::CodeSnippetData, erbsland::text::impl::LinkData
-
class TextNodeType
The semantic type of a text document node.
Public Types
-
enum Value
The raw semantic node type.
Values:
-
enumerator Document
The root node of a document.
-
enumerator Paragraph
A paragraph containing inline content.
-
enumerator Section
A structural section containing blocks.
-
enumerator Blockquote
A quoted block containing blocks.
-
enumerator LineBreak
An explicit line break.
-
enumerator Heading
A heading containing inline content.
-
enumerator BulletList
A bullet list containing list items.
-
enumerator NumberedList
A numbered list containing list items.
-
enumerator BulletListItem
A bullet-list item containing inline content and nested blocks.
-
enumerator NumberedListItem
A numbered-list item containing inline content and nested blocks.
-
enumerator DefinitionList
A definition list containing terms and descriptions.
-
enumerator DefinitionTerm
A definition term.
-
enumerator DefinitionDescription
A definition description.
-
enumerator TermList
A semantic term list with names and descriptions.
-
enumerator TermItem
A semantic term-list item.
-
enumerator TermName
A semantic term name.
-
enumerator TermDescription
A semantic term description.
-
enumerator FieldList
A form-like list of labeled fields.
-
enumerator FieldItem
One field-list item.
-
enumerator FieldLabel
The label of a field.
-
enumerator FieldContent
The primary content of a field.
-
enumerator CodeBlock
A block of code.
-
enumerator CodeSnippet
A line-oriented code snippet.
-
enumerator CodeLine
A line in a code snippet.
-
enumerator CodeLineNumber
A code snippet line number.
-
enumerator CodeLineText
A code snippet source text.
-
enumerator CodeLineMarker
A marker attached to one code snippet source line.
-
enumerator HorizontalLine
A horizontal separator.
-
enumerator Text
Plain inline text.
-
enumerator Emphasis
Emphasized inline content.
-
enumerator Strong
Strong inline content.
-
enumerator Underline
Underlined inline content.
-
enumerator Span
Generic inline span.
-
enumerator Link
Link inline content.
-
enumerator Code
Inline code.
-
enumerator OptionExecutable
Option output executable name.
-
enumerator OptionModule
Option output module name.
-
enumerator OptionName
Option output complete option name.
-
enumerator OptionShort
Option output short option name.
-
enumerator OptionLong
Option output long option name.
-
enumerator OptionMeta
Option output meta value.
-
enumerator OptionOptional
Option output optional placeholder.
-
enumerator OptionDetails
Option output inline details.
-
enumerator Separator
A semantic inline separator and wrapping opportunity.
-
enumerator EscapeSequence
An indivisible inline escape sequence.
-
enumerator Unsupported
Unsupported content preserved as text.
-
enumerator Error
Error content preserved as text.
-
enumerator None
No node type.
-
enumerator _count
-
enumerator Document
Public Functions
-
constexpr TextNodeType() noexcept = default
Create the empty node type.
-
constexpr bool operator==(const TextNodeType &other) const noexcept = default
Test if two node types are equal.
-
inline constexpr bool operator==(Value value) const noexcept
Test if this node type is the given raw value.
-
inline constexpr bool operator!=(Value value) const noexcept
Test if this node type is not the given raw value.
-
RenderClass renderClass() const noexcept
Get the broad rendering class of this node type.
-
bool isInline() const noexcept
Test if this type renders inline.
-
bool isTextContainer() const noexcept
Test if this type can directly contain text while parsing or building documents.
-
bool isListContainer() const noexcept
Test if this type is a list container.
-
bool isListItem() const noexcept
Test if this type is a list item.
-
bool isTermListElement() const noexcept
Test if this type is a term-list element.
-
bool isFieldListElement() const noexcept
Test if this type is a field-list element.
-
bool preserveWhitespace() const noexcept
Test if this type preserves whitespace when rendered as a paragraph-like block.
-
enum Value
-
class TextWalkResult : public erbsland::util::Result
The result of a text node walk call.
Public Functions
-
inline constexpr Result(const Value value)
Create a new result.
- Parameters:
value – The value of the result.
Public Static Attributes
-
static const TextWalkResult Success = Value::success<0>()
Successfully completed the walk.
-
static const TextWalkResult Stopped = Value::success<1>()
The user early stopped the walk successfully.
-
static const TextWalkResult Failure = Value::failure<0>()
The walk was stopped because of a failure.
-
inline constexpr Result(const Value value)