rs-rich-micro
Micro assets for rs-rich,
the Rust port of Python's rich: emoji-sized inline images and animations,
written Deploying :micro:rocket:. This crate is an rs-rich addition, not a
port: rich has no micro assets. Core is untouched; :micro:name: is not an
emoji code, so it passes through core as plain text.
0.0.1 holds the model, the package format, the layered registry, the
markup and the drawing: MicroGraphics picks Kitty, iTerm2, Sixel,
half-blocks or the emoji or text fallback for the terminal (RICH_MICRO
overrides it; a pipe always gets the text), animates where it can, and
carries images through rich-ext's live regions and the interactive
painter. It also has the image pipeline that makes packages from any
picture (pipeline, create) and a built-in library (builtin), which
rich micro in the rich CLI puts on the command line. 0.0.2 adds
:micro:name: in Markdown (PreparedMarkdown, MarkdownView).
use Console;
use ;
let mut registry = new;
registry.add?;
let console = builder.width.build;
let =
render_markup;
assert_eq!;
assert!;
Assets
A MicroAsset has a name ([a-z0-9_-] segments joined by /, like
status/success), a kind (static or animated), a size in cells (2×1 by
default, the footprint of an emoji; up to 4×2, so 1×1, a 2×2 icon or a 3×2
animation too), images,
mandatory alt text, an emoji and/or text fallback that must fit its
columns, aliases, and where it came from (layer, pack, version, licence,
author).
Packages
A .richmicro package is a zip archive or a directory:
success.richmicro/
├── manifest.json {"schema_version": 1, "name": "status/success", "alt": "…",
│ "size": "2x1", "fallback": {"emoji": "✅", "text": "OK"},
│ "static": "static.png", "animation": "animation.gif"}
├── static.png
└── animation.gif optional: GIF, APNG or WebP; or "frames": [...]
A pack is a directory or archive with a pack.json listing its packages.
Packages are untrusted input: hard Limits bound archive and file sizes,
entry counts, the manifest, pixel dimensions, frame counts and the bytes an
asset takes decoded, all checked from headers without decoding; paths that
are absolute, use .., or are links out of the package are refused.
Registry
Layers resolve built-in (MicroRegistry::builtin()) < user
(~/.config/rich/micro/) < trusted project
(.rich/micro/) < inline. A project's assets load only when the caller says
the project is trusted. Aliases resolve within their layer; two claims on a
name in one layer are reported as a collision, and the first in file-name
order wins. MicroRegistry::explain(name) shows the chain.
Markup and API
:micro:name:is the one syntax;\:micro:escapes it. Unknown names stay as written and come back as diagnostics.render_markup/markup_text/PreparedMarkupswap tokens out before core parses the markup, so:micro:ship::fire:gets both.PreparedMarkdowndoes the same for a Markdown document: each token outside code spans and fenced blocks becomes stand-in cells of the asset's width, and itsview(Markdown::new(prepared.source()))turns them back into placeholders after rendering.MicroExtonText(append_micro,expand_micro), theMicroAssetRefrenderable, andMicroTransform/MicroPluginfor transform pipelines.
Placeholders
An asset in a Text is exactly its columns of ordinary text (its fallback,
padded with U+2800) under a style whose metadata holds rich.micro = [name, cols, rows, id]. So it measures, wraps, crops and sits in tables and
panels at exactly its width, and prints as plain fallback in pipes, logs and
exports. MicroView offers each complete placement to MicroRenderers,
which may swap it for other cells of the same width.
That is an asset's first row. A two-row asset (2×2, 3×2) also takes the row
below its line: MicroRows reserves it after layout, blank but for the
asset's second row, in wrapped text, table cells and panels, so nothing is
ever drawn over the next line. Kitty, iTerm2, Sixel and half-blocks then
draw over both rows; without the reserved row, the first row's fallback
shows.
Making assets
pipeline::Pipeline takes a PNG, APNG, GIF, JPEG or WebP and fits every frame to
exactly the asset's cells (contain, cover with an anchor, or stretch), with
brightness, contrast and gamma, an optional unsharp mask, a transparency
rule (a threshold, kept, flattened, or a key colour) and an optional
reduced palette, using rs-rich-art's image code; animations are
deduplicated and rate-limited. create::write_package writes the result as
a package directory or .richmicro zip and reads it back, so what it
returns is what the registry accepts. Processed::preview magnifies it.
The built-in library
| Pack | Assets |
|---|---|
status |
status/success, status/warning, status/error, status/info, status/loading (animated) |
dev |
dev/bug, dev/branch, dev/terminal, dev/package |
fun |
fun/heart (animated), fun/star, fun/cat, fun/coffee (animated) |
Drawn for this project by examples/gen_builtin.rs, each with alt text, an
emoji and a text fallback, and the MIT licence; no third-party logos, and
no name is an emoji code.
Licensed MIT.