Skip to content
lambda-symbolicsPublic

About

Mermaid diagrams as Common Lisp terminal text

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

21 Commits

Folders and files

Repository files navigation

Clermaid

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.

Usage

(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.

Supported Mermaid subset

The parser accepts one diagram header followed by the listed statements. This is an intentionally small terminal-oriented subset, not a general Mermaid implementation.

Flowcharts and graphs

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
Loading

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.

State diagrams

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.

Class and ER diagrams

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.

Sequence diagrams

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.

Limits

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.

Public conditions

  • mermaid-error is the base condition, with mermaid-error-reason and mermaid-error-position readers.
  • invalid-diagram reports malformed input.
  • unsupported-syntax reports syntax outside the supported subset.
  • diagram-too-wide provides diagram-too-wide-width and diagram-too-wide-required-width.
  • resource-limit-exceeded reports bounded resource failures.

Development

./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/.

Dependencies and license

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.

About

Mermaid diagrams as Common Lisp terminal text

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages