sextile 0.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.
Files changed (164) hide show
  1. sextile-0.1.0/.gitignore +24 -0
  2. sextile-0.1.0/LICENSE +26 -0
  3. sextile-0.1.0/NOTICE.md +51 -0
  4. sextile-0.1.0/PKG-INFO +119 -0
  5. sextile-0.1.0/README.md +90 -0
  6. sextile-0.1.0/docs/design.md +962 -0
  7. sextile-0.1.0/docs/glossary.md +4 -0
  8. sextile-0.1.0/docs/graphics.md +6 -0
  9. sextile-0.1.0/docs/layout.md +244 -0
  10. sextile-0.1.0/docs/navigation.md +202 -0
  11. sextile-0.1.0/docs/public-surface.md +298 -0
  12. sextile-0.1.0/docs/rendering.md +154 -0
  13. sextile-0.1.0/docs/viewdata-encoding.md +5 -0
  14. sextile-0.1.0/docs/writing-an-application.md +7 -0
  15. sextile-0.1.0/pyproject.toml +47 -0
  16. sextile-0.1.0/src/sextile/__init__.py +96 -0
  17. sextile-0.1.0/src/sextile/__main__.py +100 -0
  18. sextile-0.1.0/src/sextile/application.py +538 -0
  19. sextile-0.1.0/src/sextile/builtin/__init__.py +29 -0
  20. sextile-0.1.0/src/sextile/builtin/contents.py +66 -0
  21. sextile-0.1.0/src/sextile/builtin/guidance.py +166 -0
  22. sextile-0.1.0/src/sextile/builtin/history.py +80 -0
  23. sextile-0.1.0/src/sextile/builtin/names.py +61 -0
  24. sextile-0.1.0/src/sextile/builtin/readership.py +212 -0
  25. sextile-0.1.0/src/sextile/cli.py +357 -0
  26. sextile-0.1.0/src/sextile/content/__init__.py +5 -0
  27. sextile-0.1.0/src/sextile/content/blocks.py +87 -0
  28. sextile-0.1.0/src/sextile/content/transliterate.py +104 -0
  29. sextile-0.1.0/src/sextile/formatting.py +525 -0
  30. sextile-0.1.0/src/sextile/forms/__init__.py +36 -0
  31. sextile-0.1.0/src/sextile/forms/base.py +194 -0
  32. sextile-0.1.0/src/sextile/forms/fields.py +301 -0
  33. sextile-0.1.0/src/sextile/forms/type_ahead.py +227 -0
  34. sextile-0.1.0/src/sextile/handlers.py +362 -0
  35. sextile-0.1.0/src/sextile/keys.py +173 -0
  36. sextile-0.1.0/src/sextile/layout/__init__.py +85 -0
  37. sextile-0.1.0/src/sextile/layout/footer.py +200 -0
  38. sextile-0.1.0/src/sextile/layout/furniture.py +160 -0
  39. sextile-0.1.0/src/sextile/layout/page.py +283 -0
  40. sextile-0.1.0/src/sextile/layout/parts.py +446 -0
  41. sextile-0.1.0/src/sextile/middleware.py +180 -0
  42. sextile-0.1.0/src/sextile/page.py +176 -0
  43. sextile-0.1.0/src/sextile/pages.py +232 -0
  44. sextile-0.1.0/src/sextile/py.typed +0 -0
  45. sextile-0.1.0/src/sextile/requests.py +77 -0
  46. sextile-0.1.0/src/sextile/routing.py +614 -0
  47. sextile-0.1.0/src/sextile/server.py +200 -0
  48. sextile-0.1.0/src/sextile/session/__init__.py +1 -0
  49. sextile-0.1.0/src/sextile/session/commands.py +238 -0
  50. sextile-0.1.0/src/sextile/session/navigation.py +89 -0
  51. sextile-0.1.0/src/sextile/session/screen.py +216 -0
  52. sextile-0.1.0/src/sextile/session/session.py +455 -0
  53. sextile-0.1.0/src/sextile/state.py +96 -0
  54. sextile-0.1.0/src/sextile/testing.py +200 -0
  55. sextile-0.1.0/src/sextile/viewdata/__init__.py +18 -0
  56. sextile-0.1.0/src/sextile/viewdata/ansi.py +88 -0
  57. sextile-0.1.0/src/sextile/viewdata/attributes.py +222 -0
  58. sextile-0.1.0/src/sextile/viewdata/blocks.py +242 -0
  59. sextile-0.1.0/src/sextile/viewdata/canvas.py +363 -0
  60. sextile-0.1.0/src/sextile/viewdata/charset.py +98 -0
  61. sextile-0.1.0/src/sextile/viewdata/charting.py +105 -0
  62. sextile-0.1.0/src/sextile/viewdata/command_line.py +123 -0
  63. sextile-0.1.0/src/sextile/viewdata/compass.py +141 -0
  64. sextile-0.1.0/src/sextile/viewdata/composition.py +517 -0
  65. sextile-0.1.0/src/sextile/viewdata/controls.py +130 -0
  66. sextile-0.1.0/src/sextile/viewdata/display.py +181 -0
  67. sextile-0.1.0/src/sextile/viewdata/drawing.py +195 -0
  68. sextile-0.1.0/src/sextile/viewdata/encoding.py +81 -0
  69. sextile-0.1.0/src/sextile/viewdata/font.py +342 -0
  70. sextile-0.1.0/src/sextile/viewdata/fonts/3x3-mono.font +477 -0
  71. sextile-0.1.0/src/sextile/viewdata/fonts/OFL-1.1.txt +116 -0
  72. sextile-0.1.0/src/sextile/viewdata/fonts/__init__.py +7 -0
  73. sextile-0.1.0/src/sextile/viewdata/fonts/acorn.font +1899 -0
  74. sextile-0.1.0/src/sextile/viewdata/fonts/arcade.font +665 -0
  75. sextile-0.1.0/src/sextile/viewdata/fonts/boldbash.font +1041 -0
  76. sextile-0.1.0/src/sextile/viewdata/fonts/console-bold.font +947 -0
  77. sextile-0.1.0/src/sextile/viewdata/fonts/console.font +947 -0
  78. sextile-0.1.0/src/sextile/viewdata/fonts/garland.font +1793 -0
  79. sextile-0.1.0/src/sextile/viewdata/fonts/grotesque-bold.font +1229 -0
  80. sextile-0.1.0/src/sextile/viewdata/fonts/grotesque.font +1229 -0
  81. sextile-0.1.0/src/sextile/viewdata/fonts/lilliputsteps.font +947 -0
  82. sextile-0.1.0/src/sextile/viewdata/fonts/pixeloperator-bold.font +1417 -0
  83. sextile-0.1.0/src/sextile/viewdata/fonts/pixeloperator-hb.font +1417 -0
  84. sextile-0.1.0/src/sextile/viewdata/fonts/pixeloperator-sc-bold.font +1417 -0
  85. sextile-0.1.0/src/sextile/viewdata/fonts/pixeloperator-sc-hb.font +1417 -0
  86. sextile-0.1.0/src/sextile/viewdata/fonts/pixeloperator-sc.font +1417 -0
  87. sextile-0.1.0/src/sextile/viewdata/fonts/pixeloperator.font +1417 -0
  88. sextile-0.1.0/src/sextile/viewdata/fonts/pixeloperator8-bold.font +947 -0
  89. sextile-0.1.0/src/sextile/viewdata/fonts/pixeloperator8-hb.font +947 -0
  90. sextile-0.1.0/src/sextile/viewdata/fonts/pixeloperator8.font +947 -0
  91. sextile-0.1.0/src/sextile/viewdata/fonts/pixelplace.font +759 -0
  92. sextile-0.1.0/src/sextile/viewdata/fonts/publicpixel.font +853 -0
  93. sextile-0.1.0/src/sextile/viewdata/fonts/roman.font +1041 -0
  94. sextile-0.1.0/src/sextile/viewdata/fonts/scientifica-bold.font +1135 -0
  95. sextile-0.1.0/src/sextile/viewdata/fonts/scientifica-italic.font +1135 -0
  96. sextile-0.1.0/src/sextile/viewdata/fonts/scientifica.font +1135 -0
  97. sextile-0.1.0/src/sextile/viewdata/fonts/silkscreen-bold.font +1041 -0
  98. sextile-0.1.0/src/sextile/viewdata/fonts/silkscreen.font +1041 -0
  99. sextile-0.1.0/src/sextile/viewdata/frame.py +209 -0
  100. sextile-0.1.0/src/sextile/viewdata/hangup.py +38 -0
  101. sextile-0.1.0/src/sextile/viewdata/html.py +98 -0
  102. sextile-0.1.0/src/sextile/viewdata/idle_warning.py +85 -0
  103. sextile-0.1.0/src/sextile/viewdata/lettering.py +404 -0
  104. sextile-0.1.0/src/sextile/viewdata/measure.py +42 -0
  105. sextile-0.1.0/src/sextile/viewdata/repaint.py +187 -0
  106. sextile-0.1.0/src/sextile/viewdata/static/bedstead.woff2 +0 -0
  107. sextile-0.1.0/src/sextile/viewdata/static/viewdata.css +64 -0
  108. sextile-0.1.0/src/sextile/viewdata/typesetting.py +143 -0
  109. sextile-0.1.0/src/sextile/viewdata/wrapping.py +141 -0
  110. sextile-0.1.0/src/sextile/visits.py +230 -0
  111. sextile-0.1.0/tests/data/viewdata_fixture.html +24 -0
  112. sextile-0.1.0/tests/exemplar.py +121 -0
  113. sextile-0.1.0/tests/test_addressing.py +92 -0
  114. sextile-0.1.0/tests/test_ansi.py +108 -0
  115. sextile-0.1.0/tests/test_application.py +1076 -0
  116. sextile-0.1.0/tests/test_blocks.py +99 -0
  117. sextile-0.1.0/tests/test_canvas.py +387 -0
  118. sextile-0.1.0/tests/test_charset.py +148 -0
  119. sextile-0.1.0/tests/test_charting.py +90 -0
  120. sextile-0.1.0/tests/test_cli.py +248 -0
  121. sextile-0.1.0/tests/test_command_line.py +108 -0
  122. sextile-0.1.0/tests/test_commands.py +364 -0
  123. sextile-0.1.0/tests/test_compass.py +195 -0
  124. sextile-0.1.0/tests/test_composition.py +537 -0
  125. sextile-0.1.0/tests/test_contents.py +151 -0
  126. sextile-0.1.0/tests/test_control_codes.py +129 -0
  127. sextile-0.1.0/tests/test_display.py +120 -0
  128. sextile-0.1.0/tests/test_drawing.py +233 -0
  129. sextile-0.1.0/tests/test_encoding.py +134 -0
  130. sextile-0.1.0/tests/test_fields.py +414 -0
  131. sextile-0.1.0/tests/test_font.py +278 -0
  132. sextile-0.1.0/tests/test_footer.py +217 -0
  133. sextile-0.1.0/tests/test_formatting.py +337 -0
  134. sextile-0.1.0/tests/test_forms.py +553 -0
  135. sextile-0.1.0/tests/test_frame.py +271 -0
  136. sextile-0.1.0/tests/test_frame_engine.py +91 -0
  137. sextile-0.1.0/tests/test_guidance.py +89 -0
  138. sextile-0.1.0/tests/test_handlers.py +80 -0
  139. sextile-0.1.0/tests/test_hangup.py +65 -0
  140. sextile-0.1.0/tests/test_history.py +137 -0
  141. sextile-0.1.0/tests/test_icons.py +74 -0
  142. sextile-0.1.0/tests/test_idle_warning.py +72 -0
  143. sextile-0.1.0/tests/test_layout.py +625 -0
  144. sextile-0.1.0/tests/test_lettering.py +460 -0
  145. sextile-0.1.0/tests/test_middleware.py +212 -0
  146. sextile-0.1.0/tests/test_names.py +69 -0
  147. sextile-0.1.0/tests/test_page.py +128 -0
  148. sextile-0.1.0/tests/test_pages.py +206 -0
  149. sextile-0.1.0/tests/test_public_surface.py +244 -0
  150. sextile-0.1.0/tests/test_readership.py +189 -0
  151. sextile-0.1.0/tests/test_repaint.py +200 -0
  152. sextile-0.1.0/tests/test_router.py +163 -0
  153. sextile-0.1.0/tests/test_routing.py +458 -0
  154. sextile-0.1.0/tests/test_server.py +458 -0
  155. sextile-0.1.0/tests/test_session.py +998 -0
  156. sextile-0.1.0/tests/test_skeleton.py +13 -0
  157. sextile-0.1.0/tests/test_state.py +60 -0
  158. sextile-0.1.0/tests/test_testing.py +145 -0
  159. sextile-0.1.0/tests/test_transliteration.py +191 -0
  160. sextile-0.1.0/tests/test_typesetting.py +264 -0
  161. sextile-0.1.0/tests/test_typing_repaint.py +190 -0
  162. sextile-0.1.0/tests/test_viewdata_html.py +99 -0
  163. sextile-0.1.0/tests/test_visits.py +120 -0
  164. sextile-0.1.0/tests/test_wrapping.py +204 -0
@@ -0,0 +1,24 @@
1
+ # Python-generated files
2
+ __pycache__/
3
+ *.py[oc]
4
+ build/
5
+ dist/
6
+ wheels/
7
+ *.egg-info
8
+
9
+ # Virtual environments
10
+ .venv
11
+
12
+ # The archive Sextile accumulates at runtime
13
+ *.sqlite
14
+
15
+ # macOS
16
+ .DS_Store
17
+
18
+ # Editors
19
+ .idea/
20
+ .vscode/
21
+
22
+ # Sphinx build output and autosummary-generated stubs
23
+ docs/_build/
24
+ uv.lock
sextile-0.1.0/LICENSE ADDED
@@ -0,0 +1,26 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Robert Smallshire
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
23
+ ---
24
+
25
+ The MIT licence above covers the software and its documentation. It does not,
26
+ and cannot, cover third-party material included for testing. See NOTICE.md.
@@ -0,0 +1,51 @@
1
+ # Third-party material
2
+
3
+ Sextile is MIT licensed (see [LICENSE](LICENSE)). The mosaic font faces and the
4
+ Bedstead font it ships are not ours to license, and are noted here. Each face
5
+ also carries its source and terms in its own header, and the conversion to this
6
+ project's format changes the format and nothing else about the design.
7
+
8
+ ## Fonts
9
+
10
+ `sextile/viewdata/fonts/` holds bitmap faces converted into this project's own
11
+ format. None is covered by the MIT grant above.
12
+
13
+ ### Free for public use
14
+
15
+ | face | from |
16
+ |---|---|
17
+ | `acorn` | MDFS ArcNormal (mdfs.net/Apps/Font/Fonts1.zip), by J.G.Harston |
18
+
19
+ ### Public domain (Creative Commons Zero v1.0)
20
+
21
+ `3x3-mono` (GGBotNet), `boldbash` (Michiel), `lilliputsteps` (Raymond Larabie),
22
+ `pixeloperator` and its variants (Jayvee Enaguas / HarvettFox96), `pixelplace`
23
+ (Michiel), `publicpixel` (GGBotNet).
24
+
25
+ ### SIL Open Font License, Version 1.1
26
+
27
+ The licence text and copyright notices are in `sextile/viewdata/fonts/OFL-1.1.txt`,
28
+ which ships with the faces because the licence requires it. Converting a font to
29
+ another format makes a Modified Version, which may not use a reserved font name,
30
+ so several carry a name of ours instead; the original is named in each file's
31
+ `source:` line, and the mapping is in the licence file.
32
+
33
+ `arcade` (QuinqueFive, GGBotNet), `console` and `console-bold` (Dogica, Roberto
34
+ Mocci), `garland` (Birch Leaf, solirides), `grotesque` and `grotesque-bold`
35
+ (Pixeloid Sans, GGBotNet), `roman` (Times9k, Sammy L. Koch), `scientifica` and
36
+ its variants (Akshay Oppiliappan), `silkscreen` and `silkscreen-bold` (Jason
37
+ Kottke).
38
+
39
+ The CC0 and Open Font faces come from `github.com/michielp1807/more-fonts`, whose
40
+ own MIT licence covers its source and not the faces it collects.
41
+
42
+ ## Bedstead
43
+
44
+ `sextile/viewdata/static/bedstead.woff2` is Bedstead, the Mullard SAA5050
45
+ teletext character generator recreated as an OpenType font by bjh21 (Ben
46
+ Harris), which draws Viewdata frames as HTML — `sextile render --form html`
47
+ ships it. The program that generates Bedstead and its newly-designed glyphs are
48
+ released into the public domain (CC0-1.0); the original SAA5050 bitmap is stated
49
+ to be public domain in the United Kingdom under Section 55 of the Copyright,
50
+ Designs and Patents Act 1988. Vendored from `https://bjh21.me.uk/bedstead/bedstead.otf`
51
+ and converted to WOFF2 with fontTools; the design is unchanged.
sextile-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,119 @@
1
+ Metadata-Version: 2.5
2
+ Name: sextile
3
+ Version: 0.1.0
4
+ Summary: A framework for Prestel-style Viewdata services
5
+ Project-URL: Homepage, https://github.com/rob-smallshire/sextile
6
+ Project-URL: Documentation, https://rob-smallshire.github.io/sextile/
7
+ Project-URL: Repository, https://github.com/rob-smallshire/sextile
8
+ Project-URL: Issues, https://github.com/rob-smallshire/sextile/issues
9
+ Project-URL: Changelog, https://github.com/rob-smallshire/sextile/blob/master/CHANGELOG.md
10
+ Author-email: Robert Smallshire <robert@smallshire.org.uk>
11
+ License-Expression: MIT
12
+ License-File: LICENSE
13
+ License-File: NOTICE.md
14
+ Keywords: bbc-micro,prestel,retrocomputing,teletext,videotex,viewdata
15
+ Classifier: Development Status :: 3 - Alpha
16
+ Classifier: Framework :: AsyncIO
17
+ Classifier: Intended Audience :: Developers
18
+ Classifier: Operating System :: OS Independent
19
+ Classifier: Programming Language :: Python :: 3
20
+ Classifier: Programming Language :: Python :: 3 :: Only
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Topic :: Communications
24
+ Classifier: Topic :: Software Development :: Libraries
25
+ Classifier: Topic :: Terminals
26
+ Requires-Python: >=3.12
27
+ Requires-Dist: anyascii>=0.3
28
+ Description-Content-Type: text/markdown
29
+
30
+ # Sextile
31
+
32
+ [![CI](https://github.com/rob-smallshire/sextile/actions/workflows/ci.yml/badge.svg)](https://github.com/rob-smallshire/sextile/actions/workflows/ci.yml)
33
+ [![PyPI](https://img.shields.io/pypi/v/sextile.svg)](https://pypi.org/project/sextile/)
34
+ [![Python](https://img.shields.io/pypi/pyversions/sextile.svg)](https://pypi.org/project/sextile/)
35
+ [![Licence](https://img.shields.io/pypi/l/sextile.svg)](https://github.com/rob-smallshire/sextile/blob/master/LICENSE)
36
+ [![Docs](https://img.shields.io/badge/docs-github.io-blue)](https://rob-smallshire.github.io/sextile/)
37
+
38
+ A framework for Viewdata services, in Python. Sextile is to a Prestel-style
39
+ service what Flask or Starlette is to a web application: it owns the connection,
40
+ the session, the page numbering and the frames on the wire, and you write what
41
+ the pages say. The [documentation](https://rob-smallshire.github.io/sextile/)
42
+ opens with what Viewdata is.
43
+
44
+ ```sh
45
+ uv add sextile # or pip install sextile
46
+ ```
47
+
48
+ ```python
49
+ from sextile import Page, PageRequest, Sextile, notice_page
50
+
51
+ app = Sextile(name="My service")
52
+
53
+ @app.page("1", name="main", keywords=("MAIN",))
54
+ async def main(request: PageRequest) -> Page:
55
+ return notice_page(request, "Hello, 1981.")
56
+ ```
57
+
58
+ ```sh
59
+ sextile serve my_service:app # answer calls on port 6850
60
+ nc localhost 6850 # and call it
61
+ ```
62
+
63
+ ## What it gives you
64
+
65
+ **Routing by page number.** Patterns of literal digits and named fields, so
66
+ `82{post_id:int}` answers every page beginning 82 and hands the rest to the
67
+ handler already read as an integer. `app.address_for("post", post_id=...)` reads
68
+ the same pattern backwards, so a page linking to another does not respell the
69
+ numbering. Keywords — `*MAIN#` for `*1#` — are the route's `keywords=`.
70
+
71
+ **Sessions that last as long as the line.** A Viewdata terminal is a display and
72
+ nothing more: it holds the frame on screen and nothing else. So the server holds
73
+ where the reader is, what they have seen, and the menu they came through, and a
74
+ handler is a function of a request rather than of a number. The reasoning is in
75
+ [the explanation](https://rob-smallshire.github.io/sextile/explanation/why-sextile.html).
76
+
77
+ **The wire, measured rather than assumed.** Attributes travel as `ESC` + code +
78
+ 0x40, a frame is 24 rows of 40 that wraps at the bottom-right back to the top
79
+ left, `RETURN` transmits 0x5F. Those were settled by driving real Commstar under
80
+ an emulator, and are written up in
81
+ [the encoding reference](https://rob-smallshire.github.io/sextile/reference/viewdata-encoding.html).
82
+
83
+ **Nobody is cut off without warning.** After half the idle timeout a silent
84
+ caller's footer becomes a bar that drains, reading `Press a key`. The first key
85
+ dismisses it and does nothing else, so it is safe to press whatever comes to
86
+ hand. Every service gets this without writing anything.
87
+
88
+ **Forty columns, accounted for.** A colour attribute occupies a character cell,
89
+ so a row that changes colour twice has thirty-eight columns for text. `Canvas`
90
+ does that arithmetic so nothing above it has to.
91
+
92
+ **Drawable without a Beeb.** `sextile render` draws any page four ways: `ansi`
93
+ colour as the Beeb would draw it, `grid` for the character and attribute layers,
94
+ `bytes` for the wire stream, and `html` for a self-contained web page with the
95
+ Bedstead font embedded, opening from disk with no server.
96
+
97
+ ## Documentation
98
+
99
+ The full documentation is at
100
+ [rob-smallshire.github.io/sextile](https://rob-smallshire.github.io/sextile/):
101
+ [the tutorial](https://rob-smallshire.github.io/sextile/tutorial/index.html)
102
+ builds a service step by step, the
103
+ [how-to guides](https://rob-smallshire.github.io/sextile/how-to/index.html)
104
+ answer particular questions, the
105
+ [reference](https://rob-smallshire.github.io/sextile/reference/index.html) states
106
+ the surface, the glossary and the wire, and the
107
+ [explanation](https://rob-smallshire.github.io/sextile/explanation/index.html)
108
+ says why the framework is shaped as it is.
109
+
110
+ ## Status
111
+
112
+ Young, and extracted from a working service rather than designed in the abstract.
113
+ Three applications use it in the
114
+ [source repository](https://github.com/rob-smallshire/sextile): a real Stardot
115
+ forum reader, a weather service, and a calendar written to be read.
116
+
117
+ MIT licensed. The bundled font faces and the Bedstead font are third-party
118
+ material; see
119
+ [NOTICE.md](https://github.com/rob-smallshire/sextile/blob/master/packages/sextile/NOTICE.md).
@@ -0,0 +1,90 @@
1
+ # Sextile
2
+
3
+ [![CI](https://github.com/rob-smallshire/sextile/actions/workflows/ci.yml/badge.svg)](https://github.com/rob-smallshire/sextile/actions/workflows/ci.yml)
4
+ [![PyPI](https://img.shields.io/pypi/v/sextile.svg)](https://pypi.org/project/sextile/)
5
+ [![Python](https://img.shields.io/pypi/pyversions/sextile.svg)](https://pypi.org/project/sextile/)
6
+ [![Licence](https://img.shields.io/pypi/l/sextile.svg)](https://github.com/rob-smallshire/sextile/blob/master/LICENSE)
7
+ [![Docs](https://img.shields.io/badge/docs-github.io-blue)](https://rob-smallshire.github.io/sextile/)
8
+
9
+ A framework for Viewdata services, in Python. Sextile is to a Prestel-style
10
+ service what Flask or Starlette is to a web application: it owns the connection,
11
+ the session, the page numbering and the frames on the wire, and you write what
12
+ the pages say. The [documentation](https://rob-smallshire.github.io/sextile/)
13
+ opens with what Viewdata is.
14
+
15
+ ```sh
16
+ uv add sextile # or pip install sextile
17
+ ```
18
+
19
+ ```python
20
+ from sextile import Page, PageRequest, Sextile, notice_page
21
+
22
+ app = Sextile(name="My service")
23
+
24
+ @app.page("1", name="main", keywords=("MAIN",))
25
+ async def main(request: PageRequest) -> Page:
26
+ return notice_page(request, "Hello, 1981.")
27
+ ```
28
+
29
+ ```sh
30
+ sextile serve my_service:app # answer calls on port 6850
31
+ nc localhost 6850 # and call it
32
+ ```
33
+
34
+ ## What it gives you
35
+
36
+ **Routing by page number.** Patterns of literal digits and named fields, so
37
+ `82{post_id:int}` answers every page beginning 82 and hands the rest to the
38
+ handler already read as an integer. `app.address_for("post", post_id=...)` reads
39
+ the same pattern backwards, so a page linking to another does not respell the
40
+ numbering. Keywords — `*MAIN#` for `*1#` — are the route's `keywords=`.
41
+
42
+ **Sessions that last as long as the line.** A Viewdata terminal is a display and
43
+ nothing more: it holds the frame on screen and nothing else. So the server holds
44
+ where the reader is, what they have seen, and the menu they came through, and a
45
+ handler is a function of a request rather than of a number. The reasoning is in
46
+ [the explanation](https://rob-smallshire.github.io/sextile/explanation/why-sextile.html).
47
+
48
+ **The wire, measured rather than assumed.** Attributes travel as `ESC` + code +
49
+ 0x40, a frame is 24 rows of 40 that wraps at the bottom-right back to the top
50
+ left, `RETURN` transmits 0x5F. Those were settled by driving real Commstar under
51
+ an emulator, and are written up in
52
+ [the encoding reference](https://rob-smallshire.github.io/sextile/reference/viewdata-encoding.html).
53
+
54
+ **Nobody is cut off without warning.** After half the idle timeout a silent
55
+ caller's footer becomes a bar that drains, reading `Press a key`. The first key
56
+ dismisses it and does nothing else, so it is safe to press whatever comes to
57
+ hand. Every service gets this without writing anything.
58
+
59
+ **Forty columns, accounted for.** A colour attribute occupies a character cell,
60
+ so a row that changes colour twice has thirty-eight columns for text. `Canvas`
61
+ does that arithmetic so nothing above it has to.
62
+
63
+ **Drawable without a Beeb.** `sextile render` draws any page four ways: `ansi`
64
+ colour as the Beeb would draw it, `grid` for the character and attribute layers,
65
+ `bytes` for the wire stream, and `html` for a self-contained web page with the
66
+ Bedstead font embedded, opening from disk with no server.
67
+
68
+ ## Documentation
69
+
70
+ The full documentation is at
71
+ [rob-smallshire.github.io/sextile](https://rob-smallshire.github.io/sextile/):
72
+ [the tutorial](https://rob-smallshire.github.io/sextile/tutorial/index.html)
73
+ builds a service step by step, the
74
+ [how-to guides](https://rob-smallshire.github.io/sextile/how-to/index.html)
75
+ answer particular questions, the
76
+ [reference](https://rob-smallshire.github.io/sextile/reference/index.html) states
77
+ the surface, the glossary and the wire, and the
78
+ [explanation](https://rob-smallshire.github.io/sextile/explanation/index.html)
79
+ says why the framework is shaped as it is.
80
+
81
+ ## Status
82
+
83
+ Young, and extracted from a working service rather than designed in the abstract.
84
+ Three applications use it in the
85
+ [source repository](https://github.com/rob-smallshire/sextile): a real Stardot
86
+ forum reader, a weather service, and a calendar written to be read.
87
+
88
+ MIT licensed. The bundled font faces and the Bedstead font are third-party
89
+ material; see
90
+ [NOTICE.md](https://github.com/rob-smallshire/sextile/blob/master/packages/sextile/NOTICE.md).