From 5deb2f642548a29446aabc23b4f47d238509e85b Mon Sep 17 00:00:00 2001 From: kami Date: Thu, 2 Jul 2026 13:26:42 +0400 Subject: [PATCH] fix(tui): fill the frame background so the terminal backdrop can't bleed through MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The main render path never applied the Screen backdrop, so any sub-view that left a line short or a row empty showed the transparent terminal background. Pad every frame to full width×height with the theme backdrop before display; content stays top-left anchored so caret coords are unaffected. --- apps/tui-go/internal/app/view.go | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/apps/tui-go/internal/app/view.go b/apps/tui-go/internal/app/view.go index 96b46f64..381399d9 100644 --- a/apps/tui-go/internal/app/view.go +++ b/apps/tui-go/internal/app/view.go @@ -41,14 +41,38 @@ const cursorMarker = "" // bubbletea v2 the View carries terminal state, so renderRaw() builds the string // and View() resolves the caret to a real blinking cursor + sets the window title. func (m Model) View() tea.View { - content, cur := splitCursor(m.renderRaw(), " ") + content, cur := splitCursor(m.fillFrame(m.renderRaw()), " ") return tea.View{Content: content, AltScreen: true, Cursor: cur, WindowTitle: m.windowTitle()} } +// fillFrame guarantees every cell of the width×height frame carries the theme backdrop, so a +// sub-view that leaves a line short or a row empty shows the theme background rather than the +// terminal-transparent backdrop bleeding through. Pads each line to full width and appends any +// missing bottom rows; content stays anchored top-left so caret coordinates are unaffected. +func (m Model) fillFrame(s string) string { + if m.width <= 0 || m.height <= 0 { + return s + } + pad := m.theme.Screen + lines := strings.Split(s, "\n") + out := make([]string, 0, m.height) + for i := 0; i < m.height; i++ { + ln := "" + if i < len(lines) { + ln = lines[i] + } + if gap := m.width - ansi.StringWidth(ln); gap > 0 { + ln += pad.Render(strings.Repeat(" ", gap)) + } + out = append(out, ln) + } + return strings.Join(out, "\n") +} + // render returns the frame as a plain string with the caret drawn as the static // "▏" glyph — for the preview tool and golden tests, which have no live cursor. func (m Model) render() string { - content, _ := splitCursor(m.renderRaw(), "▏") + content, _ := splitCursor(m.fillFrame(m.renderRaw()), "▏") return content }