| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110 |
- package chat
- import (
- "strings"
- tea "charm.land/bubbletea/v2"
- "charm.land/lipgloss/v2"
- "github.com/charmbracelet/crush/internal/message"
- "github.com/charmbracelet/crush/internal/ui/attachments"
- "github.com/charmbracelet/crush/internal/ui/common"
- "github.com/charmbracelet/crush/internal/ui/styles"
- )
- // UserMessageItem represents a user message in the chat UI.
- type UserMessageItem struct {
- *highlightableMessageItem
- *cachedMessageItem
- *focusableMessageItem
- attachments *attachments.Renderer
- message *message.Message
- sty *styles.Styles
- }
- // NewUserMessageItem creates a new UserMessageItem.
- func NewUserMessageItem(sty *styles.Styles, message *message.Message, attachments *attachments.Renderer) MessageItem {
- return &UserMessageItem{
- highlightableMessageItem: defaultHighlighter(sty),
- cachedMessageItem: &cachedMessageItem{},
- focusableMessageItem: &focusableMessageItem{},
- attachments: attachments,
- message: message,
- sty: sty,
- }
- }
- // RawRender implements [MessageItem].
- func (m *UserMessageItem) RawRender(width int) string {
- cappedWidth := cappedMessageWidth(width)
- content, height, ok := m.getCachedRender(cappedWidth)
- // cache hit
- if ok {
- return m.renderHighlighted(content, cappedWidth, height)
- }
- renderer := common.MarkdownRenderer(m.sty, cappedWidth)
- msgContent := strings.TrimSpace(m.message.Content().Text)
- result, err := renderer.Render(msgContent)
- if err != nil {
- content = msgContent
- } else {
- content = strings.TrimSuffix(result, "\n")
- }
- if len(m.message.BinaryContent()) > 0 {
- attachmentsStr := m.renderAttachments(cappedWidth)
- if content == "" {
- content = attachmentsStr
- } else {
- content = strings.Join([]string{content, "", attachmentsStr}, "\n")
- }
- }
- height = lipgloss.Height(content)
- m.setCachedRender(content, cappedWidth, height)
- return m.renderHighlighted(content, cappedWidth, height)
- }
- // Render implements MessageItem.
- func (m *UserMessageItem) Render(width int) string {
- var prefix string
- if m.focused {
- prefix = m.sty.Chat.Message.UserFocused.Render()
- } else {
- prefix = m.sty.Chat.Message.UserBlurred.Render()
- }
- lines := strings.Split(m.RawRender(width), "\n")
- for i, line := range lines {
- lines[i] = prefix + line
- }
- return strings.Join(lines, "\n")
- }
- // ID implements MessageItem.
- func (m *UserMessageItem) ID() string {
- return m.message.ID
- }
- // renderAttachments renders attachments.
- func (m *UserMessageItem) renderAttachments(width int) string {
- var attachments []message.Attachment
- for _, at := range m.message.BinaryContent() {
- attachments = append(attachments, message.Attachment{
- FileName: at.Path,
- MimeType: at.MIMEType,
- })
- }
- return m.attachments.Render(attachments, false, width)
- }
- // HandleKeyEvent implements KeyEventHandler.
- func (m *UserMessageItem) HandleKeyEvent(key tea.KeyMsg) (bool, tea.Cmd) {
- if k := key.String(); k == "c" || k == "y" {
- text := m.message.Content().Text
- return true, common.CopyToClipboard(text, "Message copied to clipboard")
- }
- return false, nil
- }
|