mirror of
https://github.com/sst/opencode.git
synced 2025-08-31 10:17:26 +00:00
wip: refactoring tui
This commit is contained in:
parent
fce9e79d38
commit
26606ccbf7
3 changed files with 198 additions and 267 deletions
|
@ -11,7 +11,6 @@ import (
|
|||
"github.com/charmbracelet/x/ansi"
|
||||
"github.com/sst/opencode/internal/config"
|
||||
"github.com/sst/opencode/internal/diff"
|
||||
"github.com/sst/opencode/internal/llm/models"
|
||||
"github.com/sst/opencode/internal/llm/tools"
|
||||
"github.com/sst/opencode/internal/message"
|
||||
"github.com/sst/opencode/internal/tui/styles"
|
||||
|
@ -22,64 +21,25 @@ import (
|
|||
type uiMessageType int
|
||||
|
||||
const (
|
||||
userMessageType uiMessageType = iota
|
||||
assistantMessageType
|
||||
toolMessageType
|
||||
|
||||
maxResultHeight = 10
|
||||
)
|
||||
|
||||
type uiMessage struct {
|
||||
ID string
|
||||
messageType uiMessageType
|
||||
content string
|
||||
}
|
||||
|
||||
func toMarkdown(content string, focused bool, width int) string {
|
||||
func toMarkdown(content string, width int) string {
|
||||
r := styles.GetMarkdownRenderer(width)
|
||||
rendered, _ := r.Render(content)
|
||||
return rendered
|
||||
return strings.TrimSuffix(rendered, "\n")
|
||||
}
|
||||
|
||||
func renderMessage(msg string, isUser bool, isFocused bool, width int, info ...string) string {
|
||||
func renderUserMessage(msg client.MessageInfo, width int) string {
|
||||
t := theme.CurrentTheme()
|
||||
|
||||
style := styles.BaseStyle().
|
||||
// Width(width - 1).
|
||||
BorderLeft(true).
|
||||
Foreground(t.TextMuted()).
|
||||
BorderForeground(t.Primary()).
|
||||
BorderForeground(t.Secondary()).
|
||||
BorderStyle(lipgloss.ThickBorder())
|
||||
|
||||
if isUser {
|
||||
style = style.BorderForeground(t.Secondary())
|
||||
}
|
||||
|
||||
// Apply markdown formatting and handle background color
|
||||
parts := []string{
|
||||
styles.ForceReplaceBackgroundWithLipgloss(toMarkdown(msg, isFocused, width), t.Background()),
|
||||
}
|
||||
|
||||
// Remove newline at the end
|
||||
parts[0] = strings.TrimSuffix(parts[0], "\n")
|
||||
if len(info) > 0 {
|
||||
parts = append(parts, info...)
|
||||
}
|
||||
|
||||
rendered := style.Render(
|
||||
lipgloss.JoinVertical(
|
||||
lipgloss.Left,
|
||||
parts...,
|
||||
),
|
||||
)
|
||||
|
||||
return rendered
|
||||
}
|
||||
|
||||
func renderUserMessage(msg client.MessageInfo, isFocused bool, width int) uiMessage {
|
||||
// var styledAttachments []string
|
||||
t := theme.CurrentTheme()
|
||||
baseStyle := styles.BaseStyle()
|
||||
// var styledAttachments []string
|
||||
// attachmentStyles := baseStyle.
|
||||
// MarginLeft(1).
|
||||
// Background(t.TextMuted()).
|
||||
|
@ -95,16 +55,12 @@ func renderUserMessage(msg client.MessageInfo, isFocused bool, width int) uiMess
|
|||
// styledAttachments = append(styledAttachments, attachmentStyles.Render(filename))
|
||||
// }
|
||||
|
||||
info := []string{}
|
||||
|
||||
// Add timestamp info
|
||||
timestamp := time.UnixMilli(int64(msg.Metadata.Time.Created)).Local().Format("02 Jan 2006 03:04 PM")
|
||||
username, _ := config.GetUsername()
|
||||
info = append(info, baseStyle.
|
||||
Width(width-1).
|
||||
info := baseStyle.
|
||||
Foreground(t.TextMuted()).
|
||||
Render(fmt.Sprintf(" %s (%s)", username, timestamp)),
|
||||
)
|
||||
Render(fmt.Sprintf(" %s (%s)", username, timestamp))
|
||||
|
||||
content := ""
|
||||
// if len(styledAttachments) > 0 {
|
||||
|
@ -120,125 +76,175 @@ func renderUserMessage(msg client.MessageInfo, isFocused bool, width int) uiMess
|
|||
switch part.(type) {
|
||||
case client.MessagePartText:
|
||||
textPart := part.(client.MessagePartText)
|
||||
content = renderMessage(textPart.Text, true, isFocused, width, info...)
|
||||
text := toMarkdown(textPart.Text, width)
|
||||
content = style.Render(lipgloss.JoinVertical(lipgloss.Left, text, info))
|
||||
}
|
||||
}
|
||||
// content = renderMessage(msg.Parts, true, isFocused, width, info...)
|
||||
|
||||
userMsg := uiMessage{
|
||||
ID: msg.Id,
|
||||
messageType: userMessageType,
|
||||
content: content,
|
||||
}
|
||||
return userMsg
|
||||
return content
|
||||
}
|
||||
|
||||
func convertToMap(input *any) (map[string]any, bool) {
|
||||
if input == nil {
|
||||
return nil, false // Handle nil pointer
|
||||
}
|
||||
value := *input // Dereference the pointer to get the interface value
|
||||
m, ok := value.(map[string]any) // Type assertion
|
||||
return m, ok
|
||||
}
|
||||
|
||||
// Returns multiple uiMessages because of the tool calls
|
||||
func renderAssistantMessage(
|
||||
msg message.Message,
|
||||
msgIndex int,
|
||||
allMessages []message.Message, // we need this to get tool results and the user message
|
||||
messagesService message.Service, // We need this to get the task tool messages
|
||||
focusedUIMessageId string,
|
||||
msg client.MessageInfo,
|
||||
width int,
|
||||
position int,
|
||||
showToolMessages bool,
|
||||
) []uiMessage {
|
||||
messages := []uiMessage{}
|
||||
content := strings.TrimSpace(msg.Content().String())
|
||||
thinking := msg.IsThinking()
|
||||
thinkingContent := msg.ReasoningContent().Thinking
|
||||
finished := msg.IsFinished()
|
||||
finishData := msg.FinishPart()
|
||||
info := []string{}
|
||||
|
||||
) string {
|
||||
t := theme.CurrentTheme()
|
||||
baseStyle := styles.BaseStyle()
|
||||
|
||||
// Always add timestamp info
|
||||
timestamp := msg.CreatedAt.Local().Format("02 Jan 2006 03:04 PM")
|
||||
modelName := "Assistant"
|
||||
if msg.Model != "" {
|
||||
modelName = models.SupportedModels[msg.Model].Name
|
||||
}
|
||||
|
||||
info = append(info, baseStyle.
|
||||
Width(width-1).
|
||||
style := styles.BaseStyle().
|
||||
BorderLeft(true).
|
||||
Foreground(t.TextMuted()).
|
||||
Render(fmt.Sprintf(" %s (%s)", modelName, timestamp)),
|
||||
)
|
||||
BorderForeground(t.Primary()).
|
||||
BorderStyle(lipgloss.ThickBorder())
|
||||
toolStyle := styles.BaseStyle().
|
||||
BorderLeft(true).
|
||||
Foreground(t.TextMuted()).
|
||||
BorderForeground(t.TextMuted()).
|
||||
BorderStyle(lipgloss.ThickBorder())
|
||||
|
||||
if finished {
|
||||
// Add finish info if available
|
||||
switch finishData.Reason {
|
||||
case message.FinishReasonCanceled:
|
||||
info = append(info, baseStyle.
|
||||
Width(width-1).
|
||||
Foreground(t.Warning()).
|
||||
Render("(canceled)"),
|
||||
)
|
||||
case message.FinishReasonError:
|
||||
info = append(info, baseStyle.
|
||||
Width(width-1).
|
||||
Foreground(t.Error()).
|
||||
Render("(error)"),
|
||||
)
|
||||
case message.FinishReasonPermissionDenied:
|
||||
info = append(info, baseStyle.
|
||||
Width(width-1).
|
||||
Foreground(t.Info()).
|
||||
Render("(permission denied)"),
|
||||
)
|
||||
baseStyle := styles.BaseStyle()
|
||||
messages := []string{}
|
||||
|
||||
// content := strings.TrimSpace(msg.Content().String())
|
||||
// thinking := msg.IsThinking()
|
||||
// thinkingContent := msg.ReasoningContent().Thinking
|
||||
// finished := msg.IsFinished()
|
||||
// finishData := msg.FinishPart()
|
||||
|
||||
// Add timestamp info
|
||||
timestamp := time.UnixMilli(int64(msg.Metadata.Time.Created)).Local().Format("02 Jan 2006 03:04 PM")
|
||||
modelName := msg.Metadata.Assistant.ModelID
|
||||
info := baseStyle.
|
||||
Foreground(t.TextMuted()).
|
||||
Render(fmt.Sprintf(" %s (%s)", modelName, timestamp))
|
||||
|
||||
for _, p := range msg.Parts {
|
||||
part, err := p.ValueByDiscriminator()
|
||||
if err != nil {
|
||||
continue //TODO: handle error?
|
||||
}
|
||||
|
||||
switch part.(type) {
|
||||
case client.MessagePartText:
|
||||
textPart := part.(client.MessagePartText)
|
||||
text := toMarkdown(textPart.Text, width)
|
||||
content := style.Render(lipgloss.JoinVertical(lipgloss.Left, text, info))
|
||||
messages = append(messages, content)
|
||||
|
||||
case client.MessagePartToolInvocation:
|
||||
if !showToolMessages {
|
||||
continue
|
||||
}
|
||||
|
||||
toolInvocationPart := part.(client.MessagePartToolInvocation)
|
||||
toolInvocation, _ := toolInvocationPart.ToolInvocation.ValueByDiscriminator()
|
||||
switch toolInvocation.(type) {
|
||||
case client.MessageToolInvocationToolCall:
|
||||
toolCall := toolInvocation.(client.MessageToolInvocationToolCall)
|
||||
toolName := toolName(toolCall.ToolName)
|
||||
var toolArgs []string
|
||||
toolMap, _ := convertToMap(toolCall.Args)
|
||||
for _, arg := range toolMap {
|
||||
toolArgs = append(toolArgs, fmt.Sprintf("%v", arg))
|
||||
}
|
||||
params := renderParams(width-lipgloss.Width(toolName)-1, toolArgs...)
|
||||
title := styles.Padded().Render(fmt.Sprintf("%s: %s", toolName, params))
|
||||
|
||||
content := toolStyle.Render(lipgloss.JoinVertical(lipgloss.Left,
|
||||
title,
|
||||
" In progress...",
|
||||
))
|
||||
messages = append(messages, content)
|
||||
|
||||
case client.MessageToolInvocationToolResult:
|
||||
toolInvocationResult := toolInvocation.(client.MessageToolInvocationToolResult)
|
||||
toolName := toolName(toolInvocationResult.ToolName)
|
||||
var toolArgs []string
|
||||
toolMap, _ := convertToMap(toolInvocationResult.Args)
|
||||
for _, arg := range toolMap {
|
||||
toolArgs = append(toolArgs, fmt.Sprintf("%v", arg))
|
||||
}
|
||||
result := truncateHeight(strings.TrimSpace(toolInvocationResult.Result), 10)
|
||||
params := renderParams(width-lipgloss.Width(toolName)-1, toolArgs...)
|
||||
title := styles.Padded().Render(fmt.Sprintf("%s: %s", toolName, params))
|
||||
|
||||
markdown := toMarkdown(result, width)
|
||||
|
||||
content := toolStyle.Render(lipgloss.JoinVertical(lipgloss.Left,
|
||||
title,
|
||||
markdown,
|
||||
))
|
||||
messages = append(messages, content)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if content != "" || (finished && finishData.Reason == message.FinishReasonEndTurn) {
|
||||
if content == "" {
|
||||
content = "*Finished without output*"
|
||||
}
|
||||
// if finished {
|
||||
// // Add finish info if available
|
||||
// switch finishData.Reason {
|
||||
// case message.FinishReasonCanceled:
|
||||
// info = append(info, baseStyle.
|
||||
// Width(width-1).
|
||||
// Foreground(t.Warning()).
|
||||
// Render("(canceled)"),
|
||||
// )
|
||||
// case message.FinishReasonError:
|
||||
// info = append(info, baseStyle.
|
||||
// Width(width-1).
|
||||
// Foreground(t.Error()).
|
||||
// Render("(error)"),
|
||||
// )
|
||||
// case message.FinishReasonPermissionDenied:
|
||||
// info = append(info, baseStyle.
|
||||
// Width(width-1).
|
||||
// Foreground(t.Info()).
|
||||
// Render("(permission denied)"),
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
|
||||
content = renderMessage(content, false, true, width, info...)
|
||||
messages = append(messages, uiMessage{
|
||||
ID: msg.ID,
|
||||
messageType: assistantMessageType,
|
||||
// position: position,
|
||||
// height: lipgloss.Height(content),
|
||||
content: content,
|
||||
})
|
||||
// position += messages[0].height
|
||||
position++ // for the space
|
||||
} else if thinking && thinkingContent != "" {
|
||||
// Render the thinking content with timestamp
|
||||
content = renderMessage(thinkingContent, false, msg.ID == focusedUIMessageId, width, info...)
|
||||
messages = append(messages, uiMessage{
|
||||
ID: msg.ID,
|
||||
messageType: assistantMessageType,
|
||||
// position: position,
|
||||
// height: lipgloss.Height(content),
|
||||
content: content,
|
||||
})
|
||||
position += lipgloss.Height(content)
|
||||
position++ // for the space
|
||||
}
|
||||
// if content != "" || (finished && finishData.Reason == message.FinishReasonEndTurn) {
|
||||
// if content == "" {
|
||||
// content = "*Finished without output*"
|
||||
// }
|
||||
//
|
||||
// content = renderMessage(content, false, width, info...)
|
||||
// messages = append(messages, content)
|
||||
// // position += messages[0].height
|
||||
// position++ // for the space
|
||||
// } else if thinking && thinkingContent != "" {
|
||||
// // Render the thinking content with timestamp
|
||||
// content = renderMessage(thinkingContent, false, width, info...)
|
||||
// messages = append(messages, content)
|
||||
// position += lipgloss.Height(content)
|
||||
// position++ // for the space
|
||||
// }
|
||||
|
||||
// Only render tool messages if they should be shown
|
||||
if showToolMessages {
|
||||
for i, toolCall := range msg.ToolCalls() {
|
||||
toolCallContent := renderToolMessage(
|
||||
toolCall,
|
||||
allMessages,
|
||||
messagesService,
|
||||
focusedUIMessageId,
|
||||
false,
|
||||
width,
|
||||
i+1,
|
||||
)
|
||||
messages = append(messages, toolCallContent)
|
||||
// position += toolCallContent.height
|
||||
position++ // for the space
|
||||
}
|
||||
// for i, toolCall := range msg.ToolCalls() {
|
||||
// toolCallContent := renderToolMessage(
|
||||
// toolCall,
|
||||
// allMessages,
|
||||
// messagesService,
|
||||
// focusedUIMessageId,
|
||||
// false,
|
||||
// width,
|
||||
// i+1,
|
||||
// )
|
||||
// messages = append(messages, toolCallContent)
|
||||
// }
|
||||
}
|
||||
return messages
|
||||
|
||||
return strings.Join(messages, "\n\n")
|
||||
}
|
||||
|
||||
func findToolResponse(toolCallID string, futureMessages []message.Message) *message.ToolResult {
|
||||
|
@ -497,7 +503,7 @@ func renderToolResponse(toolCall message.ToolCall, response message.ToolResult,
|
|||
case tools.BashToolName:
|
||||
resultContent = fmt.Sprintf("```bash\n%s\n```", resultContent)
|
||||
return styles.ForceReplaceBackgroundWithLipgloss(
|
||||
toMarkdown(resultContent, true, width),
|
||||
toMarkdown(resultContent, width),
|
||||
t.Background(),
|
||||
)
|
||||
case tools.EditToolName:
|
||||
|
@ -517,7 +523,7 @@ func renderToolResponse(toolCall message.ToolCall, response message.ToolResult,
|
|||
}
|
||||
resultContent = fmt.Sprintf("```%s\n%s\n```", mdFormat, resultContent)
|
||||
return styles.ForceReplaceBackgroundWithLipgloss(
|
||||
toMarkdown(resultContent, true, width),
|
||||
toMarkdown(resultContent, width),
|
||||
t.Background(),
|
||||
)
|
||||
case tools.GlobToolName:
|
||||
|
@ -537,7 +543,7 @@ func renderToolResponse(toolCall message.ToolCall, response message.ToolResult,
|
|||
}
|
||||
resultContent = fmt.Sprintf("```%s\n%s\n```", ext, truncateHeight(metadata.Content, maxResultHeight))
|
||||
return styles.ForceReplaceBackgroundWithLipgloss(
|
||||
toMarkdown(resultContent, true, width),
|
||||
toMarkdown(resultContent, width),
|
||||
t.Background(),
|
||||
)
|
||||
case tools.WriteToolName:
|
||||
|
@ -553,7 +559,7 @@ func renderToolResponse(toolCall message.ToolCall, response message.ToolResult,
|
|||
}
|
||||
resultContent = fmt.Sprintf("```%s\n%s\n```", ext, truncateHeight(params.Content, maxResultHeight))
|
||||
return styles.ForceReplaceBackgroundWithLipgloss(
|
||||
toMarkdown(resultContent, true, width),
|
||||
toMarkdown(resultContent, width),
|
||||
t.Background(),
|
||||
)
|
||||
case tools.BatchToolName:
|
||||
|
@ -591,7 +597,7 @@ func renderToolResponse(toolCall message.ToolCall, response message.ToolResult,
|
|||
default:
|
||||
resultContent = fmt.Sprintf("```text\n%s\n```", resultContent)
|
||||
return styles.ForceReplaceBackgroundWithLipgloss(
|
||||
toMarkdown(resultContent, true, width),
|
||||
toMarkdown(resultContent, width),
|
||||
t.Background(),
|
||||
)
|
||||
}
|
||||
|
@ -605,7 +611,7 @@ func renderToolMessage(
|
|||
nested bool,
|
||||
width int,
|
||||
position int,
|
||||
) uiMessage {
|
||||
) string {
|
||||
if nested {
|
||||
width = width - 3
|
||||
}
|
||||
|
@ -634,13 +640,7 @@ func renderToolMessage(
|
|||
Render(fmt.Sprintf("%s", toolAction))
|
||||
|
||||
content := style.Render(lipgloss.JoinHorizontal(lipgloss.Left, toolNameText, progressText))
|
||||
toolMsg := uiMessage{
|
||||
messageType: toolMessageType,
|
||||
// position: position,
|
||||
// height: lipgloss.Height(content),
|
||||
content: content,
|
||||
}
|
||||
return toolMsg
|
||||
return content
|
||||
}
|
||||
|
||||
params := renderToolParams(width-1-lipgloss.Width(toolNameText), toolCall)
|
||||
|
@ -702,11 +702,5 @@ func renderToolMessage(
|
|||
parts...,
|
||||
)
|
||||
}
|
||||
toolMsg := uiMessage{
|
||||
messageType: toolMessageType,
|
||||
// position: position,
|
||||
// height: lipgloss.Height(content),
|
||||
content: content,
|
||||
}
|
||||
return toolMsg
|
||||
return content
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package chat
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"time"
|
||||
|
||||
"github.com/charmbracelet/bubbles/key"
|
||||
|
@ -20,18 +18,11 @@ import (
|
|||
"github.com/sst/opencode/pkg/client"
|
||||
)
|
||||
|
||||
type cacheItem struct {
|
||||
width int
|
||||
content []uiMessage
|
||||
}
|
||||
|
||||
type messagesCmp struct {
|
||||
app *app.App
|
||||
width, height int
|
||||
viewport viewport.Model
|
||||
uiMessages []uiMessage
|
||||
currentMsgID string
|
||||
cachedContent map[string]cacheItem
|
||||
spinner spinner.Model
|
||||
rendering bool
|
||||
attachments viewport.Model
|
||||
|
@ -71,17 +62,17 @@ func (m *messagesCmp) Init() tea.Cmd {
|
|||
}
|
||||
|
||||
func (m *messagesCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
m.renderView()
|
||||
// m.renderView()
|
||||
|
||||
var cmds []tea.Cmd
|
||||
switch msg := msg.(type) {
|
||||
case dialog.ThemeChangedMsg:
|
||||
m.rerender()
|
||||
m.renderView()
|
||||
return m, nil
|
||||
case ToggleToolMessagesMsg:
|
||||
m.showToolMessages = !m.showToolMessages
|
||||
// Clear the cache to force re-rendering of all messages
|
||||
m.cachedContent = make(map[string]cacheItem)
|
||||
// m.cachedContent = make(map[string]cacheItem)
|
||||
m.renderView()
|
||||
return m, nil
|
||||
case state.SessionSelectedMsg:
|
||||
|
@ -171,93 +162,43 @@ func (m *messagesCmp) IsAgentWorking() bool {
|
|||
return m.app.PrimaryAgentOLD.IsSessionBusy(m.app.CurrentSessionOLD.ID)
|
||||
}
|
||||
|
||||
func formatTimeDifference(unixTime1, unixTime2 int64) string {
|
||||
diffSeconds := float64(math.Abs(float64(unixTime2 - unixTime1)))
|
||||
|
||||
if diffSeconds < 60 {
|
||||
return fmt.Sprintf("%.1fs", diffSeconds)
|
||||
}
|
||||
|
||||
minutes := int(diffSeconds / 60)
|
||||
seconds := int(diffSeconds) % 60
|
||||
return fmt.Sprintf("%dm%ds", minutes, seconds)
|
||||
}
|
||||
|
||||
func (m *messagesCmp) renderView() {
|
||||
m.uiMessages = make([]uiMessage, 0)
|
||||
baseStyle := styles.BaseStyle()
|
||||
|
||||
if m.width == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
t := theme.CurrentTheme()
|
||||
messages := make([]string, 0)
|
||||
for _, msg := range m.app.Messages {
|
||||
switch msg.Role {
|
||||
case client.User:
|
||||
if cache, ok := m.cachedContent[msg.Id]; ok && cache.width == m.width {
|
||||
m.uiMessages = append(m.uiMessages, cache.content...)
|
||||
continue
|
||||
}
|
||||
userMsg := renderUserMessage(
|
||||
content := renderUserMessage(
|
||||
msg,
|
||||
msg.Id == m.currentMsgID,
|
||||
m.width,
|
||||
)
|
||||
m.uiMessages = append(m.uiMessages, userMsg)
|
||||
m.cachedContent[msg.Id] = cacheItem{
|
||||
width: m.width,
|
||||
content: []uiMessage{userMsg},
|
||||
}
|
||||
// pos += userMsg.height + 1 // + 1 for spacing
|
||||
messages = append(messages, content+"\n")
|
||||
case client.Assistant:
|
||||
if cache, ok := m.cachedContent[msg.Id]; ok && cache.width == m.width {
|
||||
m.uiMessages = append(m.uiMessages, cache.content...)
|
||||
continue
|
||||
}
|
||||
// assistantMessages := renderAssistantMessage(
|
||||
// msg,
|
||||
// inx,
|
||||
// m.app.Messages,
|
||||
// m.app.MessagesOLD,
|
||||
// m.currentMsgID,
|
||||
// m.width,
|
||||
// pos,
|
||||
// m.showToolMessages,
|
||||
// )
|
||||
// for _, msg := range assistantMessages {
|
||||
// m.uiMessages = append(m.uiMessages, msg)
|
||||
// // pos += msg.height + 1 // + 1 for spacing
|
||||
// }
|
||||
// m.cachedContent[msg.Id] = cacheItem{
|
||||
// width: m.width,
|
||||
// content: assistantMessages,
|
||||
// }
|
||||
content := renderAssistantMessage(
|
||||
msg,
|
||||
m.width,
|
||||
m.showToolMessages,
|
||||
)
|
||||
messages = append(messages, content+"\n")
|
||||
}
|
||||
}
|
||||
|
||||
messages := make([]string, 0)
|
||||
for _, v := range m.uiMessages {
|
||||
messages = append(messages, lipgloss.JoinVertical(lipgloss.Left, v.content),
|
||||
baseStyle.
|
||||
m.viewport.SetContent(
|
||||
styles.ForceReplaceBackgroundWithLipgloss(
|
||||
styles.BaseStyle().
|
||||
Width(m.width).
|
||||
Render(
|
||||
"",
|
||||
lipgloss.JoinVertical(
|
||||
lipgloss.Top,
|
||||
messages...,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
// temp, _ := json.MarshalIndent(m.app.State, "", " ")
|
||||
|
||||
m.viewport.SetContent(
|
||||
baseStyle.
|
||||
Width(m.width).
|
||||
Render(
|
||||
// string(temp),
|
||||
lipgloss.JoinVertical(
|
||||
lipgloss.Top,
|
||||
messages...,
|
||||
),
|
||||
),
|
||||
t.Background(),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -416,13 +357,6 @@ func (m *messagesCmp) initialScreen() string {
|
|||
)
|
||||
}
|
||||
|
||||
func (m *messagesCmp) rerender() {
|
||||
for _, msg := range m.app.Messages {
|
||||
delete(m.cachedContent, msg.Id)
|
||||
}
|
||||
m.renderView()
|
||||
}
|
||||
|
||||
func (m *messagesCmp) SetSize(width, height int) tea.Cmd {
|
||||
if m.width == width && m.height == height {
|
||||
return nil
|
||||
|
@ -433,7 +367,7 @@ func (m *messagesCmp) SetSize(width, height int) tea.Cmd {
|
|||
m.viewport.Height = height - 2
|
||||
m.attachments.Width = width + 40
|
||||
m.attachments.Height = 3
|
||||
m.rerender()
|
||||
m.renderView()
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -453,7 +387,7 @@ func (m *messagesCmp) Reload(session *session.Session) tea.Cmd {
|
|||
if len(m.app.Messages) > 0 {
|
||||
m.currentMsgID = m.app.Messages[len(m.app.Messages)-1].Id
|
||||
}
|
||||
delete(m.cachedContent, m.currentMsgID)
|
||||
// delete(m.cachedContent, m.currentMsgID)
|
||||
m.rendering = true
|
||||
return func() tea.Msg {
|
||||
m.renderView()
|
||||
|
@ -476,18 +410,19 @@ func NewMessagesCmp(app *app.App) tea.Model {
|
|||
FPS: time.Second / 3,
|
||||
}
|
||||
s := spinner.New(spinner.WithSpinner(customSpinner))
|
||||
|
||||
vp := viewport.New(0, 0)
|
||||
attachmets := viewport.New(0, 0)
|
||||
attachments := viewport.New(0, 0)
|
||||
vp.KeyMap.PageUp = messageKeys.PageUp
|
||||
vp.KeyMap.PageDown = messageKeys.PageDown
|
||||
vp.KeyMap.HalfPageUp = messageKeys.HalfPageUp
|
||||
vp.KeyMap.HalfPageDown = messageKeys.HalfPageDown
|
||||
|
||||
return &messagesCmp{
|
||||
app: app,
|
||||
cachedContent: make(map[string]cacheItem),
|
||||
viewport: vp,
|
||||
spinner: s,
|
||||
attachments: attachmets,
|
||||
attachments: attachments,
|
||||
showToolMessages: true,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -285,7 +285,8 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||
|
||||
a.app.Session = &sessionInfo
|
||||
}
|
||||
return a, nil
|
||||
|
||||
return a.updateAllPages(state.StateUpdatedMsg{State: a.app.State})
|
||||
}
|
||||
|
||||
if parts[0] == "session" && parts[1] == "message" {
|
||||
|
@ -303,7 +304,7 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||
if m.Id == messageId {
|
||||
a.app.Messages[i] = message
|
||||
slog.Debug("Updated message", "message", message)
|
||||
return a, nil
|
||||
return a.updateAllPages(state.StateUpdatedMsg{State: a.app.State})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -316,7 +317,8 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||
// a.app.CurrentSession.Cost += message.Cost
|
||||
// a.app.CurrentSession.UpdatedAt = message.CreatedAt
|
||||
}
|
||||
return a, nil
|
||||
|
||||
return a.updateAllPages(state.StateUpdatedMsg{State: a.app.State})
|
||||
}
|
||||
|
||||
// log key and content
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue