extui

Crates.ioextui
lib.rsextui
version0.1.2
created_at2026-01-18 18:07:39.299492+00
updated_at2026-01-22 12:26:40.941899+00
descriptionAn experimental fast compiling serialization and deserialization libary for JSON like formats.
homepage
repositoryhttps://github.com/exrok/extui
max_upload_size
id2052772
size244,618
Thomas Dagenais (exrok)

documentation

README

extui: Exrok's Minimal Unix TUI Crate

extui provides powerful primitives and low-level access for terminal interfaces tightly integrated together in a single crate.

Crates.io Docs.rs License

extui was largly made for my own needs and is used some of my other projects such as:

  • devsm: A development focused service manager
  • extask: My todo list manager

Example

use extui::event::polling::GlobalWakerConfig;
use extui::event::{self, Event, Events, KeyCode, KeyEvent};
use extui::{Color, DoubleBuffer, Style, Terminal, TerminalFlags};

fn main() -> std::io::Result<()> {
    extui::event::polling::initialize_global_waker(GlobalWakerConfig {
        resize: true,
        ..Default::default()
    })?;

    let mut term = Terminal::open(
        TerminalFlags::RAW_MODE | TerminalFlags::ALT_SCREEN | TerminalFlags::HIDE_CURSOR,
    )?;

    let (w, h) = term.size()?;
    let mut buf = DoubleBuffer::new(w, h);
    let mut events = Events::default();
    let stdin = std::io::stdin();
    let mut last_key = None::<KeyEvent>;

    loop {
        // Render
        buf.rect().with(Color::Blue1.as_bg()).fill(&mut buf);
        let mut rect = buf.rect();
        rect.take_top(1)
            .with(Style::DEFAULT)
            .text(&mut buf, "Press 'q' to quit");

        if let Some(key) = last_key {
            rect.take_top(1)
                .with(Color::Black.with_fg(Color::White))
                .text(&mut buf, "Last Key Pressed: ")
                .fmt(&mut buf, format_args!("{key:?}"));
        }

        buf.render(&mut term);

        // Poll for events
        if event::poll(&stdin, None)?.is_readable() {
            events.read_from(&stdin)?;
        }
        while let Some(ev) = events.next(term.is_raw()) {
            match ev {
                Event::FocusGained => {}
                Event::FocusLost => {}
                Event::Key(key) => {
                    if key.code == KeyCode::Char('q') {
                        return Ok(());
                    }
                    last_key = Some(key);
                }
                Event::Mouse(_mouse_event) => {}
                Event::Resized => {
                    let (new_w, new_h) = term.size()?;
                    buf.resize(new_w, new_h);
                }
            }
        }
    }
}

Deliberate Limitations

extui intentionally omits certain features. This results in simpler interfaces and better performance:

Limitation Rationale
8-bit color only No 24-bit true color. The 256-color palette covers most use cases with simpler encoding.
4-byte grapheme limit Characters exceeding 4 bytes are truncated. Enables fixed-size Cell storage.
Unix only No Windows support. Allows direct POSIX APIs without abstraction overhead.

Inspirations

extui draws inspiration from excellent crates in the Rust terminal ecosystem while pursuing different tradeoffs.

ratatouille

The lower-level buffer API designs are influenced by ratatouille, with the following differences:

  • New diffing algorithm: Generates VT rendering bytes directly in a greedy single-pass fashion, rather than computing diffs separately.
  • Smaller diffs: Smarter about style transitions and leverages advanced VT escape sequences when possible, such as clearing whole lines to fill spaces.
  • Compact Cell storage: The core Cell abstraction is 8 bytes by default, packed into a single u64 for trivial diffing and cache-friendly iteration.

crossterm

Terminal input events and parsing are inspired by crossterm. extui improves on this foundation:

  • Compact KeyEvent: KeyEvent is only 8 bytes, fitting inside a single CPU register.
  • Linear parsing: The event parser was optimized from O(n²) to O(n).
Commit count: 3

cargo fmt