729921e16e
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
55 lines
1.7 KiB
Go
55 lines
1.7 KiB
Go
package tui
|
||
|
||
import (
|
||
"strings"
|
||
|
||
"github.com/hinshun/vt10x"
|
||
)
|
||
|
||
// VTRender emulates a terminal of size cols×rows, feeds raw into it,
|
||
// and returns the resulting screen as plain text preserving the visual layout.
|
||
//
|
||
// Unlike strip_ansi which removes escape sequences from sequential output,
|
||
// VTRender correctly handles TUIs that use absolute cursor positioning
|
||
// (ESC[row;colH, ESC[colG, etc.) by maintaining a 2D grid and reconstructing
|
||
// real spaces between columns.
|
||
//
|
||
// Defaults: rows<=0 → 40, cols<=0 → 120.
|
||
// Trailing spaces on each line are trimmed. Trailing empty lines are removed.
|
||
func VTRender(raw string, rows, cols int) string {
|
||
if rows <= 0 {
|
||
rows = 40
|
||
}
|
||
if cols <= 0 {
|
||
cols = 120
|
||
}
|
||
|
||
// Create a fresh terminal emulator for each call — no shared state.
|
||
term := vt10x.New(vt10x.WithSize(cols, rows))
|
||
term.Write([]byte(raw)) //nolint:errcheck // Write on vt10x never returns a meaningful error
|
||
|
||
// String() returns all rows joined by '\n', one row per terminal line.
|
||
// Each row is exactly `cols` runes wide (padded with NUL/space for empty cells).
|
||
raw = term.String()
|
||
|
||
lines := strings.Split(raw, "\n")
|
||
|
||
// Trim trailing spaces from every line (cells that were never written
|
||
// contain NUL '\x00' in some versions, so we trim both NUL and space).
|
||
for i, line := range lines {
|
||
// Replace NUL characters (unwritten cells) with spaces first.
|
||
line = strings.ReplaceAll(line, "\x00", " ")
|
||
lines[i] = strings.TrimRight(line, " ")
|
||
}
|
||
|
||
// Remove trailing empty lines — the TUI probably only used the top portion
|
||
// of the grid. Keep intermediate empty lines (real visual separators).
|
||
last := len(lines) - 1
|
||
for last >= 0 && lines[last] == "" {
|
||
last--
|
||
}
|
||
lines = lines[:last+1]
|
||
|
||
return strings.Join(lines, "\n")
|
||
}
|