Clermaid renders a bounded, supported subset of Mermaid diagrams as plain terminal rows. It is intended for callers that already own terminal output, such as cl-termdown.
(asdf:load-system :clermaid)
(mapc #'write-line
(clermaid:render-mermaid
"flowchart LR
A[Source] --> B[Terminal]"))render-mermaid accepts (source &key (width 120) (unicode t)) and returns a
fresh list of printable strings, one string per terminal row. width is a
terminal-cell limit. unicode selects Unicode box and line characters; it does
not change the source text. The renderer emits no ANSI sequences, performs no
terminal I/O, and starts no subprocesses. Unicode grapheme and cell-width
handling is provided by Clinedi.
For colored output, call render-mermaid-spans with the same arguments. Each
row contains (role . text) spans: :mermaid-box, :mermaid-edge,
:mermaid-arrow, :mermaid-label, and :plain. Choose colors in the caller.
Roles come from drawing operations, including when labels contain line or
arrow characters. Concatenating each row’s span text gives the plain row.
A caller can handle clermaid:mermaid-error and display the original source
when a diagram is malformed, unsupported, too wide, or exceeds a resource
limit. A too-narrow width is an error: Clermaid does not scale or truncate
output. The retry-with-width restart is available when a caller wants to
retry with a different budget.
The parser accepts one diagram header followed by the listed statements. This is an intentionally small terminal-oriented subset, not a general Mermaid implementation.
Use flowchart or graph, optionally followed by TB, TD, BT, LR,
or RL. Connect nodes with -->, ---, -.->, or -.-; chains and
&-separated groups are supported. Add edge labels with -->|label|.
Node labels use [], (), {}, or ([label]) for rectangular, rounded,
decision, or stadium boxes. Quote label text to include delimiters.
Use %% comments and newlines or semicolons between statements.
Use subgraph ID[Label] with a matching end to draw a group frame.
Labels can be quoted, as in subgraph backend["Data services"].
A bare or quoted title also works: subgraph Data services or
subgraph "Data services". An unlabelled single-word title is also its ID.
Use explicit single-word IDs when connecting edges to a group.
Nest subgraphs to retain containment. Put direction LR, RL, TD,
TB, or BT inside a group to set its local layout direction; groups
without this statement inherit their parent’s direction. Local directions
apply even when nodes connect across group boundaries. Each node belongs to
the first subgraph in which it occurs. Later references do not move it.
Group IDs share the node namespace and must be unique.
Edges can connect nodes across groups and whole groups in separate branches.
An edge between a group and one of its own descendants (a node or a nested
group) signals invalid-diagram during parsing, in either direction.
Frames permit perpendicular edge crossings; labels and node boxes are protected.
Each scope is laid out with child groups as whole rectangles, so sibling frames
and their contents do not overlap. Edge labels use the same adjacent-label or
legend placement as other graph edges.
Empty groups are supported.
flowchart LR
subgraph app["Application"]
direction TD
A[Request] --> B[Response]
end
subgraph storage["Storage"]
C[Database]
end
B --> C
app --> storage
Graph layers are centered and reordered to reduce crossings. Connection ports follow the order of the opposite nodes. Routing favors fewer crossings before shorter paths, then avoids extra bends; Unicode routes use rounded corners and directional end caps.
Headers are stateDiagram or stateDiagram-v2. The supported transition form
is left --> right, with optional labels and aliases. The initial and final
pseudostate spelling [*] is supported. This is the flat transition subset;
state descriptions and composite-state syntax are not part of this API.
Use classDiagram with class Name declarations and optional multiline
{ ... } member blocks. Supported class relations are <|--, --|>,
*--, o--, ..>, --.., -->, and ---.
Use erDiagram with NAME { attribute blocks and relation statements such
as USER ||--o{ ORDER : places. Left cardinalities are ||, |o, }o,
and }|; right cardinalities are ||, o|, o{, and |{. Join them with
-- or ... Put member lines and the closing } on separate lines.
Class and ER diagrams have connected boxes with member compartments. Relation tokens appear beside connections as text annotations rather than UML or crow-foot endpoint drawings.
Use sequenceDiagram with participant ID or actor ID declarations,
optionally followed by as Label. Both render as named header boxes.
IDs start with a letter, digit, or underscore, followed by letters, digits,
underscores, or hyphens. Implicit participants follow first-encounter order.
Message arrows are ->, -->, ->>, -->>, -x, --x, -), and --),
with an optional : label. Messages include reverse-direction replies and
self-calls. Use nested alt / else, loop, or opt frames with matching
end. Notes support Note over A,B:, Note over A:, Note left of A:,
and Note right of A: forms.
The implementation rejects input or output beyond these bounds:
- source: 65,536 characters
- nodes and flowchart subgraphs together: 64
- nested flowchart subgraphs: 16
- graph edges or sequence events: 128
- output: 256 rows and 2,048 columns
Individual renderers can also reject a diagram whose required width exceeds the
requested width. Limit failures signal resource-limit-exceeded;
malformed input signals invalid-diagram; unsupported families or constructs
signal unsupported-syntax; width failures signal diagram-too-wide.
mermaid-erroris the base condition, withmermaid-error-reasonandmermaid-error-positionreaders.invalid-diagramreports malformed input.unsupported-syntaxreports syntax outside the supported subset.diagram-too-wideprovidesdiagram-too-wide-widthanddiagram-too-wide-required-width.resource-limit-exceededreports bounded resource failures.
./script/bootstrap
./script/check
./script/check --fix./script/check loads this checkout through an isolated source registry and
runs ASDF’s clermaid/tests system in a fresh SBCL process. It then checks the
source with cheque as
cheque.sexp configures it. --fix skips the tests and repairs what cheque can
repair. cheque and its tools are development dependencies: checks/qlfile
lists them, and the check installs them on first use into
~/.cache/cheque/tools/.
Clermaid depends on Clinedi for grapheme boundaries and terminal-cell widths. Qlot records the exact dependency revisions used by the checks.
The license is COLL-Attribution; see LICENSE.lisp.