@@ -2,48 +2,6 @@ package chat
3import "github.com/charmbracelet/bubbles/v2/key"
3import "github.com/charmbracelet/bubbles/v2/key"
11−// "github.com/charmbracelet/bubbles/v2/key"
12−// "github.com/charmbracelet/bubbles/v2/spinner"
13−// "github.com/charmbracelet/bubbles/v2/viewport"
14−// tea "github.com/charmbracelet/bubbletea/v2"
15−// "github.com/charmbracelet/lipgloss/v2"
16−// "github.com/opencode-ai/opencode/internal/app"
17−// "github.com/opencode-ai/opencode/internal/message"
18−// "github.com/opencode-ai/opencode/internal/pubsub"
19−// "github.com/opencode-ai/opencode/internal/session"
20−// "github.com/opencode-ai/opencode/internal/tui/components/dialog"
21−// "github.com/opencode-ai/opencode/internal/tui/styles"
22−// "github.com/opencode-ai/opencode/internal/tui/theme"
23−// "github.com/opencode-ai/opencode/internal/tui/util"
27−// type cacheItem struct {
29−// content []uiMessage
32−// type messagesCmp struct {
35−// viewport viewport.Model
36−// session session.Session
37−// messages []message.Message
38−// uiMessages []uiMessage
39−// currentMsgID string
40−// cachedContent map[string]cacheItem
41−// spinner spinner.Model
43−// attachments viewport.Model
46−// type renderFinishedMsg struct{}
47type MessageKeys struct {
5type MessageKeys struct {
48 PageDown key.Binding
6 PageDown key.Binding
49 PageUp key.Binding
7 PageUp key.Binding
@@ -69,412 +27,3 @@ var messageKeys = MessageKeys{
69 key.WithHelp("ctrl+d", "½ page down"),
27 key.WithHelp("ctrl+d", "½ page down"),
74−// func (m *messagesCmp) Init() tea.Cmd {
75−// return tea.Batch(m.viewport.Init(), m.spinner.Tick)
78−// func (m *messagesCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
80−// switch msg := msg.(type) {
81−// case dialog.ThemeChangedMsg:
84−// case SessionSelectedMsg:
85−// if msg.ID != m.session.ID {
86−// cmd := m.SetSession(msg)
90−// case SessionClearedMsg:
91−// m.session = session.Session{}
92−// m.messages = make([]message.Message, 0)
93−// m.currentMsgID = ""
94−// m.rendering = false
98−// if key.Matches(msg, messageKeys.PageUp) || key.Matches(msg, messageKeys.PageDown) ||
99−// key.Matches(msg, messageKeys.HalfPageUp) || key.Matches(msg, messageKeys.HalfPageDown) {
100−// u, cmd := m.viewport.Update(msg)
102−// cmds = append(cmds, cmd)
105−// case renderFinishedMsg:
106−// m.rendering = false
107−// m.viewport.GotoBottom()
108−// case pubsub.Event[session.Session]:
109−// if msg.Type == pubsub.UpdatedEvent && msg.Payload.ID == m.session.ID {
110−// m.session = msg.Payload
111−// if m.session.SummaryMessageID == m.currentMsgID {
112−// delete(m.cachedContent, m.currentMsgID)
116−// case pubsub.Event[message.Message]:
117−// needsRerender := false
118−// if msg.Type == pubsub.CreatedEvent {
119−// if msg.Payload.SessionID == m.session.ID {
121−// messageExists := false
122−// for _, v := range m.messages {
123−// if v.ID == msg.Payload.ID {
124−// messageExists = true
129−// if !messageExists {
130−// if len(m.messages) > 0 {
131−// lastMsgID := m.messages[len(m.messages)-1].ID
132−// delete(m.cachedContent, lastMsgID)
135−// m.messages = append(m.messages, msg.Payload)
136−// delete(m.cachedContent, m.currentMsgID)
137−// m.currentMsgID = msg.Payload.ID
138−// needsRerender = true
141−// // There are tool calls from the child task
142−// for _, v := range m.messages {
143−// for _, c := range v.ToolCalls() {
144−// if c.ID == msg.Payload.SessionID {
145−// delete(m.cachedContent, v.ID)
146−// needsRerender = true
150−// } else if msg.Type == pubsub.UpdatedEvent && msg.Payload.SessionID == m.session.ID {
151−// for i, v := range m.messages {
152−// if v.ID == msg.Payload.ID {
153−// m.messages[i] = msg.Payload
154−// delete(m.cachedContent, msg.Payload.ID)
155−// needsRerender = true
160−// if needsRerender {
162−// if len(m.messages) > 0 {
163−// if (msg.Type == pubsub.CreatedEvent) ||
164−// (msg.Type == pubsub.UpdatedEvent && msg.Payload.ID == m.messages[len(m.messages)-1].ID) {
165−// m.viewport.GotoBottom()
171−// spinner, cmd := m.spinner.Update(msg)
172−// m.spinner = spinner
173−// cmds = append(cmds, cmd)
174−// return m, tea.Batch(cmds...)
177−// func (m *messagesCmp) IsAgentWorking() bool {
178−// return m.app.CoderAgent.IsSessionBusy(m.session.ID)
181−// func formatTimeDifference(unixTime1, unixTime2 int64) string {
182−// diffSeconds := float64(math.Abs(float64(unixTime2 - unixTime1)))
184−// if diffSeconds < 60 {
185−// return fmt.Sprintf("%.1fs", diffSeconds)
188−// minutes := int(diffSeconds / 60)
189−// seconds := int(diffSeconds) % 60
190−// return fmt.Sprintf("%dm%ds", minutes, seconds)
193−// func (m *messagesCmp) renderView() {
194−// m.uiMessages = make([]uiMessage, 0)
196−// baseStyle := styles.BaseStyle()
201−// for inx, msg := range m.messages {
203−// case message.User:
204−// if cache, ok := m.cachedContent[msg.ID]; ok && cache.width == m.width {
205−// m.uiMessages = append(m.uiMessages, cache.content...)
208−// userMsg := renderUserMessage(
210−// msg.ID == m.currentMsgID,
214−// m.uiMessages = append(m.uiMessages, userMsg)
215−// m.cachedContent[msg.ID] = cacheItem{
217−// content: []uiMessage{userMsg},
219−// pos += userMsg.height + 1 // + 1 for spacing
220−// case message.Assistant:
221−// if cache, ok := m.cachedContent[msg.ID]; ok && cache.width == m.width {
222−// m.uiMessages = append(m.uiMessages, cache.content...)
225−// isSummary := m.session.SummaryMessageID == msg.ID
227−// assistantMessages := renderAssistantMessage(
237−// for _, msg := range assistantMessages {
238−// m.uiMessages = append(m.uiMessages, msg)
239−// pos += msg.height + 1 // + 1 for spacing
241−// m.cachedContent[msg.ID] = cacheItem{
243−// content: assistantMessages,
248−// messages := make([]string, 0)
249−// for _, v := range m.uiMessages {
250−// messages = append(messages, lipgloss.JoinVertical(lipgloss.Left, v.content),
259−// m.viewport.SetContent(
263−// lipgloss.JoinVertical(
271−// func (m *messagesCmp) View() string {
272−// baseStyle := styles.BaseStyle()
278−// lipgloss.JoinVertical(
286−// if len(m.messages) == 0 {
287−// content := baseStyle.
289−// Height(m.height - 1).
297−// lipgloss.JoinVertical(
309−// lipgloss.JoinVertical(
311−// m.viewport.View(),
318−// func hasToolsWithoutResponse(messages []message.Message) bool {
319−// toolCalls := make([]message.ToolCall, 0)
320−// toolResults := make([]message.ToolResult, 0)
321−// for _, m := range messages {
322−// toolCalls = append(toolCalls, m.ToolCalls()...)
323−// toolResults = append(toolResults, m.ToolResults()...)
326−// for _, v := range toolCalls {
328−// for _, r := range toolResults {
329−// if v.ID == r.ToolCallID {
334−// if !found && v.Finished {
341−// func hasUnfinishedToolCalls(messages []message.Message) bool {
342−// toolCalls := make([]message.ToolCall, 0)
343−// for _, m := range messages {
344−// toolCalls = append(toolCalls, m.ToolCalls()...)
346−// for _, v := range toolCalls {
354−// func (m *messagesCmp) working() string {
356−// if m.IsAgentWorking() && len(m.messages) > 0 {
357−// t := theme.CurrentTheme()
358−// baseStyle := styles.BaseStyle()
360−// task := "Thinking..."
361−// lastMessage := m.messages[len(m.messages)-1]
362−// if hasToolsWithoutResponse(m.messages) {
363−// task = "Waiting for tool response..."
364−// } else if hasUnfinishedToolCalls(m.messages) {
365−// task = "Building tool call..."
366−// } else if !lastMessage.IsFinished() {
367−// task = "Generating..."
370−// text += baseStyle.
372−// Foreground(t.Primary()).
374−// Render(fmt.Sprintf("%s %s ", m.spinner.View(), task))
380−// func (m *messagesCmp) help() string {
381−// t := theme.CurrentTheme()
382−// baseStyle := styles.BaseStyle()
386−// if m.app.CoderAgent.IsBusy() {
387−// text += lipgloss.JoinHorizontal(
389−// baseStyle.Foreground(t.TextMuted()).Bold(true).Render("press "),
390−// baseStyle.Foreground(t.Text()).Bold(true).Render("esc"),
391−// baseStyle.Foreground(t.TextMuted()).Bold(true).Render(" to exit cancel"),
394−// text += lipgloss.JoinHorizontal(
396−// baseStyle.Foreground(t.TextMuted()).Bold(true).Render("press "),
397−// baseStyle.Foreground(t.Text()).Bold(true).Render("enter"),
398−// baseStyle.Foreground(t.TextMuted()).Bold(true).Render(" to send the message,"),
399−// baseStyle.Foreground(t.TextMuted()).Bold(true).Render(" write"),
400−// baseStyle.Foreground(t.Text()).Bold(true).Render(" \\"),
401−// baseStyle.Foreground(t.TextMuted()).Bold(true).Render(" and enter to add a new line"),
409−// func (m *messagesCmp) rerender() {
410−// for _, msg := range m.messages {
411−// delete(m.cachedContent, msg.ID)
416−// func (m *messagesCmp) SetSize(width, height int) tea.Cmd {
417−// if m.width == width && m.height == height {
422−// m.viewport.SetWidth(width)
423−// m.viewport.SetHeight(height - 2)
424−// m.attachments.SetWidth(width + 40)
425−// m.attachments.SetHeight(3)
430−// func (m *messagesCmp) GetSize() (int, int) {
431−// return m.width, m.height
434−// func (m *messagesCmp) SetSession(session session.Session) tea.Cmd {
435−// if m.session.ID == session.ID {
438−// m.session = session
439−// messages, err := m.app.Messages.List(context.Background(), session.ID)
441−// return util.ReportError(err)
443−// m.messages = messages
444−// if len(m.messages) > 0 {
445−// m.currentMsgID = m.messages[len(m.messages)-1].ID
447−// delete(m.cachedContent, m.currentMsgID)
448−// m.rendering = true
449−// return func() tea.Msg {
451−// return renderFinishedMsg{}
455−// func (m *messagesCmp) BindingKeys() []key.Binding {
456−// return []key.Binding{
457−// m.viewport.KeyMap.PageDown,
458−// m.viewport.KeyMap.PageUp,
459−// m.viewport.KeyMap.HalfPageUp,
460−// m.viewport.KeyMap.HalfPageDown,
464−// func NewMessagesCmp(app *app.App) util.Model {
465−// s := spinner.New()
466−// s.Spinner = spinner.Pulse
467−// vp := viewport.New()
468−// attachmets := viewport.New()
469−// vp.KeyMap.PageUp = messageKeys.PageUp
470−// vp.KeyMap.PageDown = messageKeys.PageDown
471−// vp.KeyMap.HalfPageUp = messageKeys.HalfPageUp
472−// vp.KeyMap.HalfPageDown = messageKeys.HalfPageDown
473−// return &messagesCmp{
475−// cachedContent: make(map[string]cacheItem),
478−// attachments: attachmets,