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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: oaknut-cli
3
- Version: 12.7.2
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.2.0
26
+ Requires-Dist: asyoulikeit>=1.3.0
27
27
  Dynamic: license-file
28
28
 
29
29
  # oaknut-cli
@@ -27,7 +27,7 @@ dependencies = [
27
27
  "oaknut-extension>=10.0",
28
28
  "oaknut-file>=10.0",
29
29
  "click>=8.1.7",
30
- "asyoulikeit>=1.2.0",
30
+ "asyoulikeit>=1.3.0",
31
31
  ]
32
32
 
33
33
  [project.urls]
@@ -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.7.2"
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.7.2
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.2.0
26
+ Requires-Dist: asyoulikeit>=1.3.0
27
27
  Dynamic: license-file
28
28
 
29
29
  # oaknut-cli
@@ -11,4 +11,5 @@ src/oaknut_cli.egg-info/dependency_links.txt
11
11
  src/oaknut_cli.egg-info/requires.txt
12
12
  src/oaknut_cli.egg-info/top_level.txt
13
13
  tests/test_commands.py
14
- tests/test_help.py
14
+ tests/test_help.py
15
+ tests/test_reports.py
@@ -2,4 +2,4 @@ oaknut-exception>=10.0
2
2
  oaknut-extension>=10.0
3
3
  oaknut-file>=10.0
4
4
  click>=8.1.7
5
- asyoulikeit>=1.2.0
5
+ asyoulikeit>=1.3.0
@@ -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