From 3d7f80eebbe72adafce52bc6d14899a6670dec86 Mon Sep 17 00:00:00 2001 From: patriceckhart Date: Fri, 22 May 2026 18:53:23 +0200 Subject: [PATCH] Add spacing around dialog frames --- internal/agent/modes/dialog_frame.go | 37 ++++++++++++++++++++++++++++ internal/agent/modes/help.go | 4 +-- internal/agent/modes/interactive.go | 3 +++ 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/internal/agent/modes/dialog_frame.go b/internal/agent/modes/dialog_frame.go index 8e41ea5..d12a1f8 100644 --- a/internal/agent/modes/dialog_frame.go +++ b/internal/agent/modes/dialog_frame.go @@ -33,6 +33,43 @@ func frameRule(th tui.Theme, width int) string { return th.FG256(th.Muted, strings.Repeat("─", width)) } +// padDialogFrame inserts breathing room between the shared dialog frame +// chrome and its body while keeping frameHeader/frameRule as single-row +// primitives for callers that need exact row accounting. +func padDialogFrame(lines []string) []string { + if len(lines) == 0 { + return lines + } + + out := append([]string(nil), lines...) + if isFrameHeaderLine(out[0]) && (len(out) == 1 || strings.TrimSpace(stripANSIBytes(out[1])) != "") { + out = append(out[:1], append([]string{""}, out[1:]...)...) + } + + last := len(out) - 1 + if last > 0 && isFrameRuleLine(out[last]) && strings.TrimSpace(stripANSIBytes(out[last-1])) != "" { + out = append(out[:last], append([]string{""}, out[last:]...)...) + } + return out +} + +func isFrameHeaderLine(line string) bool { + return strings.HasPrefix(stripANSIBytes(line), "── ") +} + +func isFrameRuleLine(line string) bool { + plain := stripANSIBytes(line) + if plain == "" { + return false + } + for _, r := range plain { + if r != '─' { + return false + } + } + return true +} + // frameHeaderColor is like frameHeader but renders in a caller-supplied // 256-color code. Used by the update-available banner which wants a // yellow accent on the rules and title. diff --git a/internal/agent/modes/help.go b/internal/agent/modes/help.go index 0e4c8f2..ed25007 100644 --- a/internal/agent/modes/help.go +++ b/internal/agent/modes/help.go @@ -69,7 +69,7 @@ func renderHelpBlock(th tui.Theme, width int) []string { } var out []string - out = append(out, frameHeader(th, "zot help", width)) + out = append(out, frameHeader(th, "zot help", width), "") // commands section out = append(out, tui.Bold("slash commands:")) @@ -87,6 +87,6 @@ func renderHelpBlock(th tui.Theme, width int) []string { th.FG256(th.Muted, k[1]))) } - out = append(out, frameRule(th, width), "") + out = append(out, "", frameRule(th, width), "") return out } diff --git a/internal/agent/modes/interactive.go b/internal/agent/modes/interactive.go index 36332a9..b4b38cc 100644 --- a/internal/agent/modes/interactive.go +++ b/internal/agent/modes/interactive.go @@ -931,6 +931,9 @@ func (i *Interactive) redraw() { case i.extPanel.Active(): dialog = i.extPanel.Render(i.cfg.Theme, cols) } + if len(dialog) > 0 { + dialog = padDialogFrame(dialog) + } // Slash-command autocomplete: popup above the status line, only // when the editor starts with "/" and no dialog is already open.