3 unstable releases
| 0.2.6 | Sep 18, 2025 |
|---|---|
| 0.2.0 | Sep 10, 2025 |
| 0.1.0 | Sep 9, 2025 |
#931 in GUI
111 downloads per month
340KB
9K
SLoC
ratatui_ffi
Native C ABI for Ratatui, shipped as a tiny cdylib you can call from C, C#, Python, TypeScript (via FFI), and more. Optimized for hot loops: span‑based setters and batch APIs minimize allocations and marshaling.
Highlights
- Widgets: Paragraph, List (+state), Table (+state), Tabs, Gauge, LineGauge, BarChart, Sparkline, Chart, Scrollbar, Clear, RatatuiLogo, Canvas.
- Layout:
layout_split,layout_split_ex(spacing + per‑side margins),layout_split_ex2(addsConstraint::Ratio). - Text/Styles:
FfiStyle,FfiSpan,FfiLineSpans; lines of styled spans; paragraph base style, alignment, wrap(trim), scroll; named/RGB/indexed colors; all modifiers (incl. hidden/blink). - Blocks: per‑side borders, border type, padding, title alignment, and title as spans across all block‑bearing widgets.
- Terminal: init/clear, batched frame render, raw/alt toggles, cursor get/set/show, size, event poll and injection.
- Headless: ASCII snapshots; compact and extended style dumps; structured cell dump (
FfiCellInfo). - Throughput: list/paragraph/table batching; table multi‑line cells; dataset batching; reserve helpers.
- Zero‑alloc paths: span‑based label/title/divider setters for hot code paths.
Quick Start
Language Bindings
- C#: holo-q/Ratatui.cs
- Python: holo-q/ratatui-py
- Go: holo-q/ratatui-go
- TypeScript: holo-q/ratatui-ts
Building
Build the library:
cargo build --release
# → target/release/libratatui_ffi.so (Linux), .dylib (macOS), ratatui_ffi.dll (Windows)
Use from C (example: Gauge label spans):
FfiStyle white = { .fg = 0x00000010, .bg = 0, .mods = 0 }; // white named
FfiSpan spans[2] = {
{ .text_utf8 = "Load ", .style = white },
{ .text_utf8 = "80%", .style = white },
};
ratatui_gauge_set_label_spans(gauge, spans, 2);
Aspects
Span‑Based Setters (Zero‑Alloc Paths)
Preferred over UTF‑8 string setters in hot loops. All functions treat FfiSpan.text_utf8 as NUL‑terminated UTF‑8 without ownership transfer.
- Tabs:
ratatui_tabs_set_divider_spans(spans, len) - Gauge:
ratatui_gauge_set_label_spans(spans, len),ratatui_gauge_set_block_title_spans(spans, len, show_border) - LineGauge:
ratatui_linegauge_set_label_spans(spans, len) - BarChart:
ratatui_barchart_set_labels_spans(lines, len),ratatui_barchart_set_block_title_spans(spans, len, show_border) - Table:
ratatui_table_set_block_title_spans(spans, len, show_border) - Paragraph/List/Tabs/LineGauge/Chart/Sparkline/Scrollbar/Canvas:
*_set_block_title_spans(spans, len, show_border)
Notes and limits:
- Tabs divider: if a single span is provided, style is preserved; otherwise texts are concatenated (ratatui accepts a single
Span). - Gauge label: texts are concatenated; use
ratatui_gauge_set_styles(..., label_style, ...)for label styling. - BarChart labels: per‑label styling is not supported by ratatui; text‑only, same as TSV path.
FFI Types
FfiStyle { fg: u32, bg: u32, mods: u16 }with helpersratatui_color_rgb,ratatui_color_indexed.FfiSpan { text_utf8: *const c_char, style: FfiStyle }FfiLineSpans { spans: *const FfiSpan, len: usize }- Structured outputs:
FfiCellInfo(headless), list/table state types, draw commands for batched frames.
Headless Rendering
- Text snapshots:
ratatui_headless_render_frame, and per‑widget helpers (_paragraph,_list,_table, ...). - Style snapshots:
- Compact:
ratatui_headless_render_frame_styles→ rows ofFG2 BG2 MOD4hex (named palette). - Extended:
ratatui_headless_render_frame_styles_ex→FG8 BG8 MOD4hex (FfiStyleencoding). - Structured cells:
ratatui_headless_render_frame_cells→ fill array ofFfiCellInfo.
- Compact:
Feature Bits (Introspection)
Call ratatui_ffi_feature_bits() to detect support at runtime. Bits include:
SCROLLBAR,CANVAS,STYLE_DUMP_EX,BATCH_TABLE_ROWS,BATCH_LIST_ITEMS,COLOR_HELPERS,AXIS_LABELS,SPAN_SETTERS.
Tips
Hot‑Path Tips
- Prefer span‑based setters and batched APIs to avoid allocations and repeated marshaling.
- Reserve capacity where possible (
ratatui_*_reserve_*) before large appends. - Use headless render snapshots in CI for fast, deterministic tests.
Runtime Behavior & Logging
- By default raw mode is enabled; use
RATATUI_FFI_NO_RAW=1to disable;RATATUI_FFI_ALTSCR=1to use the alternate screen. - Set
RATATUI_FFI_TRACE=1to traceENTER/EXITof FFI calls (stderr and optional file). - Set
RATATUI_FFI_LOG=<path>to write logs; truncate per run; useRATATUI_FFI_LOG_APPEND=1to append. - Functions that interact with the terminal are wrapped in panic guards and validate pointers/rects.
Development
Introspection & Codegen
The ffi_introspect tool drives coverage and optional code generation directly from the target crate sources (no rustdoc scraping). It is generic and configured via Cargo.toml.
-
One‑shot run (reads Cargo.toml metadata, no args):
cargo run --quiet --bin ffi_introspect- Clones the configured repo/tag into
target/src-cache/<repo>/<tag>(cached), generates code if configured, or prints a clean, hierarchical coverage log (one line per symbol). - Build first to see green binary coverage:
cargo build --release(or debug).
-
Configure in Cargo.toml:
- Under
[package.metadata.ffi_introspect]set:emit_rs→ output file for generated symbols/palettes (e.g.,src/ffi/generated.rs).widgets_emit_rs→ optional output for widget DTOs (experimental).git_url,git_tag(optional),dep_name(to derive tag from Cargo.lock).const_root(path prefix for consts) andfn_prefix(name prefix for getters).symbol_namespacesandset_modulesto control which modules emit string getters andSetstructs.const_modulesto scan nested modules (e.g.,symbols::half_block) for char/u16 constants.dto_enum_u32to map specific enums tou32in generated DTOs (e.g.,Alignment,BorderType).dto_renamesto rename generated DTOs (e.g.,layout::Rect=FfiRect).macros.*to override macro names so the generator can integrate with any project.
- Under
-
What gets generated:
- Public
&'static strconstants in configured namespaces → extern getters. struct Setconstants (module‑scoped, all&strfields) →repr(C)FFI struct + getter per const.- Palette structs (all
Colorfields) →repr(C)u32palette FFI struct + getters; singleColorconsts →u32getters. - Char/u16 symbols within configured
const_modules(e.g., half-block characters, brailleBLANK). - Widgets DTOs: placeholder file if
widgets_emit_rsis configured (implementation evolving).
- Public
-
Using the output:
- The library includes
include!("ffi/generated.rs")so getters are compiled into the cdylib. - Commit generated files so consumers don’t need the tool at runtime.
- The library includes
Safety Checks (optional)
For QA and development, you can compile additional input‑validation guards into the FFI layer.
-
Feature:
ffi_safety(disabled by default)- Build with:
cargo build --features ffi_safety - Adds lightweight validation at FFI boundaries and a small control API.
- Default builds remain zero‑overhead — no checks or safety symbols are compiled.
- Build with:
-
Runtime control (only available when built with
ffi_safety):void ratatui_ffi_set_safety(bool enabled)— enable/disable checks at runtime.void ratatui_ffi_set_caps(u16 max_w, u16 max_h, u32 max_area, u32 max_text_len, u32 max_batch)— tune caps.FfiStr ratatui_ffi_last_error()/void ratatui_ffi_clear_last_error()— observe/clear the last safety error.
-
What is validated today
- Draw rectangles: dimension and viewport sanity in renderer and per‑widget draw_in paths.
- Lists: per‑item UTF‑8 length cap; batch length cap; selected/offset clamped to item count.
- Paragraphs: per‑item UTF‑8 length cap; batch length cap; rect sanity in draw_in.
- Tables: rect sanity in both stateful and stateless draw_in.
-
Recommended usage for bindings
- Ship two artifacts if you prefer (with/without
ffi_safety), or ask advanced users to build from submodule. - In debug/QA builds of the
ffi_safetyartifact, callratatui_ffi_set_safety(true)at startup and optionally set caps. In release, leave safety disabled.
- Ship two artifacts if you prefer (with/without
C Header Generation
This crate exposes a C ABI and ships a cbindgen config to generate a header for C/C++ consumers.
Generate include/ratatui_ffi.h with either:
# Rusty way (requires cbindgen installed):
cargo run --quiet --bin gen_header
# or Bash helper:
bash tools/gen_header.sh
Then include it from C/C++ bindings. CI can generate and attach it to releases.
CI Notes
Release builds can produce prebuilt binaries for Linux/macOS/Windows. See the GitHub Actions in this repo and the C# binding repo for multi‑RID examples.
Dependencies
~9–21MB
~293K SLoC