oaknut-cli 12.7.2__tar.gz → 12.8.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.
- {oaknut_cli-12.7.2/src/oaknut_cli.egg-info → oaknut_cli-12.8.1}/PKG-INFO +2 -2
- {oaknut_cli-12.7.2 → oaknut_cli-12.8.1}/pyproject.toml +1 -1
- {oaknut_cli-12.7.2 → oaknut_cli-12.8.1}/src/oaknut/cli/__init__.py +5 -1
- {oaknut_cli-12.7.2 → oaknut_cli-12.8.1}/src/oaknut/cli/reports.py +34 -0
- {oaknut_cli-12.7.2 → oaknut_cli-12.8.1/src/oaknut_cli.egg-info}/PKG-INFO +2 -2
- {oaknut_cli-12.7.2 → oaknut_cli-12.8.1}/src/oaknut_cli.egg-info/SOURCES.txt +2 -1
- {oaknut_cli-12.7.2 → oaknut_cli-12.8.1}/src/oaknut_cli.egg-info/requires.txt +1 -1
- oaknut_cli-12.8.1/tests/test_reports.py +38 -0
- {oaknut_cli-12.7.2 → oaknut_cli-12.8.1}/LICENSE +0 -0
- {oaknut_cli-12.7.2 → oaknut_cli-12.8.1}/README.md +0 -0
- {oaknut_cli-12.7.2 → oaknut_cli-12.8.1}/setup.cfg +0 -0
- {oaknut_cli-12.7.2 → oaknut_cli-12.8.1}/src/oaknut/cli/commands.py +0 -0
- {oaknut_cli-12.7.2 → oaknut_cli-12.8.1}/src/oaknut/cli/help.py +0 -0
- {oaknut_cli-12.7.2 → oaknut_cli-12.8.1}/src/oaknut_cli.egg-info/dependency_links.txt +0 -0
- {oaknut_cli-12.7.2 → oaknut_cli-12.8.1}/src/oaknut_cli.egg-info/top_level.txt +0 -0
- {oaknut_cli-12.7.2 → oaknut_cli-12.8.1}/tests/test_commands.py +0 -0
- {oaknut_cli-12.7.2 → oaknut_cli-12.8.1}/tests/test_help.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: oaknut-cli
|
|
3
|
-
Version: 12.
|
|
3
|
+
Version: 12.8.1
|
|
4
4
|
Summary: Shared CLI toolkit for the oaknut family: the contributed-command axis and report-rendering helpers a disc command needs, below the filesystem packages.
|
|
5
5
|
Author-email: Robert Smallshire <robert@smallshire.org.uk>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -23,7 +23,7 @@ Requires-Dist: oaknut-exception>=10.0
|
|
|
23
23
|
Requires-Dist: oaknut-extension>=10.0
|
|
24
24
|
Requires-Dist: oaknut-file>=10.0
|
|
25
25
|
Requires-Dist: click>=8.1.7
|
|
26
|
-
Requires-Dist: asyoulikeit>=1.
|
|
26
|
+
Requires-Dist: asyoulikeit>=1.3.0
|
|
27
27
|
Dynamic: license-file
|
|
28
28
|
|
|
29
29
|
# oaknut-cli
|
|
@@ -32,11 +32,13 @@ from oaknut.cli.reports import (
|
|
|
32
32
|
SECTOR_SIZE,
|
|
33
33
|
address_cell,
|
|
34
34
|
bytes_cell,
|
|
35
|
+
control_pictures,
|
|
35
36
|
kv_table,
|
|
36
37
|
size_cell,
|
|
38
|
+
text_cell,
|
|
37
39
|
)
|
|
38
40
|
|
|
39
|
-
__version__ = "12.
|
|
41
|
+
__version__ = "12.8.1"
|
|
40
42
|
|
|
41
43
|
__all__ = [
|
|
42
44
|
"COMMAND_KIND",
|
|
@@ -48,6 +50,8 @@ __all__ = [
|
|
|
48
50
|
"SECTOR_SIZE",
|
|
49
51
|
"address_cell",
|
|
50
52
|
"bytes_cell",
|
|
53
|
+
"control_pictures",
|
|
51
54
|
"kv_table",
|
|
52
55
|
"size_cell",
|
|
56
|
+
"text_cell",
|
|
53
57
|
]
|
|
@@ -15,6 +15,40 @@ from oaknut.file.capacity import format_capacity
|
|
|
15
15
|
#: Acorn discs are addressed in 256-byte sectors throughout.
|
|
16
16
|
SECTOR_SIZE = 256
|
|
17
17
|
|
|
18
|
+
# The Unicode Control Pictures block (U+2400–U+241F) holds a visible,
|
|
19
|
+
# inert glyph for each C0 control character (0x00–0x1F); U+2421 (␡) is
|
|
20
|
+
# the symbol for DEL (0x7F). Mapping to these never emits an active
|
|
21
|
+
# control code, so a terminal is never driven by data read off a disc.
|
|
22
|
+
_CONTROL_PICTURES = {codepoint: chr(0x2400 + codepoint) for codepoint in range(0x20)}
|
|
23
|
+
_CONTROL_PICTURES[0x7F] = "␡"
|
|
24
|
+
_CONTROL_PICTURES_TABLE = str.maketrans(_CONTROL_PICTURES)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def control_pictures(text: str) -> str:
|
|
28
|
+
"""Render C0 control characters and DEL as Unicode Control Pictures.
|
|
29
|
+
|
|
30
|
+
Acorn names and titles are stored as arbitrary bytes and may carry
|
|
31
|
+
control characters (a disc title decorated with a form-feed, say).
|
|
32
|
+
This replaces each with the matching glyph from the Control Pictures
|
|
33
|
+
block so it is visible and inert; all other characters pass through.
|
|
34
|
+
"""
|
|
35
|
+
return text.translate(_CONTROL_PICTURES_TABLE)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def text_cell(text: str) -> str | ByAudience:
|
|
39
|
+
"""On-disc text that may contain control characters, as a cell.
|
|
40
|
+
|
|
41
|
+
Clean text is returned unchanged, so the common case is untouched.
|
|
42
|
+
When control characters are present the cell becomes audience-aware:
|
|
43
|
+
machine formatters (JSON, TSV) keep the raw string for a faithful
|
|
44
|
+
round-trip, while the display formatter shows :func:`control_pictures`
|
|
45
|
+
so the terminal is never driven by active control codes.
|
|
46
|
+
"""
|
|
47
|
+
pretty = control_pictures(text)
|
|
48
|
+
if pretty == text:
|
|
49
|
+
return text
|
|
50
|
+
return ByAudience(machine=text, human=pretty)
|
|
51
|
+
|
|
18
52
|
|
|
19
53
|
def size_cell(sectors: int) -> ByAudience:
|
|
20
54
|
"""A capacity (given in sectors) as an audience-aware cell.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: oaknut-cli
|
|
3
|
-
Version: 12.
|
|
3
|
+
Version: 12.8.1
|
|
4
4
|
Summary: Shared CLI toolkit for the oaknut family: the contributed-command axis and report-rendering helpers a disc command needs, below the filesystem packages.
|
|
5
5
|
Author-email: Robert Smallshire <robert@smallshire.org.uk>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -23,7 +23,7 @@ Requires-Dist: oaknut-exception>=10.0
|
|
|
23
23
|
Requires-Dist: oaknut-extension>=10.0
|
|
24
24
|
Requires-Dist: oaknut-file>=10.0
|
|
25
25
|
Requires-Dist: click>=8.1.7
|
|
26
|
-
Requires-Dist: asyoulikeit>=1.
|
|
26
|
+
Requires-Dist: asyoulikeit>=1.3.0
|
|
27
27
|
Dynamic: license-file
|
|
28
28
|
|
|
29
29
|
# oaknut-cli
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""Tests for the shared report-rendering cell helpers."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from asyoulikeit import ByAudience
|
|
6
|
+
from oaknut.cli import control_pictures, text_cell
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class TestControlPictures:
|
|
10
|
+
def test_c0_controls_map_to_pictures_block(self):
|
|
11
|
+
# Every C0 control (0x00–0x1F) maps to U+2400 + codepoint.
|
|
12
|
+
for c in range(0x20):
|
|
13
|
+
assert control_pictures(chr(c)) == chr(0x2400 + c)
|
|
14
|
+
|
|
15
|
+
def test_del_maps_to_its_symbol(self):
|
|
16
|
+
assert control_pictures("\x7f") == "␡" # ␡
|
|
17
|
+
|
|
18
|
+
def test_printable_text_unchanged(self):
|
|
19
|
+
assert control_pictures("Pascal 1.2 (c)") == "Pascal 1.2 (c)"
|
|
20
|
+
|
|
21
|
+
def test_mixed_title(self):
|
|
22
|
+
# The Oxford Pascal disc title: form-feed, then "Pascal", LF, CR.
|
|
23
|
+
assert control_pictures("\x0cPascal\n\r") == "␌Pascal␊␍"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class TestTextCell:
|
|
27
|
+
def test_clean_text_is_plain_string(self):
|
|
28
|
+
# No control characters → no need to wrap; output is identical to
|
|
29
|
+
# passing the bare string, keeping the common case untouched.
|
|
30
|
+
assert text_cell("HELLO") == "HELLO"
|
|
31
|
+
assert not isinstance(text_cell("HELLO"), ByAudience)
|
|
32
|
+
|
|
33
|
+
def test_control_text_is_audience_aware(self):
|
|
34
|
+
cell = text_cell("\x0cPascal\n\r")
|
|
35
|
+
assert isinstance(cell, ByAudience)
|
|
36
|
+
# Machines keep the raw bytes; humans get control pictures.
|
|
37
|
+
assert cell.machine == "\x0cPascal\n\r"
|
|
38
|
+
assert cell.human == "␌Pascal␊␍"
|
|
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
|