v0.3.0 write output on its own goroutine, blocked terminal report

This commit is contained in:
lixen committed 2026-10-14 20:38:40 -04:00
1 parent c657af606d
commit 0919d2a6b1
7 files changed
+288 -78

No files matched your search

+15 -20
View File
@@ -1,20 +1,22 @@
package terminal
import (
"bufio"
"bytes"
"unicode"
"unicode/utf8"
"github.com/lixenwraith/color"
)
// outputBuffer manages double-buffered terminal output with diffing
// outputBuffer renders double-buffered terminal output with diffing. It only
// encodes: what an operation renders collects in buf, and termImpl hands it to
// the goroutine that writes it.
type outputBuffer struct {
front []Cell
width int
height int
colorMode ColorMode
writer *bufio.Writer
buf bytes.Buffer
cursorX int
cursorY int
@@ -27,7 +29,7 @@ type outputBuffer struct {
lastValid bool
}
// writerAdapter adapts Backend to io.Writer for bufio
// writerAdapter adapts Backend to io.Writer
type writerAdapter struct {
b Backend
}
@@ -40,13 +42,8 @@ func (wa writerAdapter) Write(p []byte) (int, error) {
return len(p), nil
}
func newOutputBuffer(backend Backend, colorMode ColorMode) *outputBuffer {
// Use 128KB buffer for minimal calls to backend
adapter := writerAdapter{b: backend}
return &outputBuffer{
writer: bufio.NewWriterSize(adapter, 131072),
colorMode: colorMode,
}
func newOutputBuffer(colorMode ColorMode) *outputBuffer {
return &outputBuffer{colorMode: colorMode}
}
func (o *outputBuffer) resize(width, height int) {
@@ -74,7 +71,7 @@ func cellEqual(a, b Cell) bool {
a.Attrs == b.Attrs
}
// flush writes the back buffer to terminal, diffing against front buffer
// flush renders the back buffer into buf, diffing against front buffer
func (o *outputBuffer) flush(cells []Cell, width, height int) {
if width != o.width || height != o.height {
o.resize(width, height)
@@ -85,7 +82,7 @@ func (o *outputBuffer) flush(cells []Cell, width, height int) {
return
}
w := o.writer
w := &o.buf
for y := 0; y < height; y++ {
rowStart := y * width
@@ -178,7 +175,6 @@ func (o *outputBuffer) flush(cells []Cell, width, height int) {
w.Write(csiSGR0)
o.lastValid = false
w.Flush()
}
// oneColumn is r as a cell draws it: one glyph in one column, where the
@@ -292,7 +288,7 @@ func digitCount(n int) int {
}
// moveCursorTo positions cursor using most efficient method
func (o *outputBuffer) moveCursorTo(w *bufio.Writer, x, y int) {
func (o *outputBuffer) moveCursorTo(w *bytes.Buffer, x, y int) {
if o.cursorValid && o.cursorX == x && o.cursorY == y {
return
}
@@ -319,7 +315,7 @@ func (o *outputBuffer) moveCursorTo(w *bufio.Writer, x, y int) {
}
// writeStyleCoalesced emits a single combined SGR sequence when style changes
func (o *outputBuffer) writeStyleCoalesced(w *bufio.Writer, fg, bg color.RGB, attr Attr) {
func (o *outputBuffer) writeStyleCoalesced(w *bytes.Buffer, fg, bg color.RGB, attr Attr) {
if o.colorMode == ColorModeNone {
fg, bg, attr = color.RGB{}, color.RGB{}, attr&AttrStyle
}
@@ -372,7 +368,7 @@ var attrCodes = [...]struct {
// writeColor writes one color's SGR parameters, after a ';' when sep, for
// base 30 (foreground) or 40 (background): the terminal's own, a palette
// index, or RGB, as the color mode allows. ColorModeNone writes nothing.
func (o *outputBuffer) writeColor(w *bufio.Writer, c color.RGB, palette, deflt bool, base int, sep bool) {
func (o *outputBuffer) writeColor(w *bytes.Buffer, c color.RGB, palette, deflt bool, base int, sep bool) {
if o.colorMode == ColorModeNone {
return
}
@@ -418,10 +414,10 @@ func (o *outputBuffer) forceFullRedraw() {
o.cursorValid = false
}
// clear writes a clear screen with specified background, attr's
// clear renders a clear screen with specified background, attr's
// AttrBgDefault or AttrBg256 saying how to read it
func (o *outputBuffer) clear(bg color.RGB, attr Attr) {
w := o.writer
w := &o.buf
w.Write(csiSGR0)
w.Write(csi)
o.writeColor(w, bg, attr&AttrBg256 != 0, attr&AttrBgDefault != 0, 40, false)
@@ -430,7 +426,6 @@ func (o *outputBuffer) clear(bg color.RGB, attr Attr) {
o.lastValid = false
o.cursorValid = false
w.Flush()
for i := range o.front {
o.front[i] = Cell{Rune: ' ', Bg: bg, Attrs: attr & AttrBgColor}