# T-DeckARD: T-Deck Augmented Runtime Distribution
## About
T-DeckARD is a curated, interconnected and integrated collection of Python 3 modules developed for CircuitPython 10.x on LilyGO T-Deck (but also mostly compatible with MicroPython and desktop CPython) aimed at turning the stock (Circuit)Python REPL into an easy to use operating environment.
T-DeckARD modules are divided into two categories: **components**, which are the building blocks anyone can use to easily create their own applications, and ready-made **applets** which can already be used as stand-alone applications, as well as included as components of other, more complicated ones. This repo also hosts the **games** section which is just a special kind of applets that implement various computer games.
Current installation process doesn't involve any `.mpy` module compilation, so, after installing the prerequisites, you just need to copy the `repl`, `deck`, `app` and `game` directories, as well as the `code.py` and `tdeckboot.py` files, into the root of the `CIRCUITPY` removable volume.
A library for single-line and multi-line (ed-like) text input.
Exported functions:
-`input(prompt=None)`: standard single-line Python input
-`input_multi(prompt=None, terminator='.')`: multi-line input, end with the terminator string on a separate line
### `deck.pager`
A library for paged text output. In CPython, relies on the terminal dimensions provided by the host OS. In CircuitPython and MicroPython, it requires correct values to be provided inside `TERM_COLS` and `TERM_ROWS` environment variables. In case they are not provided, these values default to 53 columns and 19 rows (the actual value for T-Deck running `tdeck_repl` in CircuitPython).
Exported functions:
-`term_size()`: return the terminal dimensions tuple in the `(rows, columns)` format
-`reflow(text)`: split text into a list of lines not exceeding terminal width
-`confirm(msg, yes='y', no='n', alt_prompt=None)`: prompt for yes/no confirmation, using a standard prompt in `msg` and the `yes`/`no` message in the corresponding parameters, or a completely alternative prompt in `alt_prompt`.Returns True or False as the result.
-`shortmenu(choices, suffix=': ')`: display several menu items from the `choices` list, automatically labeling the first fitting letter from the item as the selection shortcut. Returns a tuple (`result`, `label`), or (``,``) in case the selection doesn't match.
-`menu(choices)`: display up to 10 menu items with the ability to select them with a single digit or a key on the `QWERTYUIOP` keyboard row. Accepts a list of **tuples**, each in the format `(id, label)`. The `label` field is what's displayed on the screen, the `id` field is the string that gets returned upon selection. If the user selects `c`, the operation is canceled and an empty `id` string is returned.
-`start_state`: the state object to be modified by chat actions
-`chat_prefix`: the prefix to be displayed before each user's message input
-`command_prefix`: the prefix to be prepended to every registered chat command
Every chat instance exposes the following methods:
-`command(command_name, handler)`: register a command under the `command_name` according to the handler specification (see below); e.g. if the prefix is `/` and the command name is `list`, the chat will react to the `/list` command and pass everything after it as the argument to the handler function
-`start()`: start the chat loop (keyboard interrupts, if any are supported, exit the loop)
The handler accepts two parameters: a message and a state object, and returns the response and the new state object. If the returned state object is `None`, then the chat loop exits. Non-command handler (i.e. what should be done on any user input that doesn't start with a registered command) is registered under the `default` command.
T-Deck/CircuitPython-specific library for Wi-Fi connection and returning `requests` and `socket` library instances.
Exported functions:
-`wifi_scan()`: scan available Wi-Fi networks and return the list of `(ssid, rssi)` tuples (sorted from the strongest signal to the weakest)
-`wifi_connect(ssid=None, password=None)`: connect to a Wi-Fi SSID without waiting (default credentials are pulled from the `/settings.toml` file)
-`wifi_connect_wait(ssid=None, password=None, tmout=15, retries=3)`: connect to a Wi-Fi SSID (with the same parameters as `wifi_connect`) and wait until the connection is established
-`my_ip()`: return the current local IPv4 (as a string)
-`ssl_context()`: get the default SSL context for wrapping in a raw socket
-`init_socket()`: return the active reference to the `socket` library
-`init_requests()`: return the active reference to the `requests` library
-`init_ntp(tz=0)`: return an NTP time client instance (use the `.datetime` property of the instance to access current time and the `tz` parameter to specify the timezone offset)
-`wput(url, file_path, field_name="file", method="POST", format="x-www-form-urlencoded", headers={}, useragent=None)`: upload a file from a local path in the `x-www-form-urlencoded` or JSON format (returns `(status_code, content)` tuple)
A library that provides HOTP and TOTP one-time password implementations.
Exports the following functions:
-`hotp(key, counter, digits=6)`: generate a `digits`-long HOTP code from (bytes-only) key and counter value
-`totp(key, time_step, digits=6)`: generate a `digits`-long TOTP code from (bytes-only) key, using `time_step` as the basis (30 seconds is default and the most common)
-`get_epoch()`: a helper platform-agnostic function to get the current Unix timestamp in seconds
A library that implements a [DeckText](decktext-spec.md) format parser. Exports a single class, `DeckText`, with the following methods:
-`doc = DeckText(src=None)` constructor: initialize a DeckText document object from the passed source
-`doc.load(src)`: load DeckText source into the existing document object.
After the source is loaded, the document object exposes two properties: `title` and `pages`.
The `title` property is a normal string that represents the document's title (read from the `<title>` HTML tag).
The `pages` property contains a list of DeckText pages in the form of `{content, links}` dictionary, where `content` is the rendered (ready-to-display) page content and `links` is the list of links present on the page.
Each link is in the form of `(url, label)` tuple. The client using this class for DeckText page rendering is supposed to provide a UI to visit the links based on this list.
A helper library for interaction with remote LLM (large language model) endpoints that expose OpenAI-compatible API. As of now, it only exports a single class, `LLMChat`, to encapsulate all the interaction.
To initialize, this class requires a provider configuration object from a JSON file that looks like this:
```json
{
"temperature":0.7,
"system_prompt":"You are a concise, embedded assistant.",
As of now, T-DeckARD implements the following applets.
### `app.ed`
A simple line-oriented text editor and page-oriented text viewer for MicroPython/CircuitPython implementing a POSIX `ed` subset (feature-wise, it still is closer to EDLIN from DOS).
-`edit(filename)`: start an `ed`-like text editor on a file (see below)
-`edbuf(bufstr='')`: create an empty buffer, fill it with the input string (if any), run the editor interface on it and return the result as a string (without creating any files)
-`edurl(url)`: download the URL contents via HTTP, run the editor interface on it and return the result as a string (without creating any files)
-`viewbuf(text, lno=False)`: same as `view` but for string variables instead of files
-`viewurl(url, lno=False)`: download the URL contents via HTTP and run `viewbuf` method on the result
Note: with `edbuf` and `edurl` methods, you can always save the file locally while inside the editor interface. Use the `f` command to specify the name (see below).
A simple interactive chat with remote LLMs. Configured via `llmcfg.json` (see the `deck.llm` module reference and the `llmcfg.example.json` file) placed into the storage root. Run with the single `llmchat()` method it exports.
As of now, T-DeckARD implements the following games.
### Scoundrel (`game.scoundrel`)
A port of the rogue-like card game Scoundrel to CircuitPython. Uses `M` to denote monsters, `W` to denote weapons, `P` to denote potions and `D` to denote weapon durability.
Implements the [official ruleset](http://www.stfj.net/art/2011/Scoundrel.pdf) of the game with no modifications.
Run: `scoundrel()` from the REPL itself, or use `from game.scoundrel import scoundrel` in other code.
Controls: enter `a`, `b`, `c` or `d` to interact with an item above this letter in the room, or `r` to run from the room in case it's possible. To quit the game before winning or losing, enter the `q` command at any time.
No, but it provides comparable functionality to the on-device Python REPL. You can easily build a shell application from the T-DeckARD components.
### Why doesn't it include a shell by default?
It may at some point, but the entire idea is to give you the foundation to easily create your own custom shells for any special purposes. The project carries the spirit of early personal computing days when the programming language REPL (BASIC, Forth, Lisp etc) **was** your primary operating environment. In this case, the on-device Python REPL is such an environment.
To get the hang of what the shell **might** look like, you can already access some of the common methods from the main core modules via T-DeckARD REPL. See the [tdeckboot.py](./tdeckboot.py) file for details.
### So, what's the difference between `tdeckboot.py` and `autoexec.py`?
Everything that gets imported inside `tdeckboot.py` becomes automatically available in the T-DeckARD interactive REPL. This file is solely designed for passthrough import of modules into the REPL and nothing more.
Everything that gets imported inside `autoexec.py` stays in `autoexec.py`. This is just your usual startup script.
You can use `tdeckboot.py` for autoexecing but that's not recommended as this carries a heavy risk of REPL namespace pollution.