user.go

 1package chat
 2
 3import (
 4	"strings"
 5
 6	"charm.land/lipgloss/v2"
 7	"github.com/charmbracelet/crush/internal/message"
 8	"github.com/charmbracelet/crush/internal/ui/attachments"
 9	"github.com/charmbracelet/crush/internal/ui/common"
10	"github.com/charmbracelet/crush/internal/ui/styles"
11)
12
13// UserMessageItem represents a user message in the chat UI.
14type UserMessageItem struct {
15	*highlightableMessageItem
16	*cachedMessageItem
17	*focusableMessageItem
18
19	attachments *attachments.Renderer
20	message     *message.Message
21	sty         *styles.Styles
22}
23
24// NewUserMessageItem creates a new UserMessageItem.
25func NewUserMessageItem(sty *styles.Styles, message *message.Message, attachments *attachments.Renderer) MessageItem {
26	return &UserMessageItem{
27		highlightableMessageItem: defaultHighlighter(sty),
28		cachedMessageItem:        &cachedMessageItem{},
29		focusableMessageItem:     &focusableMessageItem{},
30		attachments:              attachments,
31		message:                  message,
32		sty:                      sty,
33	}
34}
35
36// Render implements MessageItem.
37func (m *UserMessageItem) Render(width int) string {
38	cappedWidth := cappedMessageWidth(width)
39
40	style := m.sty.Chat.Message.UserBlurred
41	if m.focused {
42		style = m.sty.Chat.Message.UserFocused
43	}
44
45	content, height, ok := m.getCachedRender(cappedWidth)
46	// cache hit
47	if ok {
48		return style.Render(m.renderHighlighted(content, cappedWidth, height))
49	}
50
51	renderer := common.MarkdownRenderer(m.sty, cappedWidth)
52
53	msgContent := strings.TrimSpace(m.message.Content().Text)
54	result, err := renderer.Render(msgContent)
55	if err != nil {
56		content = msgContent
57	} else {
58		content = strings.TrimSuffix(result, "\n")
59	}
60
61	if len(m.message.BinaryContent()) > 0 {
62		attachmentsStr := m.renderAttachments(cappedWidth)
63		if content == "" {
64			content = attachmentsStr
65		} else {
66			content = strings.Join([]string{content, "", attachmentsStr}, "\n")
67		}
68	}
69
70	height = lipgloss.Height(content)
71	m.setCachedRender(content, cappedWidth, height)
72	return style.Render(m.renderHighlighted(content, cappedWidth, height))
73}
74
75// ID implements MessageItem.
76func (m *UserMessageItem) ID() string {
77	return m.message.ID
78}
79
80// renderAttachments renders attachments.
81func (m *UserMessageItem) renderAttachments(width int) string {
82	var attachments []message.Attachment
83	for _, at := range m.message.BinaryContent() {
84		attachments = append(attachments, message.Attachment{
85			FileName: at.Path,
86			MimeType: at.MIMEType,
87		})
88	}
89	return m.attachments.Render(attachments, false, width)
90}