termrender 2.0.0__tar.gz → 2.1.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-2.0.0 → termrender-2.1.0}/CHANGELOG.md +32 -0
- {termrender-2.0.0 → termrender-2.1.0}/PKG-INFO +2 -2
- {termrender-2.0.0 → termrender-2.1.0}/pyproject.toml +6 -1
- termrender-2.1.0/scripts/build-mermaid-ascii.sh +36 -0
- termrender-2.1.0/src/termrender/CLAUDE.md +1 -0
- termrender-2.1.0/src/termrender/_bin/mermaid-ascii-darwin-arm64 +0 -0
- termrender-2.1.0/src/termrender/_mermaid_bin.py +41 -0
- {termrender-2.0.0 → termrender-2.1.0}/src/termrender/layout.py +2 -1
- {termrender-2.0.0 → termrender-2.1.0}/src/termrender/renderers/CLAUDE.md +2 -0
- {termrender-2.0.0 → termrender-2.1.0}/src/termrender/renderers/borders.py +1 -1
- {termrender-2.0.0 → termrender-2.1.0}/src/termrender/renderers/mermaid.py +2 -1
- termrender-2.0.0/src/termrender/CLAUDE.md +0 -15
- {termrender-2.0.0 → termrender-2.1.0}/.github/workflows/publish.yml +0 -0
- {termrender-2.0.0 → termrender-2.1.0}/.gitignore +0 -0
- {termrender-2.0.0 → termrender-2.1.0}/CLAUDE.md +0 -0
- {termrender-2.0.0 → termrender-2.1.0}/LICENSE +0 -0
- {termrender-2.0.0 → termrender-2.1.0}/README.md +0 -0
- {termrender-2.0.0 → termrender-2.1.0}/design.json +0 -0
- {termrender-2.0.0 → termrender-2.1.0}/requirements.json +0 -0
- {termrender-2.0.0 → termrender-2.1.0}/src/termrender/__init__.py +0 -0
- {termrender-2.0.0 → termrender-2.1.0}/src/termrender/__main__.py +0 -0
- {termrender-2.0.0 → termrender-2.1.0}/src/termrender/blocks.py +0 -0
- {termrender-2.0.0 → termrender-2.1.0}/src/termrender/emit.py +0 -0
- {termrender-2.0.0 → termrender-2.1.0}/src/termrender/parser.py +0 -0
- {termrender-2.0.0 → termrender-2.1.0}/src/termrender/py.typed +0 -0
- {termrender-2.0.0 → termrender-2.1.0}/src/termrender/renderers/__init__.py +0 -0
- {termrender-2.0.0 → termrender-2.1.0}/src/termrender/renderers/charts.py +0 -0
- {termrender-2.0.0 → termrender-2.1.0}/src/termrender/renderers/code.py +0 -0
- {termrender-2.0.0 → termrender-2.1.0}/src/termrender/renderers/columns.py +0 -0
- {termrender-2.0.0 → termrender-2.1.0}/src/termrender/renderers/diff.py +0 -0
- {termrender-2.0.0 → termrender-2.1.0}/src/termrender/renderers/divider.py +0 -0
- {termrender-2.0.0 → termrender-2.1.0}/src/termrender/renderers/panel.py +0 -0
- {termrender-2.0.0 → termrender-2.1.0}/src/termrender/renderers/quote.py +0 -0
- {termrender-2.0.0 → termrender-2.1.0}/src/termrender/renderers/stat.py +0 -0
- {termrender-2.0.0 → termrender-2.1.0}/src/termrender/renderers/table.py +0 -0
- {termrender-2.0.0 → termrender-2.1.0}/src/termrender/renderers/text.py +0 -0
- {termrender-2.0.0 → termrender-2.1.0}/src/termrender/renderers/timeline.py +0 -0
- {termrender-2.0.0 → termrender-2.1.0}/src/termrender/renderers/tree.py +0 -0
- {termrender-2.0.0 → termrender-2.1.0}/src/termrender/style.py +0 -0
- {termrender-2.0.0 → termrender-2.1.0}/tests/__init__.py +0 -0
- {termrender-2.0.0 → termrender-2.1.0}/tests/test_charts.py +0 -0
- {termrender-2.0.0 → termrender-2.1.0}/tests/test_cli_contract.py +0 -0
- {termrender-2.0.0 → termrender-2.1.0}/tests/test_column_alignment.py +0 -0
- {termrender-2.0.0 → termrender-2.1.0}/tests/test_diff.py +0 -0
- {termrender-2.0.0 → termrender-2.1.0}/tests/test_inline_badge.py +0 -0
- {termrender-2.0.0 → termrender-2.1.0}/tests/test_linebreak.py +0 -0
- {termrender-2.0.0 → termrender-2.1.0}/tests/test_mermaid_compat.py +0 -0
- {termrender-2.0.0 → termrender-2.1.0}/tests/test_myst_gaps.py +0 -0
- {termrender-2.0.0 → termrender-2.1.0}/tests/test_stat.py +0 -0
- {termrender-2.0.0 → termrender-2.1.0}/tests/test_tasklist.py +0 -0
- {termrender-2.0.0 → termrender-2.1.0}/tests/test_timeline.py +0 -0
- {termrender-2.0.0 → termrender-2.1.0}/tests/test_variable_colons.py +0 -0
|
@@ -1,6 +1,38 @@
|
|
|
1
1
|
# CHANGELOG
|
|
2
2
|
|
|
3
3
|
|
|
4
|
+
## v2.1.0 (2026-05-16)
|
|
5
|
+
|
|
6
|
+
### Documentation
|
|
7
|
+
|
|
8
|
+
- **claude-md**: Document mermaid-ascii vendoring and correct stale --maxWidth
|
|
9
|
+
([`643e25a`](https://github.com/crouton-labs/termrender/commit/643e25a791de1f32591b245dee064f290221cfc2))
|
|
10
|
+
|
|
11
|
+
Note _mermaid_bin resolution, the pinned master binary, the no-width-flag reality, and the back-edge
|
|
12
|
+
panic in renderers/CLAUDE.md.
|
|
13
|
+
|
|
14
|
+
- **claude-md**: Note QUOTE +1 height only applies to author/by attrs
|
|
15
|
+
([`3184d43`](https://github.com/crouton-labs/termrender/commit/3184d43e7293af735b82d559bc3253d7542cbf85))
|
|
16
|
+
|
|
17
|
+
### Features
|
|
18
|
+
|
|
19
|
+
- **mermaid**: Vendor engine from upstream master, fix broken -w invocation
|
|
20
|
+
([`d801de5`](https://github.com/crouton-labs/termrender/commit/d801de5bb22ba5205fe52ef65e80eda96590be93))
|
|
21
|
+
|
|
22
|
+
mermaid-ascii has no -w/width flag and never has; layout.py and mermaid.py passed `-w <width>`, so
|
|
23
|
+
every diagram exited non-zero and degraded to raw source text on the 1.2.0 wheel. Drop -w (call is
|
|
24
|
+
now `-f - -y 1`).
|
|
25
|
+
|
|
26
|
+
Resolve the binary via new _mermaid_bin.mermaid_ascii_bin(): prefer vendored
|
|
27
|
+
_bin/mermaid-ascii-<os>-<arch> (built from pinned upstream master 6fffb8e via
|
|
28
|
+
scripts/build-mermaid-ascii.sh), else fall back to `mermaid-ascii` on PATH (PyPI wheel, capped at
|
|
29
|
+
1.2.0). pyproject ships the binary via hatch artifacts and bumps the fallback dep to >=1.2.
|
|
30
|
+
|
|
31
|
+
Caveats: only darwin-arm64 is vendored (other platforms fall back to the older PyPI engine); a
|
|
32
|
+
labeled back-edge in graph LR panics the binary on both 1.2.0 and master and degrades to source.
|
|
33
|
+
mermaid-ascii has no width control, so wide diagrams overflow (renderer pads, never truncates).
|
|
34
|
+
|
|
35
|
+
|
|
4
36
|
## v2.0.0 (2026-05-16)
|
|
5
37
|
|
|
6
38
|
### Continuous Integration
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: termrender
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.1.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,7 +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: mermaid-ascii>=1.
|
|
24
|
+
Requires-Dist: mermaid-ascii>=1.2
|
|
25
25
|
Requires-Dist: mistune>=3.0
|
|
26
26
|
Requires-Dist: pygments>=2.0
|
|
27
27
|
Description-Content-Type: text/markdown
|
|
@@ -28,7 +28,7 @@ classifiers = [
|
|
|
28
28
|
]
|
|
29
29
|
dependencies = [
|
|
30
30
|
"mistune>=3.0",
|
|
31
|
-
"mermaid-ascii>=1.
|
|
31
|
+
"mermaid-ascii>=1.2",
|
|
32
32
|
"pygments>=2.0",
|
|
33
33
|
]
|
|
34
34
|
|
|
@@ -45,6 +45,11 @@ source = "vcs"
|
|
|
45
45
|
|
|
46
46
|
[tool.hatch.build.targets.wheel]
|
|
47
47
|
packages = ["src/termrender"]
|
|
48
|
+
# Ship the vendored mermaid-ascii binary (built from pinned upstream master;
|
|
49
|
+
# see scripts/build-mermaid-ascii.sh). It lives inside the package dir so the
|
|
50
|
+
# default file selection includes it; artifacts ensures it survives even if
|
|
51
|
+
# VCS-ignored, and hatchling preserves its 0o755 exec bit.
|
|
52
|
+
artifacts = ["src/termrender/_bin/*"]
|
|
48
53
|
|
|
49
54
|
[tool.semantic_release]
|
|
50
55
|
version_toml = []
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Build the vendored mermaid-ascii binary from pinned upstream master.
|
|
3
|
+
#
|
|
4
|
+
# Usage: scripts/build-mermaid-ascii.sh
|
|
5
|
+
#
|
|
6
|
+
# Produces src/termrender/_bin/mermaid-ascii-<os>-<arch> for the *host*
|
|
7
|
+
# platform. Run on each target platform (or with GOOS/GOARCH set) to refresh
|
|
8
|
+
# the vendored binaries. Requires a Go toolchain (>=1.21).
|
|
9
|
+
#
|
|
10
|
+
# Why vendored: the PyPI `mermaid-ascii` wheel only ships up to 1.2.0, which
|
|
11
|
+
# lacks the master-only flowchart fixes (multiline node labels, duplicate /
|
|
12
|
+
# bidirectional edge-label separation, subgraph titles, wide-rune label
|
|
13
|
+
# widths). termrender prefers this binary and falls back to the PyPI wheel's
|
|
14
|
+
# `mermaid-ascii` on PATH for platforms not vendored here.
|
|
15
|
+
set -euo pipefail
|
|
16
|
+
|
|
17
|
+
# Pinned upstream commit (github.com/AlexanderGrooff/mermaid-ascii master).
|
|
18
|
+
PIN="6fffb8e2714acab2c4cb41c78894fabbc62cee56"
|
|
19
|
+
|
|
20
|
+
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
21
|
+
workdir="$(mktemp -d)"
|
|
22
|
+
trap 'rm -rf "$workdir"' EXIT
|
|
23
|
+
|
|
24
|
+
git clone https://github.com/AlexanderGrooff/mermaid-ascii.git "$workdir/src"
|
|
25
|
+
git -C "$workdir/src" checkout --quiet "$PIN"
|
|
26
|
+
|
|
27
|
+
os="$(go env GOOS)"
|
|
28
|
+
arch="$(go env GOARCH)"
|
|
29
|
+
out="$repo_root/src/termrender/_bin/mermaid-ascii-${os}-${arch}"
|
|
30
|
+
|
|
31
|
+
mkdir -p "$(dirname "$out")"
|
|
32
|
+
( cd "$workdir/src" && go build -trimpath -o "$out" . )
|
|
33
|
+
chmod 755 "$out"
|
|
34
|
+
|
|
35
|
+
echo "Built $out"
|
|
36
|
+
"$out" --help >/dev/null && echo "Smoke test OK (pin ${PIN:0:7})"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
- **QUOTE** height gets `+1` only when `author` or `by` attr is set. Using any other key (`attribution`, `source`) silently omits the extra line — the renderer's attribution line is clipped.
|
|
Binary file
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"""Resolve the ``mermaid-ascii`` executable.
|
|
2
|
+
|
|
3
|
+
Prefers the vendored build from pinned upstream master (commit ``6fffb8e``,
|
|
4
|
+
2026-04-27) under ``_bin/mermaid-ascii-<os>-<arch>``; this carries the
|
|
5
|
+
master-only flowchart fixes the PyPI wheel (capped at 1.2.0) lacks. Falls back
|
|
6
|
+
to a ``mermaid-ascii`` on PATH (the PyPI ``mermaid-ascii`` wheel) for platforms
|
|
7
|
+
not vendored here.
|
|
8
|
+
|
|
9
|
+
Rebuild vendored binaries with ``scripts/build-mermaid-ascii.sh``.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import os
|
|
15
|
+
import platform
|
|
16
|
+
from functools import lru_cache
|
|
17
|
+
|
|
18
|
+
_BIN_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "_bin")
|
|
19
|
+
|
|
20
|
+
_OS_MAP = {"darwin": "darwin", "linux": "linux", "windows": "windows"}
|
|
21
|
+
_ARCH_MAP = {
|
|
22
|
+
"arm64": "arm64",
|
|
23
|
+
"aarch64": "arm64",
|
|
24
|
+
"x86_64": "amd64",
|
|
25
|
+
"amd64": "amd64",
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _platform_tag() -> str:
|
|
30
|
+
osname = _OS_MAP.get(platform.system().lower(), platform.system().lower())
|
|
31
|
+
arch = _ARCH_MAP.get(platform.machine().lower(), platform.machine().lower())
|
|
32
|
+
return f"{osname}-{arch}"
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@lru_cache(maxsize=1)
|
|
36
|
+
def mermaid_ascii_bin() -> str:
|
|
37
|
+
"""Path to the vendored mermaid-ascii, or ``"mermaid-ascii"`` for PATH lookup."""
|
|
38
|
+
vendored = os.path.join(_BIN_DIR, f"mermaid-ascii-{_platform_tag()}")
|
|
39
|
+
if os.path.isfile(vendored) and os.access(vendored, os.X_OK):
|
|
40
|
+
return vendored
|
|
41
|
+
return "mermaid-ascii"
|
|
@@ -4,6 +4,7 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import subprocess
|
|
6
6
|
|
|
7
|
+
from termrender._mermaid_bin import mermaid_ascii_bin
|
|
7
8
|
from termrender.blocks import Block, BlockType
|
|
8
9
|
from termrender.renderers.mermaid import fix_mermaid_encoding, preprocess_mermaid_for_ascii
|
|
9
10
|
from termrender.style import wrap_text, visual_len
|
|
@@ -147,7 +148,7 @@ def resolve_height(block: Block) -> None:
|
|
|
147
148
|
rendered = source # fallback
|
|
148
149
|
try:
|
|
149
150
|
result = subprocess.run(
|
|
150
|
-
[
|
|
151
|
+
[mermaid_ascii_bin(), "-f", "-", "-y", "1"],
|
|
151
152
|
input=preprocess_mermaid_for_ascii(source),
|
|
152
153
|
capture_output=True,
|
|
153
154
|
text=True,
|
|
@@ -52,3 +52,5 @@ Attribution line is rendered for `block.attrs["author"]` **or** `block.attrs["by
|
|
|
52
52
|
**Trailing blank line**: `rendered.split("\n")` on output ending with `\n` (typical subprocess output) produces a trailing empty string, which becomes a `block.width`-wide blank line appended to every mermaid block.
|
|
53
53
|
|
|
54
54
|
Layout pre-renders into `block.attrs["_rendered"]` (see `src/termrender/CLAUDE.md`); this renderer re-runs the subprocess only when that key is absent.
|
|
55
|
+
|
|
56
|
+
**Binary resolution & no width flag**: the executable comes from `_mermaid_bin.mermaid_ascii_bin()` — the vendored `_bin/mermaid-ascii-<os>-<arch>` (pinned upstream master `6fffb8e`, built via `scripts/build-mermaid-ascii.sh`) if present for the platform, else `mermaid-ascii` on PATH (the PyPI wheel, capped at 1.2.0). **`mermaid-ascii` has no width-control flag** (never has — `--maxWidth`/`-w` do not exist); the call passes only `-f - -y 1`, so `block.width` does not constrain the diagram and wide output overflows (compounding the no-truncation gotcha above). A labeled back-edge (`X -->|lbl| Y` in `graph LR`) panics the binary on **both** 1.2.0 and master; the non-zero exit is caught and the block degrades to raw source.
|
|
@@ -31,7 +31,7 @@ def render_box(
|
|
|
31
31
|
corner_v = visual_len("┌") # same as ┐, └, ┘
|
|
32
32
|
|
|
33
33
|
# Grow the box if any content line (or the title) won't fit at the
|
|
34
|
-
# requested width. mermaid-ascii
|
|
34
|
+
# requested width. mermaid-ascii has no width-control flag, so a child
|
|
35
35
|
# mermaid block can return lines wider than its allocated content area.
|
|
36
36
|
# Truncating would corrupt the diagram; growing keeps the box's top,
|
|
37
37
|
# bottom, and side borders aligned at the same column even if it
|
|
@@ -5,6 +5,7 @@ from __future__ import annotations
|
|
|
5
5
|
import re
|
|
6
6
|
import subprocess
|
|
7
7
|
|
|
8
|
+
from termrender._mermaid_bin import mermaid_ascii_bin
|
|
8
9
|
from termrender.blocks import Block
|
|
9
10
|
from termrender.style import visual_ljust
|
|
10
11
|
|
|
@@ -81,7 +82,7 @@ def render(block: Block, color: bool) -> list[str]:
|
|
|
81
82
|
source = block.attrs.get("source", "")
|
|
82
83
|
try:
|
|
83
84
|
result = subprocess.run(
|
|
84
|
-
[
|
|
85
|
+
[mermaid_ascii_bin(), "-f", "-", "-y", "1"],
|
|
85
86
|
input=preprocess_mermaid_for_ascii(source),
|
|
86
87
|
capture_output=True,
|
|
87
88
|
text=True,
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
- `layout.py` imports `fix_mermaid_encoding` and `preprocess_mermaid_for_ascii` from `renderers/mermaid.py` — the only reverse dependency from layout into renderers. Reorganizing `renderers/` must preserve these imports. The two mermaid subprocess call sites differ: layout uses `check=True` (non-zero exit raises → caught → raw-source fallback); the renderer omits `check` (non-zero exit silently reads `stdout`, which may be empty or partial).
|
|
2
|
-
|
|
3
|
-
- `--check` calls `parse()` and exits — it never runs `layout.py`. Layout-time failures (mermaid subprocess missing, column percent overflow, `resolve_width`/`resolve_height` exceptions) pass `--check` cleanly but crash at render time.
|
|
4
|
-
|
|
5
|
-
- Column widths: explicit percent/absolute allocations are subtracted first; remaining space is split among auto-width columns with `max(remaining, 0)`. Two columns each claiming 80% of a 100px terminal leaves auto-width columns with `width = 1` — no error, no proportional scaling.
|
|
6
|
-
|
|
7
|
-
- **QUOTE** height gets `+1` only when `author` or `by` attr is set. Using any other key (`attribution`, `source`) silently omits the extra line — the renderer's attribution line is clipped.
|
|
8
|
-
|
|
9
|
-
- **LIST_ITEM** layout wraps at `max(width - 2, 1)`, hardcoding a 2-column indent. If the renderer changes the indent width, layout height and actual render height diverge silently.
|
|
10
|
-
|
|
11
|
-
- `text.py:32–33`: after each wrapped line, the offset skips one character if the next plain-text character is a space (the space `wrap_text` consumed). If wrapping preserves trailing spaces, this skip shifts subsequent span styling by one character.
|
|
12
|
-
|
|
13
|
-
- `--tmux` exits `EXIT_OK` after the tmux pane command succeeds — the `--check` branch comes later and is never reached. `--check` is silently dropped when combined with `--tmux`.
|
|
14
|
-
|
|
15
|
-
- `_EMOJI_WIDE_RANGES` in `style.py`: `_char_width()` exits early when `cp < lo`, assuming ranges are in ascending codepoint order. Adding a range out of order silently misclassifies all codepoints whose `lo` is higher than the inserted range's `lo`.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|