feat: better assistant message visual

This commit is contained in:
adamdotdevin
2025-08-05 19:00:08 -05:00
parent 030a3a7446
commit 6b25b7e95e
2 changed files with 32 additions and 76 deletions

View File

@@ -24,6 +24,7 @@ import (
type blockRenderer struct { type blockRenderer struct {
textColor compat.AdaptiveColor textColor compat.AdaptiveColor
backgroundColor compat.AdaptiveColor
border bool border bool
borderColor *compat.AdaptiveColor borderColor *compat.AdaptiveColor
borderLeft bool borderLeft bool
@@ -44,6 +45,12 @@ func WithTextColor(color compat.AdaptiveColor) renderingOption {
} }
} }
func WithBackgroundColor(color compat.AdaptiveColor) renderingOption {
return func(c *blockRenderer) {
c.backgroundColor = color
}
}
func WithNoBorder() renderingOption { func WithNoBorder() renderingOption {
return func(c *blockRenderer) { return func(c *blockRenderer) {
c.border = false c.border = false
@@ -133,6 +140,7 @@ func renderContentBlock(
t := theme.CurrentTheme() t := theme.CurrentTheme()
renderer := &blockRenderer{ renderer := &blockRenderer{
textColor: t.TextMuted(), textColor: t.TextMuted(),
backgroundColor: t.BackgroundPanel(),
border: true, border: true,
borderLeft: true, borderLeft: true,
borderRight: false, borderRight: false,
@@ -152,7 +160,7 @@ func renderContentBlock(
style := styles.NewStyle(). style := styles.NewStyle().
Foreground(renderer.textColor). Foreground(renderer.textColor).
Background(t.BackgroundPanel()). Background(renderer.backgroundColor).
PaddingTop(renderer.paddingTop). PaddingTop(renderer.paddingTop).
PaddingBottom(renderer.paddingBottom). PaddingBottom(renderer.paddingBottom).
PaddingLeft(renderer.paddingLeft). PaddingLeft(renderer.paddingLeft).
@@ -211,7 +219,7 @@ func renderText(
switch casted := message.(type) { switch casted := message.(type) {
case opencode.AssistantMessage: case opencode.AssistantMessage:
ts = time.UnixMilli(int64(casted.Time.Created)) ts = time.UnixMilli(int64(casted.Time.Created))
content = util.ToMarkdown(text, width, backgroundColor) content = util.ToMarkdown(text, width+2, t.Background())
case opencode.UserMessage: case opencode.UserMessage:
ts = time.UnixMilli(int64(casted.Time.Created)) ts = time.UnixMilli(int64(casted.Time.Created))
base := styles.NewStyle().Foreground(t.Text()).Background(backgroundColor) base := styles.NewStyle().Foreground(t.Text()).Background(backgroundColor)
@@ -286,14 +294,14 @@ func renderText(
width, width,
WithTextColor(t.Text()), WithTextColor(t.Text()),
WithBorderColor(t.Secondary()), WithBorderColor(t.Secondary()),
WithBorderRight(),
) )
case opencode.AssistantMessage: case opencode.AssistantMessage:
return renderContentBlock( return renderContentBlock(
app, app,
content, content,
width, width+2,
WithBorderColor(t.Accent()), WithNoBorder(),
WithBackgroundColor(t.Background()),
) )
} }
return "" return ""

View File

@@ -1,52 +0,0 @@
package util
import (
"regexp"
"strings"
"github.com/charmbracelet/lipgloss/v2"
)
// PreventHyphenBreaks replaces regular hyphens with non-breaking hyphens to prevent
// sparse word breaks in hyphenated terms like "claude-code-action".
// This improves readability by keeping hyphenated words together.
// Only preserves hyphens within words, not markdown syntax like bullet points.
func PreventHyphenBreaks(text string) string {
// Use regex to match hyphens that are between word characters
// This preserves hyphens in words like "claude-code-action" but not in "- [ ]"
re := regexp.MustCompile(`(\w)-(\w)`)
return re.ReplaceAllString(text, "$1\u2011$2")
}
// RestoreHyphens converts non-breaking hyphens back to regular hyphens.
// This should be called after text processing (like word wrapping) is complete.
func RestoreHyphens(text string) string {
return strings.ReplaceAll(text, "\u2011", "-")
}
// ProcessTextWithHyphens applies hyphen preservation to text during processing.
// It wraps the provided processFunc with hyphen handling.
func ProcessTextWithHyphens(text string, processFunc func(string) string) string {
preserved := PreventHyphenBreaks(text)
processed := processFunc(preserved)
return RestoreHyphens(processed)
}
// GetMessageContainerFrame calculates the actual horizontal frame size
// (padding + borders) for message containers based on current theme.
func GetMessageContainerFrame() int {
style := lipgloss.NewStyle().
BorderStyle(lipgloss.ThickBorder()).
BorderLeft(true).
BorderRight(true).
PaddingLeft(2).
PaddingRight(2)
return style.GetHorizontalFrameSize()
}
// GetMarkdownContainerFrame calculates the actual horizontal frame size
// for markdown containers based on current theme.
func GetMarkdownContainerFrame() int {
// Markdown containers use the same styling as message containers
return GetMessageContainerFrame()
}