Skip to content

holo-q/ratatui-go

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

55 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ratatui_ffi logo ratatui-go — Go bindings for Ratatui

High‑performance Go bindings for the ratatui_ffi C ABI — the stable C layer over the Rust Ratatui engine. Build rich terminal apps with fast rendering, a robust widget set, predictable input, headless snapshots, and Go‑native ergonomics designed to avoid allocations in hot paths.

What you get

  • Widgets and layout: Paragraph, List (+state), Table (+state), Tabs, Gauge, LineGauge, BarChart, Sparkline, Chart, Clear, RatatuiLogo, Canvas, optional Scrollbar
  • Rendering: draw into rects or batch multiple widgets via Terminal.DrawFrame
  • Input: keyboard, mouse, resize (+ event injectors for tests)
  • Headless snapshots: frame text, extended styles, or cells for testing
  • Go ergonomics: Arena (per‑frame scratchpad), FrameBuilder, SmallSpans, Session helpers, Loop (tick), Keymap, Layout DSL (Percent/Min/Ratio/EqualN)

Requirements

  • Go 1.21+
  • Built ratatui_ffi shared library available at runtime
    • Linux: libratatui_ffi.so
    • macOS: libratatui_ffi.dylib
    • Windows: ratatui_ffi.dll

Install / Build

  1. Build the Rust FFI library:
cargo build --release -p ratatui_ffi
  1. Fetch the native library (recommended)

Use go:generate to fetch the correct libratatui_ffi from GitHub Releases into ./native/. Add this line once to your app and run go generate ./... before go build (in CI or locally):

//go:generate go run github.com/holo-q/ratatui-go/tools/fetch_native@latest --version v0.4.0

Thanks to rpath ($ORIGIN on Linux, @loader_path on macOS), placing the library next to your binary makes it load with no env vars.

Alternative (manual)

  • Add the library directory to your platform’s loader path, or copy the library next to your binary.
  1. Build/test your Go project that imports github.com/holo-q/ratatui-go.

Tip: set RATATUI_FFI_LIB=/absolute/path/to/libratatui_ffi.so when running the audit tool.

Bundling the native library (no env vars)

  • Use the helper to copy/download the correct library into ./native/:
# Copy from a local build
go run ./tools/fetch_native --lib ../ratatui_ffi/target/release/$(
  case "$(uname -s)" in Linux) echo libratatui_ffi.so ;; Darwin) echo libratatui_ffi.dylib ;; *) echo ratatui_ffi.dll ;; esac)

# Or download from a URL hosting your prebuilt (optionally verify checksums)
go run ./tools/fetch_native --url https://example.com/releases/libratatui_ffi-<platform>.so \
  --checksums-url https://example.com/releases/checksums.txt

Thanks to rpath, placing the library next to your app binary makes it load without LD_LIBRARY_PATH/DYLD_LIBRARY_PATH setup.

Or fetch from GitHub Releases with sane defaults:

  • Defaults: --repo holo-q/ratatui-ffi, --pattern=plain (assets named exactly libratatui_ffi.*)
  • Pass --version to choose the release tag to fetch
go run ./tools/fetch_native --version v0.4.0

If your assets are suffixed per platform (e.g., libratatui_ffi-linux-x64.so):

go run ./tools/fetch_native.go --version v0.4.0 --pattern suffixed

Spec (explicitness)

  • Defaults aim to “just work”. Override when needed:
    • --pattern suffixed for assets named libratatui_ffi-<os-arch>.* (linux-x64, darwin-arm64, windows-x64)
    • --repo org/name if you host release assets elsewhere
    • --url for fully explicit downloads

Quickstart

package main

import (
  "fmt"
  rt "github.com/holo-q/ratatui-go"
)

func main() {
  maj, min, pat := rt.Version()
  fmt.Printf("FFI: %d.%d.%d\n", maj, min, pat)

  p := rt.NewParagraph()
  defer p.Free()
  p.AppendSpan("Hello Ratatui from Go!", rt.Style{FG: rt.ColorRGB(0, 255, 180)})
  out, err := rt.HeadlessRenderParagraph(30, 3, p)
  if err != nil { panic(err) }
  fmt.Println(out)
}

Notes

  • Ownership: free returned strings via the FFI (ratatui_string_free) is handled by the wrapper; free widget handles explicitly or rely on finalizers.
  • Strings: Go strings are passed as UTF‑8 C strings; pointers remain alive for the duration of the call.
  • Loading: We link to the shared library via cgo and rely on the platform loader (see Build step 2).

Validation

  • Audit tool (no ffi_introspect):
    • go run ./tools/ffi_audit.go --lib /path/to/libratatui_ffi.so — dlsym check for symbols declared in ffi.go; also uses nm/readelf/objdump if available to compare exports
  • Headless snapshot tests: text + styles_ex + cells

Examples

  • examples/headless: render a Paragraph headlessly
  • examples/frame: init a Terminal and draw a Paragraph via batched frame
  • examples/composite: compose multiple widgets and render headless text/styles/cells
  • examples/canvas_and_logo: draw a simple Canvas (rect + line) and the Ratatui logo

Run:

go run ./examples/headless
go run ./examples/frame
go run ./examples/composite
go run ./examples/interactive
go run ./examples/canvas_and_logo

Single entrypoint (one‑liner)

  • If native lib isn’t set up, this prints friendly setup steps instead of a linker error:
go run github.com/holo-q/ratatui-go/cmd/demos@v0.1.2
  • After setup, run the real demo with the ffi tag:
go run -tags ffi github.com/holo-q/ratatui-go/cmd/demos@v0.1.2

First run setup (once per machine)

go run github.com/holo-q/ratatui-go/tools/fetch_native@latest --lib /path/to/libratatui_ffi.* --out $HOME/.local/lib
# Linux:  export LD_LIBRARY_PATH="$HOME/.local/lib:$LD_LIBRARY_PATH"   (and LIBRARY_PATH for link)
# macOS:  export DYLD_LIBRARY_PATH="$HOME/.local/lib:$DYLD_LIBRARY_PATH" (and LIBRARY_PATH for link)
# Windows: add %USERPROFILE%\.local\lib to PATH

Tests (tagged)

Headless snapshot test is behind a build tag to avoid cgo link errors when the native lib is absent.

Run with the ffi tag and ensure the library is discoverable via your platform loader paths:

go test -tags ffi ./...

go:generate (recommended, minimal)

Add one line to your app. Then run go generate ./... before go build (in CI or locally). Replace <module-path> and version with your target:

//go:generate go run github.com/holo-q/ratatui-go/tools/fetch_native@latest --version v0.4.0

That fetches the correct libratatui_ffi for your platform from GitHub Releases into ./native/. Thanks to rpath, your built app runs with no env vars.

Notes

  • Plain asset names (default): libratatui_ffi.so / .dylib / ratatui_ffi.dll → just pass --version.
  • Suffixed names (e.g., libratatui_ffi-linux-x64.so): add --pattern suffixed.

Feature bits and optional APIs

Use FeatureBits() to gate optional functionality at runtime:

  • STYLE_DUMP_EX: extended styles dump via HeadlessRenderFrameStylesEx
  • CANVAS: canvas APIs (Canvas widget)
  • SCROLLBAR: Scrollbar widget — ratatui-go uses runtime symbol lookup; constructors return errors if unavailable
  • AXIS_LABELS / batching flags: chart axis labels or batched table/list helpers (no‑op safe)

Loading the native library

The cgo bindings link against -lratatui_ffi and rely on your platform’s loader to resolve it. Common setups:

  • Add the build directory to loader paths (LD_LIBRARY_PATH/DYLD_LIBRARY_PATH/PATH)
  • Copy the library next to your binary for deployment
  • For auditing only, pass --lib to the audit tool (or RATATUI_FFI_LIB)

API overview

Terminal

  • Lifecycle: NewTerminal(), (*Terminal).Free()
  • Draw: DrawParagraphIn, DrawFrame([]DrawCmd)
  • Modes: EnableRaw/DisableRaw, EnterAlt/LeaveAlt, ShowCursor
  • Size/Viewport: Size, Set/GetViewportArea

Widgets

  • Paragraph/List/Table (+state), Tabs, Gauge/LineGauge, BarChart/Sparkline, Chart, Clear, RatatuiLogo, Canvas, optional Scrollbar
  • Spans‑based block titles available across widgets; Arena variants avoid per‑call allocations

Events

  • NextEvent(timeoutMs) (Event, ok) — kinds: Key/Resize/Mouse
  • Injectors for tests: InjectKey/InjectResize/InjectMouse

Headless snapshots

  • Frame text, extended styles, or structured cells
  • Per‑widget headless helpers (e.g., RenderParagraph, RenderChart)

Layout DSL

  • Px, Percent, MinPx, RatioOf, EqualN, and SplitEx2/Percentages
  • Compose 1..N constraints for any split; combine rows/columns by nesting

Go ergonomics

  • Arena (per‑frame scratchpad) to batch span allocations and free once per frame
  • FrameBuilder to construct []DrawCmd over a preallocated buffer
  • SmallSpans (stack‑backed) for common small spans without heap
  • Session helpers: WithTerminal, WithSession (raw/alt/clear), scoped WithCursorHidden, WithViewport
  • Loop (tick‑based) and Keymap (static dispatch) for snappy loops

See also:

  • docs/ergonomics.md — Arena, FrameBuilder, SmallSpans patterns
  • docs/layout-dsl.md — composing complex splits with DSL
  • docs/session-loop-keymap.md — sessions, loops, keymaps
  • docs/feature-bits.md — optional features and gating

Enums (quick reference)

  • Align: Left=0, Center=1, Right=2
  • Direction (layout): Vertical=0, Horizontal=1
  • Borders (bitmask): LEFT=1, RIGHT=2, TOP=4, BOTTOM=8 (combine with |)
  • BorderType: Plain=0, Thick=1, Double=2

— The Ratatui Bindings Team

Contribute

We welcome sharp eyes and strong opinions. If something feels off, open an issue and tell us exactly why — then tell us how you’d improve it.

  • File issues with specifics:

    • What’s not good yet and why (be concrete).
    • Repro steps, expected vs. actual behavior, terminal output.
    • Your improvement proposal: API shape, UX copy, code structure, or examples.
    • Scope and priority if you can (quick win vs. deeper refactor).
  • Agents process issues. You, the human, are our master QA:

    • Run the demos/examples (use the README instructions) and report results.
    • Include OS, terminal, Go version, and how you set up the native library.
    • Attach screenshots or short recordings when visuals matter.
  • Documentation and structure need a human touch:

    • Propose clarity edits to README/docs, better example layout, or naming tweaks.
    • PRs with concrete wording and structure improvements are highly valued.
  • PR expectations (keep it simple):

    • Tight scope, consistent style, no drive‑by unrelated changes.
    • If you run demos locally, remember the native lib and (optionally) -tags ffi.
    • CI builds library packages by default; examples run in the ffi job.

We’d rather get high‑signal issues/PRs than perfection. Tell us what hurts and how you’d fix it — our agents will do the heavy lifting.

Phase 2: Go ergonomics roadmap (zero‑alloc friendly)

  • FrameArena: per‑frame scratchpad that builds C spans once and frees at frame end.
  • FrameBuilder: stack‑friendly draw command builder with preallocated buffer.
  • SmallSpans: stack‑backed span builders (first N spans on stack, no heap).
  • Session helpers: WithTerminal(func(*Terminal){}) for raw/alt/cursor scoping.
  • Loop helper: tiny driver with tick budget and cooperative yielding.
  • Keymap: table‑driven handler dispatch without per‑loop allocations.
  • Scoped cursor/viewport setters using defer to restore state.

These APIs are opt‑in and keep performance front‑and‑center: no hidden goroutines, no unnecessary allocations, and clear lifetimes. See examples/interactive and upcoming examples/ergonomics for patterns.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Packages

No packages published