termrender 4.4.0__tar.gz → 4.6.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.
Files changed (76) hide show
  1. {termrender-4.4.0 → termrender-4.6.0}/CHANGELOG.md +53 -0
  2. {termrender-4.4.0 → termrender-4.6.0}/PKG-INFO +1 -1
  3. termrender-4.6.0/src/termrender/renderers/mermaid_flow.py +110 -0
  4. termrender-4.6.0/src/termrender/renderers/mermaid_flow_layout.py +1460 -0
  5. termrender-4.6.0/tests/test_mermaid_flow.py +168 -0
  6. termrender-4.6.0/tests/test_mermaid_flow_shapes.py +313 -0
  7. termrender-4.4.0/src/termrender/renderers/mermaid_flow_layout.py +0 -602
  8. {termrender-4.4.0 → termrender-4.6.0}/.github/workflows/publish.yml +0 -0
  9. {termrender-4.4.0 → termrender-4.6.0}/.gitignore +0 -0
  10. {termrender-4.4.0 → termrender-4.6.0}/CLAUDE.md +0 -0
  11. {termrender-4.4.0 → termrender-4.6.0}/LICENSE +0 -0
  12. {termrender-4.4.0 → termrender-4.6.0}/README.md +0 -0
  13. {termrender-4.4.0 → termrender-4.6.0}/design.json +0 -0
  14. {termrender-4.4.0 → termrender-4.6.0}/pyproject.toml +0 -0
  15. {termrender-4.4.0 → termrender-4.6.0}/requirements.json +0 -0
  16. {termrender-4.4.0 → termrender-4.6.0}/scripts/build-mermaid-ascii.sh +0 -0
  17. {termrender-4.4.0 → termrender-4.6.0}/src/termrender/CLAUDE.md +0 -0
  18. {termrender-4.4.0 → termrender-4.6.0}/src/termrender/__init__.py +0 -0
  19. {termrender-4.4.0 → termrender-4.6.0}/src/termrender/__main__.py +0 -0
  20. {termrender-4.4.0 → termrender-4.6.0}/src/termrender/_bin/mermaid-ascii-darwin-arm64 +0 -0
  21. {termrender-4.4.0 → termrender-4.6.0}/src/termrender/_mermaid_bin.py +0 -0
  22. {termrender-4.4.0 → termrender-4.6.0}/src/termrender/blocks.py +0 -0
  23. {termrender-4.4.0 → termrender-4.6.0}/src/termrender/emit.py +0 -0
  24. {termrender-4.4.0 → termrender-4.6.0}/src/termrender/layout.py +0 -0
  25. {termrender-4.4.0 → termrender-4.6.0}/src/termrender/parser.py +0 -0
  26. {termrender-4.4.0 → termrender-4.6.0}/src/termrender/py.typed +0 -0
  27. {termrender-4.4.0 → termrender-4.6.0}/src/termrender/renderers/CLAUDE.md +0 -0
  28. {termrender-4.4.0 → termrender-4.6.0}/src/termrender/renderers/__init__.py +0 -0
  29. {termrender-4.4.0 → termrender-4.6.0}/src/termrender/renderers/borders.py +0 -0
  30. {termrender-4.4.0 → termrender-4.6.0}/src/termrender/renderers/charts.py +0 -0
  31. {termrender-4.4.0 → termrender-4.6.0}/src/termrender/renderers/code.py +0 -0
  32. {termrender-4.4.0 → termrender-4.6.0}/src/termrender/renderers/columns.py +0 -0
  33. {termrender-4.4.0 → termrender-4.6.0}/src/termrender/renderers/diff.py +0 -0
  34. {termrender-4.4.0 → termrender-4.6.0}/src/termrender/renderers/divider.py +0 -0
  35. {termrender-4.4.0 → termrender-4.6.0}/src/termrender/renderers/mermaid.py +0 -0
  36. {termrender-4.4.0 → termrender-4.6.0}/src/termrender/renderers/mermaid_flow_model.py +0 -0
  37. {termrender-4.4.0 → termrender-4.6.0}/src/termrender/renderers/mermaid_flow_parser.py +0 -0
  38. {termrender-4.4.0 → termrender-4.6.0}/src/termrender/renderers/mermaid_gantt.py +0 -0
  39. {termrender-4.4.0 → termrender-4.6.0}/src/termrender/renderers/mermaid_journey.py +0 -0
  40. {termrender-4.4.0 → termrender-4.6.0}/src/termrender/renderers/mermaid_mindmap.py +0 -0
  41. {termrender-4.4.0 → termrender-4.6.0}/src/termrender/renderers/mermaid_pie.py +0 -0
  42. {termrender-4.4.0 → termrender-4.6.0}/src/termrender/renderers/mermaid_prelude.py +0 -0
  43. {termrender-4.4.0 → termrender-4.6.0}/src/termrender/renderers/mermaid_sequence.py +0 -0
  44. {termrender-4.4.0 → termrender-4.6.0}/src/termrender/renderers/mermaid_timeline.py +0 -0
  45. {termrender-4.4.0 → termrender-4.6.0}/src/termrender/renderers/panel.py +0 -0
  46. {termrender-4.4.0 → termrender-4.6.0}/src/termrender/renderers/quote.py +0 -0
  47. {termrender-4.4.0 → termrender-4.6.0}/src/termrender/renderers/stat.py +0 -0
  48. {termrender-4.4.0 → termrender-4.6.0}/src/termrender/renderers/table.py +0 -0
  49. {termrender-4.4.0 → termrender-4.6.0}/src/termrender/renderers/text.py +0 -0
  50. {termrender-4.4.0 → termrender-4.6.0}/src/termrender/renderers/timeline.py +0 -0
  51. {termrender-4.4.0 → termrender-4.6.0}/src/termrender/renderers/tree.py +0 -0
  52. {termrender-4.4.0 → termrender-4.6.0}/src/termrender/style.py +0 -0
  53. {termrender-4.4.0 → termrender-4.6.0}/tests/__init__.py +0 -0
  54. {termrender-4.4.0 → termrender-4.6.0}/tests/test_charts.py +0 -0
  55. {termrender-4.4.0 → termrender-4.6.0}/tests/test_cli_contract.py +0 -0
  56. {termrender-4.4.0 → termrender-4.6.0}/tests/test_column_alignment.py +0 -0
  57. {termrender-4.4.0 → termrender-4.6.0}/tests/test_diff.py +0 -0
  58. {termrender-4.4.0 → termrender-4.6.0}/tests/test_inline_badge.py +0 -0
  59. {termrender-4.4.0 → termrender-4.6.0}/tests/test_linebreak.py +0 -0
  60. {termrender-4.4.0 → termrender-4.6.0}/tests/test_mermaid_compat.py +0 -0
  61. {termrender-4.4.0 → termrender-4.6.0}/tests/test_mermaid_dispatch.py +0 -0
  62. {termrender-4.4.0 → termrender-4.6.0}/tests/test_mermaid_flow_layout.py +0 -0
  63. {termrender-4.4.0 → termrender-4.6.0}/tests/test_mermaid_flow_model.py +0 -0
  64. {termrender-4.4.0 → termrender-4.6.0}/tests/test_mermaid_flow_parser.py +0 -0
  65. {termrender-4.4.0 → termrender-4.6.0}/tests/test_mermaid_gantt.py +0 -0
  66. {termrender-4.4.0 → termrender-4.6.0}/tests/test_mermaid_journey.py +0 -0
  67. {termrender-4.4.0 → termrender-4.6.0}/tests/test_mermaid_mindmap.py +0 -0
  68. {termrender-4.4.0 → termrender-4.6.0}/tests/test_mermaid_pie.py +0 -0
  69. {termrender-4.4.0 → termrender-4.6.0}/tests/test_mermaid_sequence.py +0 -0
  70. {termrender-4.4.0 → termrender-4.6.0}/tests/test_mermaid_timeline.py +0 -0
  71. {termrender-4.4.0 → termrender-4.6.0}/tests/test_myst_gaps.py +0 -0
  72. {termrender-4.4.0 → termrender-4.6.0}/tests/test_stat.py +0 -0
  73. {termrender-4.4.0 → termrender-4.6.0}/tests/test_tasklist.py +0 -0
  74. {termrender-4.4.0 → termrender-4.6.0}/tests/test_timeline.py +0 -0
  75. {termrender-4.4.0 → termrender-4.6.0}/tests/test_variable_colons.py +0 -0
  76. {termrender-4.4.0 → termrender-4.6.0}/uv.lock +0 -0
@@ -1,6 +1,59 @@
1
1
  # CHANGELOG
2
2
 
3
3
 
4
+ ## v4.6.0 (2026-07-06)
5
+
6
+ ### Features
7
+
8
+ - Add flowchart node shapes, subgraph frames, and direction rendering
9
+ ([`e872199`](https://github.com/crouton-labs/termrender/commit/e87219956294319feb0015d2cf4573b8cc60a0cb))
10
+
11
+ Applies and hardens the salvaged decoration work for the native mermaid flowchart renderer's layout
12
+ engine:
13
+
14
+ - Nine distinct node-shape borders (rect, round, stadium, cylinder, circle, diamond, hexagon,
15
+ subroutine, parallelogram), each reserving its full bounding box so the router treats every shape
16
+ as impassable. - Subgraph enclosure frames (left-anchored title, nested, flatten when members
17
+ aren't placed contiguously enough for a clean rect). - TB/BT/LR/RL direction handling via a
18
+ post-layout coordinate transform.
19
+
20
+ Fixes found while hardening: - draw_frame now reserves the title text cells (not the whole border)
21
+ so a cross-boundary edge crossing a frame's top border can no longer clobber a letter of the
22
+ subgraph title. - Subgraph frame sizing is now computed bottom-up (_build_subgraph_frames): a
23
+ parent subgraph's extent is built from its children's *padded frame rects* (when they get a frame)
24
+ rather than raw member extents, so a nested subgraph whose members share the same column/row span
25
+ as its parent no longer produces an identically-sized frame that overwrites the parent's border —
26
+ nesting now always has real margin. - Corrected the module docstring's stale "every node renders
27
+ as a plain rectangle, frames not yet wired" description to match the shipped shape/frame drawers.
28
+
29
+ Adds tests/test_mermaid_flow_shapes.py: real-geometry assertions for shape distinctness, a 9-shape
30
+ gallery, subgraph frame containment, nested-frame non-overlap, non-contiguous-subgraph flatten,
31
+ LR/RL/BT topology + arrowhead direction, LR same-rank spacing, and router avoidance of a diamond's
32
+ interior. Full suite: 437 passed (422 existing + 15 new), no regressions.
33
+
34
+
35
+ ## v4.5.0 (2026-07-06)
36
+
37
+ ### Features
38
+
39
+ - Add flowchart edge router and public render_flowchart
40
+ ([`a1b46cf`](https://github.com/crouton-labs/termrender/commit/a1b46cf11607ec6b31ea8fe1b4d90b11aafff10f))
41
+
42
+ - Replace the placeholder edge drawing in mermaid_flow_layout.py with the full orthogonal router:
43
+ rank-relative endpoint anchors (forward/same-rank/ back-edge), L/Z staircase paths for forward
44
+ edges, growing side-lane C-paths for back-edges so they never overlay forward edges, arrowheads
45
+ chosen from final-segment direction, edge labels centered on the longest straight run (shifting
46
+ off reserved cells), and self-loops modeled on the sequence renderer's self-message loop. - Add
47
+ mermaid_flow.py exposing the public, pure, never-raising render_flowchart(source, width) ->
48
+ list[str], wiring parse -> layout_flowgraph -> lines behind the three-case degradation contract
49
+ (no header, zero nodes, unexpected layout exception -> raw echo). - Add
50
+ tests/test_mermaid_flow.py: real end-to-end geometry/topology assertions, including the labeled
51
+ back-edge cycle that panics the Go binary, multi-parent attachment, headless edges, and echo
52
+ degradation.
53
+
54
+ Unwired: nothing imports mermaid_flow yet (later phase's cutover).
55
+
56
+
4
57
  ## v4.4.0 (2026-07-06)
5
58
 
6
59
  ### Features
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: termrender
3
- Version: 4.4.0
3
+ Version: 4.6.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
@@ -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()]