termrender 0.6.0__tar.gz → 0.6.1__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-0.6.0 → termrender-0.6.1}/CHANGELOG.md +17 -0
- {termrender-0.6.0 → termrender-0.6.1}/PKG-INFO +1 -1
- {termrender-0.6.0 → termrender-0.6.1}/src/termrender/renderers/borders.py +19 -0
- {termrender-0.6.0 → termrender-0.6.1}/tests/test_column_alignment.py +76 -0
- {termrender-0.6.0 → termrender-0.6.1}/.github/workflows/publish.yml +0 -0
- {termrender-0.6.0 → termrender-0.6.1}/.gitignore +0 -0
- {termrender-0.6.0 → termrender-0.6.1}/CLAUDE.md +0 -0
- {termrender-0.6.0 → termrender-0.6.1}/LICENSE +0 -0
- {termrender-0.6.0 → termrender-0.6.1}/README.md +0 -0
- {termrender-0.6.0 → termrender-0.6.1}/design.json +0 -0
- {termrender-0.6.0 → termrender-0.6.1}/pyproject.toml +0 -0
- {termrender-0.6.0 → termrender-0.6.1}/requirements.json +0 -0
- {termrender-0.6.0 → termrender-0.6.1}/src/termrender/CLAUDE.md +0 -0
- {termrender-0.6.0 → termrender-0.6.1}/src/termrender/__init__.py +0 -0
- {termrender-0.6.0 → termrender-0.6.1}/src/termrender/__main__.py +0 -0
- {termrender-0.6.0 → termrender-0.6.1}/src/termrender/blocks.py +0 -0
- {termrender-0.6.0 → termrender-0.6.1}/src/termrender/emit.py +0 -0
- {termrender-0.6.0 → termrender-0.6.1}/src/termrender/layout.py +0 -0
- {termrender-0.6.0 → termrender-0.6.1}/src/termrender/parser.py +0 -0
- {termrender-0.6.0 → termrender-0.6.1}/src/termrender/py.typed +0 -0
- {termrender-0.6.0 → termrender-0.6.1}/src/termrender/renderers/CLAUDE.md +0 -0
- {termrender-0.6.0 → termrender-0.6.1}/src/termrender/renderers/__init__.py +0 -0
- {termrender-0.6.0 → termrender-0.6.1}/src/termrender/renderers/charts.py +0 -0
- {termrender-0.6.0 → termrender-0.6.1}/src/termrender/renderers/code.py +0 -0
- {termrender-0.6.0 → termrender-0.6.1}/src/termrender/renderers/columns.py +0 -0
- {termrender-0.6.0 → termrender-0.6.1}/src/termrender/renderers/diff.py +0 -0
- {termrender-0.6.0 → termrender-0.6.1}/src/termrender/renderers/divider.py +0 -0
- {termrender-0.6.0 → termrender-0.6.1}/src/termrender/renderers/mermaid.py +0 -0
- {termrender-0.6.0 → termrender-0.6.1}/src/termrender/renderers/panel.py +0 -0
- {termrender-0.6.0 → termrender-0.6.1}/src/termrender/renderers/quote.py +0 -0
- {termrender-0.6.0 → termrender-0.6.1}/src/termrender/renderers/stat.py +0 -0
- {termrender-0.6.0 → termrender-0.6.1}/src/termrender/renderers/table.py +0 -0
- {termrender-0.6.0 → termrender-0.6.1}/src/termrender/renderers/text.py +0 -0
- {termrender-0.6.0 → termrender-0.6.1}/src/termrender/renderers/timeline.py +0 -0
- {termrender-0.6.0 → termrender-0.6.1}/src/termrender/renderers/tree.py +0 -0
- {termrender-0.6.0 → termrender-0.6.1}/src/termrender/style.py +0 -0
- {termrender-0.6.0 → termrender-0.6.1}/tests/__init__.py +0 -0
- {termrender-0.6.0 → termrender-0.6.1}/tests/test_charts.py +0 -0
- {termrender-0.6.0 → termrender-0.6.1}/tests/test_diff.py +0 -0
- {termrender-0.6.0 → termrender-0.6.1}/tests/test_inline_badge.py +0 -0
- {termrender-0.6.0 → termrender-0.6.1}/tests/test_myst_gaps.py +0 -0
- {termrender-0.6.0 → termrender-0.6.1}/tests/test_stat.py +0 -0
- {termrender-0.6.0 → termrender-0.6.1}/tests/test_tasklist.py +0 -0
- {termrender-0.6.0 → termrender-0.6.1}/tests/test_timeline.py +0 -0
- {termrender-0.6.0 → termrender-0.6.1}/tests/test_variable_colons.py +0 -0
|
@@ -1,6 +1,23 @@
|
|
|
1
1
|
# CHANGELOG
|
|
2
2
|
|
|
3
3
|
|
|
4
|
+
## v0.6.1 (2026-04-08)
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
- **borders**: Grow render_box to fit overflowing content and titles
|
|
9
|
+
([`dc108c8`](https://github.com/CaptainCrouton89/termrender/commit/dc108c8242763828245569f719abce64b26ddf5b))
|
|
10
|
+
|
|
11
|
+
mermaid-ascii's --maxWidth is non-strict, so a child mermaid block can return lines wider than the
|
|
12
|
+
panel's allocated content area. Previously the side walls floated outward to accommodate the
|
|
13
|
+
content while the top/bottom borders stayed at the requested width, leaving corner glyphs one
|
|
14
|
+
column inside the side walls and producing a visibly jagged box.
|
|
15
|
+
|
|
16
|
+
render_box now measures the widest content line (and the title) and grows its effective width up
|
|
17
|
+
front so all four borders land at the same column. Trade-off: the box may overflow its parent
|
|
18
|
+
allocation, but the box itself is internally consistent.
|
|
19
|
+
|
|
20
|
+
|
|
4
21
|
## v0.6.0 (2026-04-07)
|
|
5
22
|
|
|
6
23
|
### Features
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: termrender
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.1
|
|
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
|
|
@@ -30,6 +30,25 @@ def render_box(
|
|
|
30
30
|
dash_v = visual_len("─")
|
|
31
31
|
corner_v = visual_len("┌") # same as ┐, └, ┘
|
|
32
32
|
|
|
33
|
+
# Grow the box if any content line (or the title) won't fit at the
|
|
34
|
+
# requested width. mermaid-ascii's --maxWidth is non-strict, so a child
|
|
35
|
+
# mermaid block can return lines wider than its allocated content area.
|
|
36
|
+
# Truncating would corrupt the diagram; growing keeps the box's top,
|
|
37
|
+
# bottom, and side borders aligned at the same column even if it
|
|
38
|
+
# overflows the parent's allocation.
|
|
39
|
+
content_max = visual_len("")
|
|
40
|
+
for cl in content_lines:
|
|
41
|
+
cl_w = visual_len(cl)
|
|
42
|
+
if cl_w > content_max:
|
|
43
|
+
content_max = cl_w
|
|
44
|
+
required_for_content = content_max + 2 + 2 * border_v # pads + walls
|
|
45
|
+
required_for_title = 0
|
|
46
|
+
if title:
|
|
47
|
+
title_part_w = dash_v + 2 + visual_len(title) # "─ TITLE "
|
|
48
|
+
# Reserve at least one trailing dash so the corner has chrome.
|
|
49
|
+
required_for_title = title_part_w + dash_v + 2 * border_v
|
|
50
|
+
width = max(width, required_for_content, required_for_title)
|
|
51
|
+
|
|
33
52
|
# inner_w = space between the two vertical borders
|
|
34
53
|
inner_w = width - 2 * border_v
|
|
35
54
|
# content_w = space for actual content (inner minus 1-space padding each side)
|
|
@@ -81,6 +81,30 @@ c/
|
|
|
81
81
|
::::
|
|
82
82
|
"""
|
|
83
83
|
|
|
84
|
+
# A panel nested inside :::col whose content (a wide mermaid diagram) exceeds
|
|
85
|
+
# the column allocation. The inner panel's side walls and corner glyphs must
|
|
86
|
+
# stay aligned even when content forces the panel to grow past its allotment.
|
|
87
|
+
NESTED_PANEL_OVERFLOW_INPUT = """\
|
|
88
|
+
::::::panel{title="Outer" color="cyan"}
|
|
89
|
+
:::::columns
|
|
90
|
+
::::col{width="58%"}
|
|
91
|
+
:::panel{title="Request Flow" color="blue"}
|
|
92
|
+
```mermaid
|
|
93
|
+
graph TD
|
|
94
|
+
A[Edge gateway<br/>accepts request] --> B{Token valid?}
|
|
95
|
+
B -->|yes| C[Route via LB<br/>to backend pool]
|
|
96
|
+
B -->|no| D[Reject 401,<br/>write audit log]
|
|
97
|
+
C --> E[Service responds,<br/>metrics emitted]
|
|
98
|
+
```
|
|
99
|
+
:::
|
|
100
|
+
::::
|
|
101
|
+
::::col{width="42%"}
|
|
102
|
+
right
|
|
103
|
+
::::
|
|
104
|
+
:::::
|
|
105
|
+
::::::
|
|
106
|
+
"""
|
|
107
|
+
|
|
84
108
|
|
|
85
109
|
class TestColumnAlignment(unittest.TestCase):
|
|
86
110
|
|
|
@@ -132,6 +156,58 @@ class TestColumnAlignment(unittest.TestCase):
|
|
|
132
156
|
f"Line {i} has visual width {w}, expected 40: {line!r}",
|
|
133
157
|
)
|
|
134
158
|
|
|
159
|
+
def test_nested_panel_corners_align_with_side_walls(self):
|
|
160
|
+
# When a panel inside a column receives content wider than the column
|
|
161
|
+
# allocation, both the side walls AND the top/bottom border glyphs
|
|
162
|
+
# must extend to the same width. Otherwise the corner glyphs (┐ ┘)
|
|
163
|
+
# land one column inside the side walls (│), producing a jagged box.
|
|
164
|
+
from termrender.style import _char_width
|
|
165
|
+
|
|
166
|
+
output = render(NESTED_PANEL_OVERFLOW_INPUT, width=80, color=False)
|
|
167
|
+
lines = output.split("\n")
|
|
168
|
+
if lines and lines[-1] == "":
|
|
169
|
+
lines = lines[:-1]
|
|
170
|
+
|
|
171
|
+
def visual_positions(line, glyphs):
|
|
172
|
+
pos = 0
|
|
173
|
+
found = []
|
|
174
|
+
for ch in line:
|
|
175
|
+
if ch == "\033":
|
|
176
|
+
continue
|
|
177
|
+
if ch in glyphs:
|
|
178
|
+
found.append(pos)
|
|
179
|
+
pos += _char_width(ch)
|
|
180
|
+
return found
|
|
181
|
+
|
|
182
|
+
# The outer panel's left wall is always at pos 0 and the right wall
|
|
183
|
+
# at the rightmost glyph. The inner panel's right border is the
|
|
184
|
+
# next-most-right border glyph in any row that contains both the
|
|
185
|
+
# outer panel's walls and inner-panel content. Across all such rows
|
|
186
|
+
# the inner panel's right border position must be constant.
|
|
187
|
+
inner_right_positions = []
|
|
188
|
+
for line in lines:
|
|
189
|
+
glyphs = sorted(set(visual_positions(line, "┌┐└┘│")))
|
|
190
|
+
# Skip rows that don't span the inner panel (e.g. outer-only).
|
|
191
|
+
if len(glyphs) < 3:
|
|
192
|
+
continue
|
|
193
|
+
outer_right = glyphs[-1]
|
|
194
|
+
# Inner panel's right border is whichever glyph sits just inside
|
|
195
|
+
# the outer right wall — i.e. the next-rightmost.
|
|
196
|
+
inner_right = glyphs[-2]
|
|
197
|
+
# Ignore the inner panel's LEFT wall (which on bare side-wall
|
|
198
|
+
# rows might appear as glyphs[1]) — we only care about the
|
|
199
|
+
# right-side glyph adjacent to the outer right wall.
|
|
200
|
+
if inner_right == glyphs[0]:
|
|
201
|
+
continue
|
|
202
|
+
inner_right_positions.append(inner_right)
|
|
203
|
+
|
|
204
|
+
unique = set(inner_right_positions)
|
|
205
|
+
self.assertEqual(
|
|
206
|
+
len(unique),
|
|
207
|
+
1,
|
|
208
|
+
f"Inner panel right border drifts across rows: {sorted(unique)}",
|
|
209
|
+
)
|
|
210
|
+
|
|
135
211
|
|
|
136
212
|
if __name__ == "__main__":
|
|
137
213
|
unittest.main()
|
|
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
|
|
File without changes
|