okami.mom/ultraviolet

git clone https://git.nkp.pet/okami.mom/ultraviolet

nekomimi.petfix(input): keep control strings whole when they span reads7bfbaab

main
5.6 KiB170 linesraw

Ultraviolet

[!NOTE] This is a fork of charmbracelet/ultraviolet used by albedo. main is upstream (the upstream branch) plus one patch: the input reader keeps OSC, DCS and other ST-terminated replies whole when a read ends between the ESC and backslash of the terminator, and holds a partial OSC 5522 clipboard reply up to 5 seconds instead of flushing it at the 50 ms escape timeout. Use it with replace github.com/charmbracelet/ultraviolet => tangled.org/okami.mom/ultraviolet <version>.

<img width="400" alt="Charm Ultraviolet" src="https://github.com/user-attachments/assets/3484e4b0-3741-4e8c-bebf-9ea51f5bb49c" /> <p> <a href="https://pkg.go.dev/github.com/charmbracelet/ultraviolet?tab=doc"><img src="https://godoc.org/github.com/charmbracelet/ultraviolet?status.svg" alt="GoDoc"></a> <a href="https://github.com/charmbracelet/ultraviolet/actions"><img src="https://github.com/charmbracelet/ultraviolet/actions/workflows/build.yml/badge.svg" alt="Build Status"></a> </p>

Ultraviolet is a set of primitives for building terminal user interfaces in Go. It provides cell-based rendering, cross-platform input handling, and a diffing renderer inspired by ncurses—without the need for terminfo or termcap databases.

Ultraviolet powers Bubble Tea v2 and Lip Gloss v2. It replaces the ad-hoc terminal primitives from earlier versions with a cohesive, imperative API that can also be used standalone.

Install

go get github.com/charmbracelet/ultraviolet@latest

Quick Start

package main

import (
	"log"

	uv "github.com/charmbracelet/ultraviolet"
	"github.com/charmbracelet/ultraviolet/screen"
)

func main() {
	t := uv.DefaultTerminal()
	scr := t.Screen()

	scr.EnterAltScreen()

	if err := t.Start(); err != nil {
		log.Fatalf("failed to start terminal: %v", err)
	}
	defer t.Stop()

	ctx := screen.NewContext(scr)
	text := "Hello, World!"
	textWidth := scr.StringWidth(text)

	display := func() {
		screen.Clear(scr)
		bounds := scr.Bounds()
		x := (bounds.Dx() - textWidth) / 2
		y := bounds.Dy() / 2
		ctx.DrawString(text, x, y)
		scr.Render()
		scr.Flush()
	}

	for ev := range t.Events() {
		switch ev := ev.(type) {
		case uv.WindowSizeEvent:
			scr.Resize(ev.Width, ev.Height)
			display()
		case uv.KeyPressEvent:
			if ev.MatchString("q", "ctrl+c") {
				return
			}
		}
	}
}

Architecture

Ultraviolet is organized as a set of layered primitives:

  • Terminal — manages the application lifecycle: raw mode, input event loop, start/stop. Create one with DefaultTerminal() or NewTerminal(console, opts).

  • TerminalScreen — the screen state manager. Handles rendering, alternate screen buffer, cursor, mouse modes, keyboard enhancements, bracketed paste, window title, and more. Access it via terminal.Screen().

  • Screen — a minimal interface (Bounds, CellAt, SetCell, WidthMethod) implemented by TerminalScreen, Buffer, Window, and ScreenBuffer. Write code against Screen to stay decoupled from the terminal.

  • Buffer / Window — off-screen cell buffers. Buffer is a flat grid of cells. Window adds parent/child relationships and shared-buffer views. Both implement Screen and Drawable.

  • screen package — drawing helpers that operate on any Screen: a Context for styled text rendering (Print, DrawString, etc.) and utility functions like Clear, Fill, Clone.

  • layout package — a constraint-based layout solver built on the Cassowary algorithm. Partition screen space with Len, Min, Max, Percent, Ratio, and Fill constraints.

Features

  • Cell-based diffing renderer — only redraws what changed. Optimizes cursor movement, uses ECH/REP/ICH/DCH when available, and supports scroll optimizations. Minimal bandwidth, critical for SSH.

  • Universal input — unified keyboard and mouse event handling across platforms. Supports legacy encodings, Kitty keyboard protocol, SGR mouse, and Windows Console input.

  • Inline and fullscreen — works in both alternate screen (fullscreen) and inline mode. Inline TUIs preserve terminal context and scrollback.

  • Cross-platform — first-class support for Unix (termios + ANSI) and Windows (Console API). Consistent behavior across terminal emulators.

  • Suspend/resume — Stop() and Start() can be called repeatedly for suspend/resume cycles, shelling out to editors, or process suspension via uv.Suspend().

Examples

See the examples/ directory for core examples and examples/advanced/ for more complex demos.

Tutorial

See TUTORIAL.md for a step-by-step guide to building your first Ultraviolet application.

[!NOTE] Ultraviolet is in active development. The API may change.

Feedback

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

License

MIT


Part of Charm.

<a href="https://charm.sh/"><img alt="The Charm logo" width="400" src="https://stuff.charm.sh/charm-banner-next.jpg" /></a>

Charm热爱开源 • Charm loves open source • نحنُ نحب المصادر المفتوحة

1# Ultraviolet
2
3> [!NOTE]
4> This is a fork of [charmbracelet/ultraviolet](https://github.com/charmbracelet/ultraviolet)
5> used by [albedo](https://tangled.org/okami.mom/albedo). `main` is upstream
6> (the `upstream` branch) plus one patch: the input reader keeps OSC, DCS and
7> other ST-terminated replies whole when a read ends between the ESC and
8> backslash of the terminator, and holds a partial OSC 5522 clipboard reply up
9> to 5 seconds instead of flushing it at the 50 ms escape timeout. Use it with
10> `replace github.com/charmbracelet/ultraviolet => tangled.org/okami.mom/ultraviolet <version>`.
11
12<img width="400" alt="Charm Ultraviolet" src="https://github.com/user-attachments/assets/3484e4b0-3741-4e8c-bebf-9ea51f5bb49c" />
13
14<p>
15    <a href="https://pkg.go.dev/github.com/charmbracelet/ultraviolet?tab=doc"><img src="https://godoc.org/github.com/charmbracelet/ultraviolet?status.svg" alt="GoDoc"></a>
16    <a href="https://github.com/charmbracelet/ultraviolet/actions"><img src="https://github.com/charmbracelet/ultraviolet/actions/workflows/build.yml/badge.svg" alt="Build Status"></a>
17</p>
18
19Ultraviolet is a set of primitives for building terminal user interfaces in Go.
20It provides cell-based rendering, cross-platform input handling, and a diffing
21renderer inspired by [ncurses](https://invisible-island.net/ncurses/)—without
22the need for `terminfo` or `termcap` databases.
23
24Ultraviolet powers [Bubble Tea v2][bbt] and [Lip Gloss v2][lg]. It replaces the
25ad-hoc terminal primitives from earlier versions with a cohesive, imperative API
26that can also be used standalone.
27
28[bbt]: https://github.com/charmbracelet/bubbletea
29[lg]: https://github.com/charmbracelet/lipgloss
30
31## Install
32
33```bash
34go get github.com/charmbracelet/ultraviolet@latest
35```
36
37## Quick Start
38
39```go
40package main
41
42import (
43	"log"
44
45	uv "github.com/charmbracelet/ultraviolet"
46	"github.com/charmbracelet/ultraviolet/screen"
47)
48
49func main() {
50	t := uv.DefaultTerminal()
51	scr := t.Screen()
52
53	scr.EnterAltScreen()
54
55	if err := t.Start(); err != nil {
56		log.Fatalf("failed to start terminal: %v", err)
57	}
58	defer t.Stop()
59
60	ctx := screen.NewContext(scr)
61	text := "Hello, World!"
62	textWidth := scr.StringWidth(text)
63
64	display := func() {
65		screen.Clear(scr)
66		bounds := scr.Bounds()
67		x := (bounds.Dx() - textWidth) / 2
68		y := bounds.Dy() / 2
69		ctx.DrawString(text, x, y)
70		scr.Render()
71		scr.Flush()
72	}
73
74	for ev := range t.Events() {
75		switch ev := ev.(type) {
76		case uv.WindowSizeEvent:
77			scr.Resize(ev.Width, ev.Height)
78			display()
79		case uv.KeyPressEvent:
80			if ev.MatchString("q", "ctrl+c") {
81				return
82			}
83		}
84	}
85}
86```
87
88## Architecture
89
90Ultraviolet is organized as a set of layered primitives:
91
92- **Terminal** — manages the application lifecycle: raw mode, input event loop,
93  start/stop. Create one with `DefaultTerminal()` or `NewTerminal(console, opts)`.
94
95- **TerminalScreen** — the screen state manager. Handles rendering, alternate
96  screen buffer, cursor, mouse modes, keyboard enhancements, bracketed paste,
97  window title, and more. Access it via `terminal.Screen()`.
98
99- **Screen** — a minimal interface (`Bounds`, `CellAt`, `SetCell`,
100  `WidthMethod`) implemented by `TerminalScreen`, `Buffer`, `Window`, and
101  `ScreenBuffer`. Write code against `Screen` to stay decoupled from the
102  terminal.
103
104- **Buffer / Window** — off-screen cell buffers. `Buffer` is a flat grid of
105  cells. `Window` adds parent/child relationships and shared-buffer views.
106  Both implement `Screen` and `Drawable`.
107
108- **screen package** — drawing helpers that operate on any `Screen`: a
109  `Context` for styled text rendering (`Print`, `DrawString`, etc.) and
110  utility functions like `Clear`, `Fill`, `Clone`.
111
112- **layout package** — a constraint-based layout solver built on the
113  [Cassowary algorithm][casso]. Partition screen space with `Len`, `Min`,
114  `Max`, `Percent`, `Ratio`, and `Fill` constraints.
115
116[casso]: https://en.wikipedia.org/wiki/Cassowary_(software)
117
118## Features
119
120- **Cell-based diffing renderer** — only redraws what changed. Optimizes
121  cursor movement, uses ECH/REP/ICH/DCH when available, and supports scroll
122  optimizations. Minimal bandwidth, critical for SSH.
123
124- **Universal input** — unified keyboard and mouse event handling across
125  platforms. Supports legacy encodings, Kitty keyboard protocol, SGR mouse,
126  and Windows Console input.
127
128- **Inline and fullscreen** — works in both alternate screen (fullscreen) and
129  inline mode. Inline TUIs preserve terminal context and scrollback.
130
131- **Cross-platform** — first-class support for Unix (termios + ANSI) and
132  Windows (Console API). Consistent behavior across terminal emulators.
133
134- **Suspend/resume** — `Stop()` and `Start()` can be called repeatedly for
135  suspend/resume cycles, shelling out to editors, or process suspension
136  via `uv.Suspend()`.
137
138## Examples
139
140See the [`examples/`](./examples/) directory for core examples and
141[`examples/advanced/`](./examples/advanced/) for more complex demos.
142
143## Tutorial
144
145See [TUTORIAL.md](./TUTORIAL.md) for a step-by-step guide to building your
146first Ultraviolet application.
147
148> [!NOTE]
149> Ultraviolet is in active development. The API may change.
150
151## Feedback
152
153We'd love to hear your thoughts on this project. Feel free to drop us a note!
154
155- [Twitter](https://twitter.com/charmcli)
156- [Discord](https://charm.land/discord)
157- [Slack](https://charm.land/slack)
158- [The Fediverse](https://mastodon.social/@charmcli)
159
160## License
161
162[MIT](./LICENSE)
163
164---
165
166Part of [Charm](https://charm.land).
167
168<a href="https://charm.sh/"><img alt="The Charm logo" width="400" src="https://stuff.charm.sh/charm-banner-next.jpg" /></a>
169
170Charm热爱开源 • Charm loves open source • نحنُ نحب المصادر المفتوحة