Skip to content

Repository files navigation

Rusty Ultraviolet
crates.io Build Status coverage

Rusty Ultraviolet (rusty-ultraviolet)

Rusty Ultraviolet is a complete, from-scratch Rust port of Ultraviolet, Charmbracelet's set of primitives for manipulating terminal emulators โ€” cell-based screen buffers, a diffing terminal renderer, and cross-platform input decoding. It tracks upstream on a rolling basis under the family's porting policies: versions mirror upstream exactly, never ahead or behind, with a hard goal of 1:1 behavioural, visual and license parity, favouring fidelity to upstream semantics over Rust-native rewrites.

It's part of the Rusty port family of the Bubble Tea ecosystem and builds on rusty-x-ansi (ANSI primitives) and rusty-colorprofile โ€” it powers rusty-bubbletea, rusty-lipgloss and rusty-bubbles.

About Ultraviolet

Ultraviolet is a set of primitives for manipulating terminal emulators, with a focus on terminal user interfaces (TUIs). It provides a set of tools and abstractions for interaction that can handle user input and display dynamic, cell-based content. It's the product of many years of research, development, collaboration and ingenuity.

Ultraviolet is not a framework by design, however it can be used standalone to create powerful terminal applications. It's in use in production and powers critical portions of Bubble Tea v2 and Lip Gloss v2, and was instrumental in the development of Crush.

Caution

This project currently exists to serve internal use cases. API stability is a goal, but expect no stability guarantees as of now.

Installation

cargo add rusty-ultraviolet

Ultraviolet provides cell-based screen buffers, a diffing terminal renderer and cross-platform input decoding for building terminal user interfaces.

Quick start

A minimal full-screen application: enter the alternate screen, draw a centered message, and exit on any key press.

use rusty_ultraviolet::decoder::DecodedEvent;
use rusty_ultraviolet::screen::clear;
use rusty_ultraviolet::screen_context::new_context;
use rusty_ultraviolet::terminal::default_terminal;
use rusty_ultraviolet::terminal_screen::TerminalScreen;

fn draw(scr: &mut TerminalScreen) {
    clear(scr);
    let bounds = scr.bounds();
    let w = scr.string_width("Hello, World!");
    let x = (bounds.dx() as i64 - w as i64) / 2;
    let y = bounds.dy() as i64 / 2;
    new_context(Box::new(&mut *scr)).draw_string("Hello, World!", x, y);
    scr.render();
    let _ = scr.flush();
}

fn main() {
    let mut t = default_terminal();
    t.screen().enter_alt_screen();
    if let Err(e) = t.start() {
        eprintln!("error: {e}");
        std::process::exit(1);
    }

    draw(t.screen());

    loop {
        match t.events().recv() {
            Ok(DecodedEvent::KeyPress(_)) => break,
            Ok(_) => {}
            Err(_) => break,
        }
    }

    draw(t.screen()); // last render before exit
    let _ = t.stop();
}

For a longer walkthrough โ€” window resize handling, the inline (non-alternate) screen, mouse events, and drawing with Drawable components โ€” see TUTORIAL.md, and the examples directory for complete programs.

Features

Ultraviolet is built with several core features in mind to make terminal application development easy and performant:

๐Ÿ‘บ The Cursed Renderer

The cell-based rendering modelโ€”called The Cursed Renderโ€”was inspired by the infamous ncurses library, which has been an essential part of terminal applications for decades. Ultraviolet takes this concept and modernizes it for the Go programming language, providing a more ergonomic and efficient way to work with terminal cells without the need for archaic technologies like terminfo or termcap databases.

Unlike ncurses, it supports both full-window and inline use-cases as we see inline TUIs as important in maintaining user context and flow.

๐ŸŽ๏ธ High Speeds and Low Bandwidth

The built-in terminal renderer efficiently handles content updates by utilizing a powerful cell-based diffing algorithm that minimizes the amount of data written to the terminal using various ANSI escape sequences to accomplish this. This allows applications to update only the parts of the terminal that have changed, significantly improving performance and responsiveness.

In practical terms, Ultraviolet optimizes for fast redraws that use minimal data transfer. This is very important locally and critically important over the network (for example, via SSH).

๐Ÿ’ฌ Universal Input

Input handling in terminals can be complex, especially when dealing with multiple input sources, different platforms, and ancient terminal baggage. Ultraviolet simplifies this by providing a unified interface for handling user input, allowing developers to focus on building their applications without getting bogged down in the intricacies of terminal input handling.

๐ŸŽฎ Cross-Platform Compatibility

Ultraviolet is designed to work seamlessly across different platforms and terminal emulators. It abstracts away the differences in terminal capabilities and provides a consistent API for developers to work with, ensuring that applications built with Ultraviolet will run smoothly on various systems.

On Windows, it uses the Windows Console API to provide a consistent experience, while on Unix-like systems, it relies on the standard Termios API along with ANSI escape sequences to manipulate the terminal.

In short: Ultraviolet provides first-class support for both Unix and Windows-based systems.

๐Ÿงฉ Extensible Architecture

Ultraviolet is built with extensibility in mind, providing a solid API that can be embedded into other applications or used as a foundation for building custom terminal user interfaces. It allows developers to create their own components, styles, and behaviors, making it a versatile tool for building terminal applications.

FAQ

๐Ÿˆ What about other Charm libraries?

Ultraviolet is not a replacement for existing libraries like Bubble Tea or Lip Gloss. Instead, it serves as a foundation for the latest versions of both of these libraries and others like them, providing the underlying primitives and abstractions needed to build terminal user interfaces applications and frameworks.

๐Ÿ› How is it different from Bubble Tea?

Ultraviolet is a lower-level library that focuses on the core primitives of terminal manipulation, rendering, and input handling. It provides the building blocks for creating terminal applications, while Bubble Tea is a higher-level framework that builds on top of Ultraviolet to provide a more structured and opinionated way to build terminal user interfaces.

๐Ÿ’‹ Is it a replacement for Lip Gloss?

Simply put, no. Ultraviolet is not a replacement for Lip Gloss. Instead, it provides the underlying rendering capabilities that Lip Gloss can use to create styled terminal content. Lip Gloss is a higher-level library that builds on top of Ultraviolet by utilizing the cell-based rendering model to provide a simplified and ergonomic way to create styled terminal content and composition of terminal user interfaces.

โœ๏ธ Tutorial

You can find a simple tutorial on how to create a UV application that displays "Hello, World!" on the screen in the TUTORIAL.md file.

Whatcha think?

Weโ€™d love to hear your thoughts on this project. Feel free to drop us a note!

License

MIT

About

Clean room, 1:1 port of charmbracelet's ๐Ÿ•ถ ultraviolet to ๐Ÿฆ€ Rust, including dependencies. Version and license matched to upstream.

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages