feat(tui): render attachments

This commit is contained in:
adamdottv 2025-07-04 10:54:53 -05:00
parent f9abc7c84f
commit 94ef341c9d
No known key found for this signature in database
GPG key ID: 9CB48779AF150E75
2 changed files with 51 additions and 3 deletions

View file

@ -223,6 +223,7 @@ func renderText(
showToolDetails bool, showToolDetails bool,
highlight bool, highlight bool,
width int, width int,
extra string,
toolCalls ...opencode.ToolInvocationPart, toolCalls ...opencode.ToolInvocationPart,
) string { ) string {
t := theme.CurrentTheme() t := theme.CurrentTheme()
@ -269,7 +270,11 @@ func renderText(
} }
} }
content = strings.Join([]string{content, info}, "\n") sections := []string{content, info}
if extra != "" {
sections = append(sections, "\n"+extra)
}
content = strings.Join(sections, "\n")
switch message.Role { switch message.Role {
case opencode.MessageRoleUser: case opencode.MessageRoleUser:

View file

@ -9,6 +9,7 @@ import (
"github.com/sst/opencode-sdk-go" "github.com/sst/opencode-sdk-go"
"github.com/sst/opencode/internal/app" "github.com/sst/opencode/internal/app"
"github.com/sst/opencode/internal/components/dialog" "github.com/sst/opencode/internal/components/dialog"
"github.com/sst/opencode/internal/layout"
"github.com/sst/opencode/internal/styles" "github.com/sst/opencode/internal/styles"
"github.com/sst/opencode/internal/theme" "github.com/sst/opencode/internal/theme"
"github.com/sst/opencode/internal/util" "github.com/sst/opencode/internal/util"
@ -133,10 +134,49 @@ func (m *messagesComponent) renderView(width int) {
switch message.Role { switch message.Role {
case opencode.MessageRoleUser: case opencode.MessageRoleUser:
for _, part := range message.Parts { for partIndex, part := range message.Parts {
switch part := part.AsUnion().(type) { switch part := part.AsUnion().(type) {
case opencode.TextPart: case opencode.TextPart:
key := m.cache.GenerateKey(message.ID, part.Text, width, m.selectedPart == m.partCount) remainingParts := message.Parts[partIndex+1:]
fileParts := make([]opencode.FilePart, 0)
for _, part := range remainingParts {
switch part := part.AsUnion().(type) {
case opencode.FilePart:
fileParts = append(fileParts, part)
}
}
flexItems := []layout.FlexItem{}
if len(fileParts) > 0 {
fileStyle := styles.NewStyle().Background(t.BackgroundElement()).Foreground(t.TextMuted()).Padding(0, 1)
mediaTypeStyle := styles.NewStyle().Background(t.Secondary()).Foreground(t.BackgroundPanel()).Padding(0, 1)
for _, filePart := range fileParts {
mediaType := ""
switch filePart.MediaType {
case "text/plain":
mediaType = "txt"
case "image/png", "image/jpeg", "image/gif", "image/webp":
mediaType = "img"
case "application/pdf":
mediaType = "pdf"
}
flexItems = append(flexItems, layout.FlexItem{
View: mediaTypeStyle.Render(mediaType) + fileStyle.Render(filePart.Filename),
})
}
}
bgColor := t.BackgroundPanel()
files := layout.Render(
layout.FlexOptions{
Background: &bgColor,
Width: width - 6,
Direction: layout.Row,
Gap: 3,
},
flexItems...,
)
key := m.cache.GenerateKey(message.ID, part.Text, width, m.selectedPart == m.partCount, files)
content, cached = m.cache.Get(key) content, cached = m.cache.Get(key)
if !cached { if !cached {
content = renderText( content = renderText(
@ -147,6 +187,7 @@ func (m *messagesComponent) renderView(width int) {
m.showToolDetails, m.showToolDetails,
m.partCount == m.selectedPart, m.partCount == m.selectedPart,
width, width,
files,
) )
m.cache.Set(key, content) m.cache.Set(key, content)
} }
@ -206,6 +247,7 @@ func (m *messagesComponent) renderView(width int) {
m.showToolDetails, m.showToolDetails,
m.partCount == m.selectedPart, m.partCount == m.selectedPart,
width, width,
"",
toolCallParts..., toolCallParts...,
) )
m.cache.Set(key, content) m.cache.Set(key, content)
@ -219,6 +261,7 @@ func (m *messagesComponent) renderView(width int) {
m.showToolDetails, m.showToolDetails,
m.partCount == m.selectedPart, m.partCount == m.selectedPart,
width, width,
"",
toolCallParts..., toolCallParts...,
) )
} }