Skip to content

Commit 80bccc8

Browse files
steilerDevclaude
andcommitted
fix(tui): remove spurious blank line from assistant messages
Commit 574a466 introduced the copy-on-hover button for assistant messages using the same "topRow+\n" pattern as user messages. However, UserMessageStyle has PaddingTop=1 (inherited from BaseMessageStyle) so PaddingTop(0)+topRow+"\n" is net-zero. AssistantMessageStyle overrides to Padding(0,1), meaning PaddingTop=0 already; PaddingTop(0) is a no-op and the unconditional "\n" prefix adds a spurious blank line to every assistant message in its normal (non-hovered) state. Fix: only use the topRow+"\n" rendering path when the copy icon is actually visible (hovered or selected). Fall back to the original messageStyle.Render(rendered) for the common case. This accepts a 1-line layout shift on hover rather than a permanent blank-line artifact on every message. Fixes: #2368 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 131e93d commit 80bccc8

File tree

1 file changed

+11
-7
lines changed

1 file changed

+11
-7
lines changed

pkg/tui/components/message/message.go

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -145,18 +145,22 @@ func (mv *messageModel) Render(width int) string {
145145
prefix = mv.senderPrefix(msg.Sender)
146146
}
147147

148-
// Always reserve a top row for the copy icon to avoid layout shifts.
149-
// The icon is only visible when hovered or selected.
150-
innerWidth := width - messageStyle.GetHorizontalFrameSize()
151-
var topRow string
148+
// Show copy icon in the top-right corner when hovered or selected.
149+
// AssistantMessageStyle has PaddingTop=0 (unlike UserMessageStyle which has
150+
// PaddingTop=1), so we cannot unconditionally prepend topRow+"\n" — doing so
151+
// would add a spurious blank line to every message in the default state.
152+
// Accept the 1-line layout shift on hover; it is less disruptive than the
153+
// blank-line artifact that affects all messages at all times.
152154
if mv.hovered || mv.selected {
155+
innerWidth := width - messageStyle.GetHorizontalFrameSize()
153156
copyIcon := styles.MutedStyle.Render(types.AssistantMessageCopyLabel)
154157
iconWidth := ansi.StringWidth(types.AssistantMessageCopyLabel)
155158
padding := max(innerWidth-iconWidth, 0)
156-
topRow = strings.Repeat(" ", padding) + copyIcon
159+
topRow := strings.Repeat(" ", padding) + copyIcon
160+
noTopPaddingStyle := messageStyle.PaddingTop(0)
161+
return prefix + noTopPaddingStyle.Width(width).Render(topRow+"\n"+rendered)
157162
}
158-
noTopPaddingStyle := messageStyle.PaddingTop(0)
159-
return prefix + noTopPaddingStyle.Width(width).Render(topRow+"\n"+rendered)
163+
return prefix + messageStyle.Render(rendered)
160164
case types.MessageTypeShellOutput:
161165
if rendered, err := markdown.NewRenderer(width).Render(fmt.Sprintf("```console\n%s\n```", msg.Content)); err == nil {
162166
return rendered

0 commit comments

Comments
 (0)