cl-termdown parses a restrained Markdown subset into terminal-oriented semantic spans. It preserves Unicode cell widths, whole-word wrapping, bullets and numbered lists, inline emphasis and code, bounded pipe tables, fenced syntax highlighting, and speculative streaming previews.
Rows are lists of neutral cons spans whose car is a keyword role and whose
cdr is text. The caller styles them.
(asdf:load-system :cl-termdown)
(let ((renderer (termdown:markdown-renderer-create :width 48)))
(termdown:markdown-render-line
renderer
"- render **strong** and `code` spans"))
;; => (((:PLAIN . " ")
;; (:BRAND . "• ")
;; (:PLAIN . "render ")
;; (:STRONG . "strong")
;; (:PLAIN . " and ")
;; (:CODE . "code")
;; (:PLAIN . " spans")))One renderer retains fenced-code and pipe-table state across logical lines.
Call markdown-render-line when a newline commits that logical line.
(multiple-value-bind (committed live retained)
(termdown:markdown-render-partial renderer "unfinished **strong")
(values committed live retained))markdown-renderer: stateful renderer classmarkdown-renderer-create: create a renderer with:widthmarkdown-renderer-width: read its effective row widthmarkdown-renderer-closed-code-source: the raw text of the fence that just closed, ornilonce another fence opens; its closing row ends in a:code-copyspan that applications may turn into a copy controlmarkdown-render-line: render and commit one logical linemarkdown-render-inline: render inline Markdown within an exact widthmarkdown-render-partial: preview an uncommitted logical line as three valuesmarkdown-render-finish: flush an unfinished buffered diagram as source at EOFmake-span,span-p,span-role,span-text: neutral(role . text)spansspans-width: total Unicode terminal-cell width of a span rowcolumn-widths: allocate cell-aware table column widthsfit-text: clip and align a single table cellspans-text: concatenate sanitized visible text, optionally as one linefit-spans: clip sanitized spans by cells without splitting graphemesrender-spans: render sanitized text with an optional trusted:style-functionaccepting(role text)and returning presentationmake-widget,widget-p,widget-role,widget-label,widget-action: a label shown like a span of its role that carries an application action; every span function above presents it as its labelpresentation-spans: replace widgets by the spans of their labelswidget-regions: the(start end action)character extents of the widgets in a row, indexingspans-text, from an optional:startoffsetshift-regions,region-action: move regions after their text is joined to other text, and find the action covering a character offsetselector-table-rows: span rows for a vertical Clinedi selector’s visible window as a table, with a selection marker, a label column, further columns from:column-functionsreturning strings or spans and aligned across the visible rows, and a heading row wherever:group-functionchanges group; columns empty in every visible row are left out, and the roles are keyword arguments
Semantic roles include :plain, :brand, :dim, :strong, :emphasis,
:code, :code-copy, and the :syntax-* roles produced by Colordiff.
./script/bootstrap
./script/checkscript/check runs CL-TERMDOWN/TESTS in an isolated source registry.
cl-termdown uses Clinedi for Unicode geometry and wrapping, Clermaid for terminal diagrams, ColorLisp and Colordiff for fenced-code highlighting, and Serapeum for declarations. Qlot pins the tested dependency revisions.
cl-termdown uses COLL-Attribution. The authoritative terms are in
LICENSE.lisp.
Fenced blocks tagged mermaid render through Clermaid when they close.
Read the original body from markdown-renderer-closed-code-source and use the
closing row’s :code-copy span to add a copy control. Unsupported, malformed,
excessively large, or too-wide diagrams display numbered source instead.
Open diagrams appear only in speculative previews. Call markdown-render-finish
at the end of a document or interrupted stream to display incomplete source.
See Clermaid’s README for the supported syntax.