termrender 4.3.2__tar.gz → 4.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {termrender-4.3.2 → termrender-4.5.0}/CHANGELOG.md +33 -0
- {termrender-4.3.2 → termrender-4.5.0}/PKG-INFO +2 -1
- {termrender-4.3.2 → termrender-4.5.0}/pyproject.toml +1 -0
- termrender-4.5.0/src/termrender/renderers/mermaid_flow.py +110 -0
- termrender-4.5.0/src/termrender/renderers/mermaid_flow_layout.py +952 -0
- termrender-4.5.0/src/termrender/renderers/mermaid_flow_parser.py +406 -0
- termrender-4.5.0/tests/test_mermaid_flow.py +168 -0
- termrender-4.5.0/tests/test_mermaid_flow_layout.py +386 -0
- termrender-4.5.0/tests/test_mermaid_flow_parser.py +356 -0
- {termrender-4.3.2 → termrender-4.5.0}/.github/workflows/publish.yml +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/.gitignore +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/CLAUDE.md +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/LICENSE +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/README.md +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/design.json +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/requirements.json +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/scripts/build-mermaid-ascii.sh +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/src/termrender/CLAUDE.md +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/src/termrender/__init__.py +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/src/termrender/__main__.py +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/src/termrender/_bin/mermaid-ascii-darwin-arm64 +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/src/termrender/_mermaid_bin.py +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/src/termrender/blocks.py +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/src/termrender/emit.py +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/src/termrender/layout.py +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/src/termrender/parser.py +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/src/termrender/py.typed +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/src/termrender/renderers/CLAUDE.md +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/src/termrender/renderers/__init__.py +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/src/termrender/renderers/borders.py +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/src/termrender/renderers/charts.py +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/src/termrender/renderers/code.py +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/src/termrender/renderers/columns.py +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/src/termrender/renderers/diff.py +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/src/termrender/renderers/divider.py +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/src/termrender/renderers/mermaid.py +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/src/termrender/renderers/mermaid_flow_model.py +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/src/termrender/renderers/mermaid_gantt.py +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/src/termrender/renderers/mermaid_journey.py +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/src/termrender/renderers/mermaid_mindmap.py +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/src/termrender/renderers/mermaid_pie.py +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/src/termrender/renderers/mermaid_prelude.py +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/src/termrender/renderers/mermaid_sequence.py +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/src/termrender/renderers/mermaid_timeline.py +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/src/termrender/renderers/panel.py +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/src/termrender/renderers/quote.py +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/src/termrender/renderers/stat.py +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/src/termrender/renderers/table.py +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/src/termrender/renderers/text.py +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/src/termrender/renderers/timeline.py +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/src/termrender/renderers/tree.py +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/src/termrender/style.py +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/tests/__init__.py +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/tests/test_charts.py +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/tests/test_cli_contract.py +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/tests/test_column_alignment.py +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/tests/test_diff.py +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/tests/test_inline_badge.py +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/tests/test_linebreak.py +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/tests/test_mermaid_compat.py +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/tests/test_mermaid_dispatch.py +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/tests/test_mermaid_flow_model.py +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/tests/test_mermaid_gantt.py +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/tests/test_mermaid_journey.py +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/tests/test_mermaid_mindmap.py +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/tests/test_mermaid_pie.py +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/tests/test_mermaid_sequence.py +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/tests/test_mermaid_timeline.py +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/tests/test_myst_gaps.py +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/tests/test_stat.py +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/tests/test_tasklist.py +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/tests/test_timeline.py +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/tests/test_variable_colons.py +0 -0
- {termrender-4.3.2 → termrender-4.5.0}/uv.lock +0 -0
|
@@ -1,6 +1,39 @@
|
|
|
1
1
|
# CHANGELOG
|
|
2
2
|
|
|
3
3
|
|
|
4
|
+
## v4.5.0 (2026-07-06)
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
- Add flowchart edge router and public render_flowchart
|
|
9
|
+
([`a1b46cf`](https://github.com/crouton-labs/termrender/commit/a1b46cf11607ec6b31ea8fe1b4d90b11aafff10f))
|
|
10
|
+
|
|
11
|
+
- Replace the placeholder edge drawing in mermaid_flow_layout.py with the full orthogonal router:
|
|
12
|
+
rank-relative endpoint anchors (forward/same-rank/ back-edge), L/Z staircase paths for forward
|
|
13
|
+
edges, growing side-lane C-paths for back-edges so they never overlay forward edges, arrowheads
|
|
14
|
+
chosen from final-segment direction, edge labels centered on the longest straight run (shifting
|
|
15
|
+
off reserved cells), and self-loops modeled on the sequence renderer's self-message loop. - Add
|
|
16
|
+
mermaid_flow.py exposing the public, pure, never-raising render_flowchart(source, width) ->
|
|
17
|
+
list[str], wiring parse -> layout_flowgraph -> lines behind the three-case degradation contract
|
|
18
|
+
(no header, zero nodes, unexpected layout exception -> raw echo). - Add
|
|
19
|
+
tests/test_mermaid_flow.py: real end-to-end geometry/topology assertions, including the labeled
|
|
20
|
+
back-edge cycle that panics the Go binary, multi-parent attachment, headless edges, and echo
|
|
21
|
+
degradation.
|
|
22
|
+
|
|
23
|
+
Unwired: nothing imports mermaid_flow yet (later phase's cutover).
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
## v4.4.0 (2026-07-06)
|
|
27
|
+
|
|
28
|
+
### Features
|
|
29
|
+
|
|
30
|
+
- Add flowchart layout engine core (grandalf adapter + canvas rasterizer)
|
|
31
|
+
([`23e26e9`](https://github.com/crouton-labs/termrender/commit/23e26e9c3228bfac302c270b4c0c5ffe880bfc20))
|
|
32
|
+
|
|
33
|
+
- Add flowchart mermaid parser
|
|
34
|
+
([`c9c80c3`](https://github.com/crouton-labs/termrender/commit/c9c80c30ed638c3532ef9464ce1cb7f4af4fa3ce))
|
|
35
|
+
|
|
36
|
+
|
|
4
37
|
## v4.3.2 (2026-07-06)
|
|
5
38
|
|
|
6
39
|
### Bug Fixes
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: termrender
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.5.0
|
|
4
4
|
Summary: Rich terminal rendering of directive-flavored markdown
|
|
5
5
|
Project-URL: Homepage, https://github.com/CaptainCrouton89/termrender
|
|
6
6
|
Project-URL: Repository, https://github.com/CaptainCrouton89/termrender
|
|
@@ -21,6 +21,7 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
21
21
|
Classifier: Topic :: Terminals
|
|
22
22
|
Classifier: Topic :: Text Processing :: Markup :: Markdown
|
|
23
23
|
Requires-Python: >=3.10
|
|
24
|
+
Requires-Dist: grandalf>=0.8
|
|
24
25
|
Requires-Dist: mermaid-ascii>=1.2
|
|
25
26
|
Requires-Dist: mistune>=3.0
|
|
26
27
|
Requires-Dist: pygments>=2.0
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"""Public entry point for the native mermaid flowchart/graph renderer.
|
|
2
|
+
|
|
3
|
+
Standalone module: exposes a single pure function, :func:`render_flowchart`.
|
|
4
|
+
Not yet wired into ``mermaid.py``'s dispatcher (a later, orchestrator-owned
|
|
5
|
+
phase) — nothing in this package imports it. This module is a thin
|
|
6
|
+
orchestrator over the parser and layout engine; it owns none of the grammar
|
|
7
|
+
or layout logic itself, only header sniffing and the degradation contract.
|
|
8
|
+
|
|
9
|
+
Layout model
|
|
10
|
+
------------
|
|
11
|
+
``render_flowchart`` is ``parse -> layout_flowgraph -> lines``, wrapped in a
|
|
12
|
+
degradation guard (see *Degradation contract* below). :func:`~termrender.
|
|
13
|
+
renderers.mermaid_flow_parser.parse` turns mermaid source into a
|
|
14
|
+
:class:`~termrender.renderers.mermaid_flow_model.FlowGraph`;
|
|
15
|
+
:func:`~termrender.renderers.mermaid_flow_layout.layout_flowgraph` lays it
|
|
16
|
+
out with ``grandalf`` (pure-Python Sugiyama) and rasterizes it — bordered
|
|
17
|
+
rectangle nodes, an orthogonal edge router (L/Z paths for forward edges,
|
|
18
|
+
growing side lanes for back-edges/cycles, arrowheads, edge labels,
|
|
19
|
+
self-loops) — onto a char grid. See ``mermaid_flow_parser.py`` and
|
|
20
|
+
``mermaid_flow_layout.py``'s module docstrings for the full grammar and
|
|
21
|
+
routing model; this module covers only the public contract.
|
|
22
|
+
|
|
23
|
+
Grammar supported
|
|
24
|
+
------------------
|
|
25
|
+
Header: ``graph``/``flowchart`` + direction (``TD``/``TB``/``LR``/``RL``/
|
|
26
|
+
``BT``). Node shapes: ``[rect]``, ``(round)``, ``([stadium])``,
|
|
27
|
+
``[(cylinder)]``, ``((circle))``, ``{diamond}``, ``{{hexagon}}``,
|
|
28
|
+
``[[subroutine]]``, ``[/parallelogram/]`` — this phase renders every shape
|
|
29
|
+
as a plain rectangle (distinct shape borders are a later phase; only the
|
|
30
|
+
label text is load-bearing here). Edges: ``-->``, ``---``, ``-.->``, ``==>``
|
|
31
|
+
(and bidirectional forms), with ``|label|`` and inline ``A -- text --> B``
|
|
32
|
+
labels, and ``&`` fan-out. ``subgraph ... end`` blocks parse but are not yet
|
|
33
|
+
rendered as frames (nodes inside them still place and render normally).
|
|
34
|
+
``class``/``classDef``/``style``/``click``/``linkStyle`` lines are ignored.
|
|
35
|
+
|
|
36
|
+
Known degradations (by design, not bugs)
|
|
37
|
+
-----------------------------------------
|
|
38
|
+
- Node shapes other than a plain rectangle border are not yet visually
|
|
39
|
+
distinct (Phase 4 of this renderer's build).
|
|
40
|
+
- Subgraph blocks parse but are not yet drawn as enclosing frames (Phase 4).
|
|
41
|
+
- See ``mermaid_flow_layout.py``'s module docstring for the edge-routing
|
|
42
|
+
degradations (dense-graph crossings, label-lane overlap, CJK wrapping,
|
|
43
|
+
minimum-box-size self-loop cosmetics).
|
|
44
|
+
- ``width`` is advisory only: like the other native renderers in this
|
|
45
|
+
package, this renderer sizes to content and may overflow a narrow
|
|
46
|
+
terminal rather than truncate the diagram.
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
from __future__ import annotations
|
|
50
|
+
|
|
51
|
+
from termrender.renderers.mermaid_flow_layout import layout_flowgraph
|
|
52
|
+
from termrender.renderers.mermaid_flow_parser import FlowchartError, parse
|
|
53
|
+
|
|
54
|
+
__all__ = ["render_flowchart"]
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def render_flowchart(source: str, width: int) -> list[str]:
|
|
58
|
+
"""Render a mermaid ``graph``/``flowchart`` source to unicode lines.
|
|
59
|
+
|
|
60
|
+
Pure and total: never raises. Degrades to a raw echo of ``source``
|
|
61
|
+
(each line ``\\n``-split and ``.rstrip()``-ed, containing no
|
|
62
|
+
box-drawing glyphs) exactly when:
|
|
63
|
+
|
|
64
|
+
1. The source isn't a flowchart at all (no ``graph``/``flowchart``
|
|
65
|
+
header on its first non-blank, post-prelude line) — :func:`parse`
|
|
66
|
+
raises :class:`FlowchartError`.
|
|
67
|
+
2. Parsing succeeds but yields zero nodes (an empty or comment-only
|
|
68
|
+
diagram body) — nothing to draw.
|
|
69
|
+
3. Any unexpected exception escapes :func:`layout_flowgraph` — a
|
|
70
|
+
defensive catch-all; this should never happen for well-typed input,
|
|
71
|
+
but the guarantee is "never crash, degrade" regardless.
|
|
72
|
+
|
|
73
|
+
Otherwise, returns the rendered diagram: guaranteed to contain unicode
|
|
74
|
+
box-drawing glyphs (every node is a bordered box), never ANSI escapes.
|
|
75
|
+
The distinction matters downstream — code that detects render success
|
|
76
|
+
by the *presence* of box-drawing glyphs relies on the echo path never
|
|
77
|
+
emitting any.
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
source: The mermaid fence body (with or without the surrounding
|
|
81
|
+
fence markers — only the text between them).
|
|
82
|
+
width: Advisory terminal width. See the module docstring's
|
|
83
|
+
"Known degradations" for why this is advisory rather than a
|
|
84
|
+
hard wrap.
|
|
85
|
+
|
|
86
|
+
Returns:
|
|
87
|
+
Rendered lines on success, or a raw-echo of ``source`` on any of
|
|
88
|
+
the three degradation conditions above.
|
|
89
|
+
"""
|
|
90
|
+
try:
|
|
91
|
+
graph = parse(source)
|
|
92
|
+
except FlowchartError:
|
|
93
|
+
return _raw_echo(source)
|
|
94
|
+
|
|
95
|
+
if not graph.nodes:
|
|
96
|
+
return _raw_echo(source)
|
|
97
|
+
|
|
98
|
+
try:
|
|
99
|
+
lines = layout_flowgraph(graph, width)
|
|
100
|
+
except Exception:
|
|
101
|
+
return _raw_echo(source)
|
|
102
|
+
|
|
103
|
+
if not lines:
|
|
104
|
+
return _raw_echo(source)
|
|
105
|
+
|
|
106
|
+
return lines
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def _raw_echo(source: str) -> list[str]:
|
|
110
|
+
return [line.rstrip() for line in source.splitlines()]
|