summaryrefslogtreecommitdiffhomepage
path: root/internal/tui/tui.go
diff options
context:
space:
mode:
authorKujtim Hoxha <[email protected]>2025-04-18 20:17:38 +0200
committerKujtim Hoxha <[email protected]>2025-04-21 13:42:27 +0200
commit333ea6ec4b2abfc2c1a9c3f6b0918ca5d296347f (patch)
treee0d456417368e8716c81ee43b82be3d6ed39c59e /internal/tui/tui.go
parent05d0e86f10369fd0e51a924ac88029fb92591499 (diff)
downloadopencode-333ea6ec4b2abfc2c1a9c3f6b0918ca5d296347f.tar.gz
opencode-333ea6ec4b2abfc2c1a9c3f6b0918ca5d296347f.zip
implement patch, update ui, improve rendering
Diffstat (limited to 'internal/tui/tui.go')
-rw-r--r--internal/tui/tui.go111
1 files changed, 95 insertions, 16 deletions
diff --git a/internal/tui/tui.go b/internal/tui/tui.go
index 840ad4905..f3a7298cf 100644
--- a/internal/tui/tui.go
+++ b/internal/tui/tui.go
@@ -1,6 +1,8 @@
package tui
import (
+ "context"
+
"github.com/charmbracelet/bubbles/key"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
@@ -8,6 +10,7 @@ import (
"github.com/kujtimiihoxha/opencode/internal/logging"
"github.com/kujtimiihoxha/opencode/internal/permission"
"github.com/kujtimiihoxha/opencode/internal/pubsub"
+ "github.com/kujtimiihoxha/opencode/internal/tui/components/chat"
"github.com/kujtimiihoxha/opencode/internal/tui/components/core"
"github.com/kujtimiihoxha/opencode/internal/tui/components/dialog"
"github.com/kujtimiihoxha/opencode/internal/tui/layout"
@@ -16,9 +19,10 @@ import (
)
type keyMap struct {
- Logs key.Binding
- Quit key.Binding
- Help key.Binding
+ Logs key.Binding
+ Quit key.Binding
+ Help key.Binding
+ SwitchSession key.Binding
}
var keys = keyMap{
@@ -35,6 +39,10 @@ var keys = keyMap{
key.WithKeys("ctrl+_"),
key.WithHelp("ctrl+?", "toggle help"),
),
+ SwitchSession: key.NewBinding(
+ key.WithKeys("ctrl+a"),
+ key.WithHelp("ctrl+a", "switch session"),
+ ),
}
var returnKey = key.NewBinding(
@@ -64,6 +72,9 @@ type appModel struct {
showQuit bool
quit dialog.QuitDialog
+
+ showSessionDialog bool
+ sessionDialog dialog.SessionDialog
}
func (a appModel) Init() tea.Cmd {
@@ -77,6 +88,8 @@ func (a appModel) Init() tea.Cmd {
cmds = append(cmds, cmd)
cmd = a.help.Init()
cmds = append(cmds, cmd)
+ cmd = a.sessionDialog.Init()
+ cmds = append(cmds, cmd)
return tea.Batch(cmds...)
}
@@ -100,6 +113,10 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
a.help = help.(dialog.HelpCmp)
cmds = append(cmds, helpCmd)
+ session, sessionCmd := a.sessionDialog.Update(msg)
+ a.sessionDialog = session.(dialog.SessionDialog)
+ cmds = append(cmds, sessionCmd)
+
return a, tea.Batch(cmds...)
// Status
@@ -144,8 +161,7 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
// Permission
case pubsub.Event[permission.PermissionRequest]:
a.showPermissions = true
- a.permissions.SetPermissions(msg.Payload)
- return a, nil
+ return a, a.permissions.SetPermissions(msg.Payload)
case dialog.PermissionResponseMsg:
switch msg.Action {
case dialog.PermissionAllow:
@@ -165,6 +181,19 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
a.showQuit = false
return a, nil
+ case dialog.CloseSessionDialogMsg:
+ a.showSessionDialog = false
+ return a, nil
+
+ case chat.SessionSelectedMsg:
+ a.sessionDialog.SetSelectedSession(msg.ID)
+ case dialog.SessionSelectedMsg:
+ a.showSessionDialog = false
+ if a.currentPage == page.ChatPage {
+ return a, util.CmdHandler(chat.SessionSelectedMsg(msg.Session))
+ }
+ return a, nil
+
case tea.KeyMsg:
switch {
case key.Matches(msg, keys.Quit):
@@ -172,6 +201,24 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
if a.showHelp {
a.showHelp = false
}
+ if a.showSessionDialog {
+ a.showSessionDialog = false
+ }
+ return a, nil
+ case key.Matches(msg, keys.SwitchSession):
+ if a.currentPage == page.ChatPage && !a.showQuit && !a.showPermissions {
+ // Load sessions and show the dialog
+ sessions, err := a.app.Sessions.List(context.Background())
+ if err != nil {
+ return a, util.ReportError(err)
+ }
+ if len(sessions) == 0 {
+ return a, util.ReportWarn("No sessions available")
+ }
+ a.sessionDialog.SetSessions(sessions)
+ a.showSessionDialog = true
+ return a, nil
+ }
return a, nil
case key.Matches(msg, logsKeyReturnKey):
if a.currentPage == page.LogsPage {
@@ -216,6 +263,16 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
}
}
+ if a.showSessionDialog {
+ d, sessionCmd := a.sessionDialog.Update(msg)
+ a.sessionDialog = d.(dialog.SessionDialog)
+ cmds = append(cmds, sessionCmd)
+ // Only block key messages send all other messages down
+ if _, ok := msg.(tea.KeyMsg); ok {
+ return a, tea.Batch(cmds...)
+ }
+ }
+
a.status, _ = a.status.Update(msg)
a.pages[a.currentPage], cmd = a.pages[a.currentPage].Update(msg)
cmds = append(cmds, cmd)
@@ -223,18 +280,24 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
}
func (a *appModel) moveToPage(pageID page.PageID) tea.Cmd {
- var cmd tea.Cmd
+ if a.app.CoderAgent.IsBusy() {
+ // For now we don't move to any page if the agent is busy
+ return util.ReportWarn("Agent is busy, please wait...")
+ }
+ var cmds []tea.Cmd
if _, ok := a.loadedPages[pageID]; !ok {
- cmd = a.pages[pageID].Init()
+ cmd := a.pages[pageID].Init()
+ cmds = append(cmds, cmd)
a.loadedPages[pageID] = true
}
a.previousPage = a.currentPage
a.currentPage = pageID
if sizable, ok := a.pages[a.currentPage].(layout.Sizeable); ok {
- sizable.SetSize(a.width, a.height)
+ cmd := sizable.SetSize(a.width, a.height)
+ cmds = append(cmds, cmd)
}
- return cmd
+ return tea.Batch(cmds...)
}
func (a appModel) View() string {
@@ -304,19 +367,35 @@ func (a appModel) View() string {
)
}
+ if a.showSessionDialog {
+ overlay := a.sessionDialog.View()
+ row := lipgloss.Height(appView) / 2
+ row -= lipgloss.Height(overlay) / 2
+ col := lipgloss.Width(appView) / 2
+ col -= lipgloss.Width(overlay) / 2
+ appView = layout.PlaceOverlay(
+ col,
+ row,
+ overlay,
+ appView,
+ true,
+ )
+ }
+
return appView
}
func New(app *app.App) tea.Model {
startPage := page.ChatPage
return &appModel{
- currentPage: startPage,
- loadedPages: make(map[page.PageID]bool),
- status: core.NewStatusCmp(app.LSPClients),
- help: dialog.NewHelpCmp(),
- quit: dialog.NewQuitCmp(),
- permissions: dialog.NewPermissionDialogCmp(),
- app: app,
+ currentPage: startPage,
+ loadedPages: make(map[page.PageID]bool),
+ status: core.NewStatusCmp(app.LSPClients),
+ help: dialog.NewHelpCmp(),
+ quit: dialog.NewQuitCmp(),
+ sessionDialog: dialog.NewSessionDialogCmp(),
+ permissions: dialog.NewPermissionDialogCmp(),
+ app: app,
pages: map[page.PageID]tea.Model{
page.ChatPage: page.NewChatPage(app),
page.LogsPage: page.NewLogsPage(),