— logo by Sam Foster
See the documentation for full details.
The engine of Tattoy is a headless terminal emulator called the Shadow Terminal. Tattoy then takes the purely text-based output of this in-memory terminal, composites it with other text-based layers and then prints it to the user's host terminal. So even though it's a fully-modern terminal, it does not itself manage any GUI windows or font glyph rendering.
There are quite a few terminals, PTYs, shadow PTYs, surfaces, etc, that are all terminal-like in some way, but do different things.
- The user's actual real terminal We don't really have control of this. Or rather, Tattoy as an application merely is a kind of magic trick that reflects the real terminal whilst sprinkling eye-candy onto it. The goal of Tattoy is that you should always be able to recover your original untouched terminal.
- The PTY (pseudo TTY) of the "original" terminal process To achieve the magic trick of Tattoy we manage a "shadow" subprocess of the user's preferred shell, prompt, etc. It is managed completely in memory and is rendered headlessly. The PTY code itself is provided by the portable_pty crate from the Wezterm project ❤️.
- The headless rendering of the user's "original" terminal This is just a headless rendering of the underlying shadow PTY by an in-memory terminal emulator. This is done with a the Shadow Terminal which in term depends on wezterm_term::Terminal ❤️.
- The composited Tattoy "surface" A surface here refers to a termwiz::surface::Surface. It represents a terminal screen but is not an actual real terminal, it's merely a structured representation. This is where we can create all the magical Tattoy eye-candy. Although it does not intefere with the shadow TTY, it can be informed by it. Hence why you can create Tattoys that seem to interact with the real terminal. In the end, this Tattoy surface is composited with the contents of the shadow PTY.
- The shadow terminal "surface" This is merely a copy of the current visual status of the shadow terminal. We don't use the actual shadow terminal emulator as the source because it's possible that this data is queried frequently by various Tattoys. Querying the cached visual representation is more efficient than querying an actual TTY, even if it exists only in memory.
- The final composite "surface" This is the final composited surface of the both the underlying shadow terminal and all the active Tattoys. A diff of this with the user's current real terminal is then used to do the final update to the user's live terminal.
We use cargo nextest
, which you will need to install if you haven't already.
cargo build --all; cargo nextest run
In CI I use cargo nextest run --retries 2
because some of the e2e tests are flakey.
- Set
log_level = "trace"
in$XDG_CONFIG_DIR/tattoy/tattoy.toml
- Default log path is
$XDG_STATE_DIR/tattoy/tattoy.log
. - Log path can be changed with
log_path = "/tmp/tattoy.log"
in$XDG_CONFIG_DIR/tattoy/tattoy.toml
- Or log path can be changed per-instance with the
--log-path
CLI argument.