From d89e3317529f7c43b54f557a61cdeb321e4bd880 Mon Sep 17 00:00:00 2001 From: Lixen Wraith Date: Fri, 16 Oct 2026 21:43:18 -0400 Subject: [PATCH] v0.4.0 terminal over caller's backend --- README.md | 5 +++++ terminal.go | 8 ++++++++ terminal_test.go | 15 +++++++++++++++ 3 files changed, 28 insertions(+) diff --git a/README.md b/README.md index 3acdee3..58407bd 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,11 @@ consoles with VT processing, and browsers via xterm.js (WASM builds). Shared code carries no build tags: cell diffing, ANSI generation, escape parsing. Platform specifics are isolated in the `Backend` implementations. +`NewWithBackend(b, mode)` builds a Terminal over a `Backend` of the caller's +own: a pipe, an in-process emulator or a test standing in for the tty. It +behaves as `New`'s Terminal does, the writer goroutine included; `New` is +`NewWithBackend` over the platform's backend and the detected color mode. + ### Rendering pipeline The application owns a flat `[]Cell` buffer (row-major, `cells[y*width+x]`) and diff --git a/terminal.go b/terminal.go index 59b8974..c10b24d 100644 --- a/terminal.go +++ b/terminal.go @@ -156,6 +156,14 @@ func New(colorMode ...ColorMode) Terminal { c = ColorModeNone } + return NewWithBackend(b, c) +} + +// NewWithBackend creates a Terminal over b in color mode c, for a pipe, an +// in-process emulator or a test standing in for the tty. b must not be nil; +// the Terminal calls its Init on Init and its Fini on Fini, and writes to it +// on its own goroutine as New's does +func NewWithBackend(b Backend, c ColorMode) Terminal { return newTerm(b, c) } diff --git a/terminal_test.go b/terminal_test.go index 8341030..6e83285 100644 --- a/terminal_test.go +++ b/terminal_test.go @@ -376,3 +376,18 @@ func waitFor(t *testing.T, what string, ok func() bool) { time.Sleep(time.Millisecond) } } + +// A Terminal built over a caller's backend draws a flushed frame to it +func TestNewWithBackendFlushesToTheBackend(t *testing.T) { + f := &fakeBackend{} + term := NewWithBackend(f, ColorMode256) + if err := term.Init(); err != nil { + t.Fatal(err) + } + defer term.Fini() + if term.ColorMode() != ColorMode256 { + t.Fatalf("color mode %v", term.ColorMode()) + } + term.Flush([]Cell{{Rune: 'x'}}, 1, 1) + waitFor(t, "the frame to reach the backend", func() bool { return strings.Contains(f.written(), "x") }) +}