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 content = strings.Join([]string{content, "", attachmentsStr}, "\n")
64 }
65
66 height = lipgloss.Height(content)
67 m.setCachedRender(content, cappedWidth, height)
68 return style.Render(m.renderHighlighted(content, cappedWidth, height))
69}
70
71// ID implements MessageItem.
72func (m *UserMessageItem) ID() string {
73 return m.message.ID
74}
75
76// renderAttachments renders attachments.
77func (m *UserMessageItem) renderAttachments(width int) string {
78 var attachments []message.Attachment
79 for _, at := range m.message.BinaryContent() {
80 attachments = append(attachments, message.Attachment{
81 FileName: at.Path,
82 MimeType: at.MIMEType,
83 })
84 }
85 return m.attachments.Render(attachments, false, width)
86}