summaryrefslogtreecommitdiffhomepage
path: root/internal/tui
diff options
context:
space:
mode:
authoradamdottv <[email protected]>2025-05-28 10:12:08 -0500
committeradamdottv <[email protected]>2025-05-28 15:36:35 -0500
commit5e738ce7d3b66b88a407a1bcc53a5169d0f4a904 (patch)
tree5c7a6ac13ebb60946e7c88f7d0e04df766edf94a /internal/tui
parent641e9ff6642ef7b55928ef235f54d53822045baf (diff)
downloadopencode-5e738ce7d3b66b88a407a1bcc53a5169d0f4a904.tar.gz
opencode-5e738ce7d3b66b88a407a1bcc53a5169d0f4a904.zip
wip: refactoring tui
Diffstat (limited to 'internal/tui')
-rw-r--r--internal/tui/components/chat/messages.go50
-rw-r--r--internal/tui/components/chat/sidebar.go61
-rw-r--r--internal/tui/components/logs/table.go13
-rw-r--r--internal/tui/tui.go63
4 files changed, 134 insertions, 53 deletions
diff --git a/internal/tui/components/chat/messages.go b/internal/tui/components/chat/messages.go
index d6f252aad..613c4169a 100644
--- a/internal/tui/components/chat/messages.go
+++ b/internal/tui/components/chat/messages.go
@@ -4,6 +4,7 @@ import (
"context"
"fmt"
"math"
+ "strings"
"time"
"github.com/charmbracelet/bubbles/key"
@@ -155,6 +156,55 @@ func (m *messagesCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
}
}
}
+ case app.StorageWriteMsg:
+ // Handle storage write events from the TypeScript backend
+ keyParts := strings.Split(msg.Key, "/")
+ if len(keyParts) >= 4 && keyParts[0] == "session" && keyParts[1] == "message" {
+ sessionID := keyParts[2]
+ if sessionID == m.app.CurrentSession.ID {
+ // Convert storage message to internal format
+ convertedMsg, err := app.ConvertStorageMessage(msg.Content, sessionID)
+ if err != nil {
+ status.Error("Failed to convert message: " + err.Error())
+ return m, nil
+ }
+
+ // Check if message exists
+ messageExists := false
+ messageIndex := -1
+ for i, v := range m.messages {
+ if v.ID == convertedMsg.ID {
+ messageExists = true
+ messageIndex = i
+ break
+ }
+ }
+
+ needsRerender := false
+ if messageExists {
+ // Update existing message
+ m.messages[messageIndex] = *convertedMsg
+ delete(m.cachedContent, convertedMsg.ID)
+ needsRerender = true
+ } else {
+ // Add new message
+ if len(m.messages) > 0 {
+ lastMsgID := m.messages[len(m.messages)-1].ID
+ delete(m.cachedContent, lastMsgID)
+ }
+
+ m.messages = append(m.messages, *convertedMsg)
+ delete(m.cachedContent, m.currentMsgID)
+ m.currentMsgID = convertedMsg.ID
+ needsRerender = true
+ }
+
+ if needsRerender {
+ m.renderView()
+ m.viewport.GotoBottom()
+ }
+ }
+ }
}
spinner, cmd := m.spinner.Update(msg)
diff --git a/internal/tui/components/chat/sidebar.go b/internal/tui/components/chat/sidebar.go
index 973b03ef1..c2b392c24 100644
--- a/internal/tui/components/chat/sidebar.go
+++ b/internal/tui/components/chat/sidebar.go
@@ -10,7 +10,7 @@ import (
"github.com/charmbracelet/lipgloss"
"github.com/sst/opencode/internal/app"
"github.com/sst/opencode/internal/config"
- "github.com/sst/opencode/internal/diff"
+ // "github.com/sst/opencode/internal/diff"
"github.com/sst/opencode/internal/history"
"github.com/sst/opencode/internal/pubsub"
"github.com/sst/opencode/internal/tui/state"
@@ -28,39 +28,28 @@ type sidebarCmp struct {
}
func (m *sidebarCmp) Init() tea.Cmd {
- if m.app.History != nil {
- ctx := context.Background()
- // Subscribe to file events
- filesCh := m.app.History.Subscribe(ctx)
-
- // Initialize the modified files map
- m.modFiles = make(map[string]struct {
- additions int
- removals int
- })
-
- // Load initial files and calculate diffs
- m.loadModifiedFiles(ctx)
-
- // Return a command that will send file events to the Update method
- return func() tea.Msg {
- return <-filesCh
- }
- }
+ // TODO: History service not implemented in API yet
+ // Initialize the modified files map
+ m.modFiles = make(map[string]struct {
+ additions int
+ removals int
+ })
return nil
}
func (m *sidebarCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
- switch msg := msg.(type) {
+ switch msg.(type) {
case state.SessionSelectedMsg:
- ctx := context.Background()
- m.loadModifiedFiles(ctx)
+ // TODO: History service not implemented in API yet
+ // ctx := context.Background()
+ // m.loadModifiedFiles(ctx)
case pubsub.Event[history.File]:
- if msg.Payload.SessionID == m.app.CurrentSession.ID {
- // Process the individual file change instead of reloading all files
- ctx := context.Background()
- m.processFileChanges(ctx, msg.Payload)
- }
+ // TODO: History service not implemented in API yet
+ // if msg.Payload.SessionID == m.app.CurrentSession.ID {
+ // // Process the individual file change instead of reloading all files
+ // ctx := context.Background()
+ // m.processFileChanges(ctx, msg.Payload)
+ // }
}
return m, nil
}
@@ -224,6 +213,9 @@ func (m *sidebarCmp) loadModifiedFiles(ctx context.Context) {
return
}
+ // TODO: History service not implemented in API yet
+ return
+ /*
// Get all latest files for this session
latestFiles, err := m.app.History.ListLatestSessionFiles(ctx, m.app.CurrentSession.ID)
if err != nil {
@@ -235,6 +227,7 @@ func (m *sidebarCmp) loadModifiedFiles(ctx context.Context) {
if err != nil {
return
}
+ */
// Clear the existing map to rebuild it
m.modFiles = make(map[string]struct {
@@ -242,6 +235,7 @@ func (m *sidebarCmp) loadModifiedFiles(ctx context.Context) {
removals int
})
+ /*
// Process each latest file
for _, file := range latestFiles {
// Skip if this is the initial version (no changes to show)
@@ -286,9 +280,13 @@ func (m *sidebarCmp) loadModifiedFiles(ctx context.Context) {
}
}
}
+ */
}
func (m *sidebarCmp) processFileChanges(ctx context.Context, file history.File) {
+ // TODO: History service not implemented in API yet
+ return
+ /*
// Skip if this is the initial version (no changes to show)
if file.Version == history.InitialVersion {
return
@@ -327,16 +325,22 @@ func (m *sidebarCmp) processFileChanges(ctx context.Context, file history.File)
displayPath := getDisplayPath(file.Path)
delete(m.modFiles, displayPath)
}
+ */
}
// Helper function to find the initial version of a file
func (m *sidebarCmp) findInitialVersion(ctx context.Context, path string) (history.File, error) {
+ // TODO: History service not implemented in API yet
+ return history.File{}, fmt.Errorf("history service not implemented")
+ /*
// Get all versions of this file for the session
fileVersions, err := m.app.History.ListBySession(ctx, m.app.CurrentSession.ID)
if err != nil {
return history.File{}, err
}
+ */
+ /*
// Find the initial version
for _, v := range fileVersions {
if v.Path == path && v.Version == history.InitialVersion {
@@ -345,6 +349,7 @@ func (m *sidebarCmp) findInitialVersion(ctx context.Context, path string) (histo
}
return history.File{}, fmt.Errorf("initial version not found")
+ */
}
// Helper function to get the display path for a file
diff --git a/internal/tui/components/logs/table.go b/internal/tui/components/logs/table.go
index e85009205..1fc1daa38 100644
--- a/internal/tui/components/logs/table.go
+++ b/internal/tui/components/logs/table.go
@@ -1,7 +1,8 @@
package logs
import (
- "context"
+ // "context"
+ "fmt"
"log/slog"
"github.com/charmbracelet/bubbles/key"
@@ -41,18 +42,16 @@ func (i *tableCmp) Init() tea.Cmd {
func (i *tableCmp) fetchLogs() tea.Cmd {
return func() tea.Msg {
- ctx := context.Background()
+ // ctx := context.Background()
var logs []logging.Log
var err error
// Limit the number of logs to improve performance
const logLimit = 100
- if i.app.CurrentSession.ID == "" {
- logs, err = i.app.Logs.ListAll(ctx, logLimit)
- } else {
- logs, err = i.app.Logs.ListBySession(ctx, i.app.CurrentSession.ID)
- }
+ // TODO: Logs service not implemented in API yet
+ logs = []logging.Log{}
+ err = fmt.Errorf("logs service not implemented")
if err != nil {
slog.Error("Failed to fetch logs", "error", err)
diff --git a/internal/tui/tui.go b/internal/tui/tui.go
index ebed1182a..ed3a94f76 100644
--- a/internal/tui/tui.go
+++ b/internal/tui/tui.go
@@ -2,7 +2,7 @@ package tui
import (
"context"
- "fmt"
+ // "fmt"
"log/slog"
"strings"
@@ -13,7 +13,7 @@ import (
"github.com/charmbracelet/lipgloss"
"github.com/sst/opencode/internal/app"
"github.com/sst/opencode/internal/config"
- "github.com/sst/opencode/internal/llm/agent"
+ // "github.com/sst/opencode/internal/llm/agent"
"github.com/sst/opencode/internal/logging"
"github.com/sst/opencode/internal/message"
"github.com/sst/opencode/internal/permission"
@@ -28,6 +28,7 @@ import (
"github.com/sst/opencode/internal/tui/page"
"github.com/sst/opencode/internal/tui/state"
"github.com/sst/opencode/internal/tui/util"
+ "github.com/sst/opencode/pkg/client"
)
type keyMap struct {
@@ -251,17 +252,18 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
a.showPermissions = true
return a, a.permissions.SetPermissions(msg.Payload)
case dialog.PermissionResponseMsg:
- var cmd tea.Cmd
- switch msg.Action {
- case dialog.PermissionAllow:
- a.app.Permissions.Grant(context.Background(), msg.Permission)
- case dialog.PermissionAllowForSession:
- a.app.Permissions.GrantPersistant(context.Background(), msg.Permission)
- case dialog.PermissionDeny:
- a.app.Permissions.Deny(context.Background(), msg.Permission)
- }
+ // TODO: Permissions service not implemented in API yet
+ // var cmd tea.Cmd
+ // switch msg.Action {
+ // case dialog.PermissionAllow:
+ // a.app.Permissions.Grant(context.Background(), msg.Permission)
+ // case dialog.PermissionAllowForSession:
+ // a.app.Permissions.GrantPersistant(context.Background(), msg.Permission)
+ // case dialog.PermissionDeny:
+ // a.app.Permissions.Deny(context.Background(), msg.Permission)
+ // }
a.showPermissions = false
- return a, cmd
+ return a, nil
case page.PageChangeMsg:
return a, a.moveToPage(msg.ID)
@@ -280,6 +282,25 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
a.app.CurrentSession = &msg.Payload
}
}
+
+ // Handle SSE events from the TypeScript backend
+ case *client.EventStorageWrite:
+ // Process storage write events
+ processedMsg := app.ProcessSSEEvent(msg)
+ if storageMsg, ok := processedMsg.(app.StorageWriteMsg); ok {
+ // Forward to the appropriate page/component based on key
+ keyParts := strings.Split(storageMsg.Key, "/")
+ if len(keyParts) >= 3 && keyParts[0] == "session" {
+ if keyParts[1] == "message" {
+ // This is a message update, forward to the chat page
+ return a.updateAllPages(storageMsg)
+ } else if keyParts[1] == "info" {
+ // This is a session info update
+ return a.updateAllPages(storageMsg)
+ }
+ }
+ }
+ return a, nil
case dialog.CloseQuitMsg:
a.showQuit = false
@@ -321,13 +342,15 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
case dialog.ModelSelectedMsg:
a.showModelDialog = false
- model, err := a.app.PrimaryAgent.Update(config.AgentPrimary, msg.Model.ID)
- if err != nil {
- status.Error(err.Error())
- return a, nil
- }
+ // TODO: Agent model update not implemented in API yet
+ // model, err := a.app.PrimaryAgent.Update(config.AgentPrimary, msg.Model.ID)
+ // if err != nil {
+ // status.Error(err.Error())
+ // return a, nil
+ // }
- status.Info(fmt.Sprintf("Model changed to %s", model.Name))
+ // status.Info(fmt.Sprintf("Model changed to %s", model.Name))
+ status.Info("Model selection not implemented in API yet")
return a, nil
case dialog.ShowInitDialogMsg:
@@ -707,6 +730,9 @@ func (a *appModel) RegisterCommand(cmd dialog.Command) {
// getAvailableToolNames returns a list of all available tool names
func getAvailableToolNames(app *app.App) []string {
+ // TODO: Tools not implemented in API yet
+ return []string{"Tools not available in API mode"}
+ /*
// Get primary agent tools (which already include MCP tools)
allTools := agent.PrimaryAgentTools(
app.Permissions,
@@ -723,6 +749,7 @@ func getAvailableToolNames(app *app.App) []string {
}
return toolNames
+ */
}
func (a *appModel) moveToPage(pageID page.PageID) tea.Cmd {