diff options
| author | Dax Raad <[email protected]> | 2025-07-21 19:53:22 -0400 |
|---|---|---|
| committer | Dax Raad <[email protected]> | 2025-07-21 19:53:58 -0400 |
| commit | f20ef61bc72ad830549c8a885f063b47e4a75557 (patch) | |
| tree | 3232940032f5c8e2a25b036c0290b22dc407cb63 /packages/tui/internal | |
| parent | 5611ef8b28216aa9dd2ceb6ed17d5779a29154f6 (diff) | |
| download | opencode-f20ef61bc72ad830549c8a885f063b47e4a75557.tar.gz opencode-f20ef61bc72ad830549c8a885f063b47e4a75557.zip | |
wip: api for tui
Diffstat (limited to 'packages/tui/internal')
| -rw-r--r-- | packages/tui/internal/api/api.go | 41 | ||||
| -rw-r--r-- | packages/tui/internal/tui/tui.go | 40 |
2 files changed, 72 insertions, 9 deletions
diff --git a/packages/tui/internal/api/api.go b/packages/tui/internal/api/api.go new file mode 100644 index 000000000..b4d3adee2 --- /dev/null +++ b/packages/tui/internal/api/api.go @@ -0,0 +1,41 @@ +package api + +import ( + "context" + "encoding/json" + "log" + + tea "github.com/charmbracelet/bubbletea/v2" + "github.com/sst/opencode-sdk-go" +) + +type Request struct { + Path string `json:"path"` + Body json.RawMessage `json:"body"` +} + +func Start(ctx context.Context, program *tea.Program, client *opencode.Client) { + for { + select { + case <-ctx.Done(): + return + default: + var req Request + if err := client.Get(ctx, "/tui/control/next", nil, &req); err != nil { + log.Printf("Error getting next request: %v", err) + continue + } + program.Send(req) + } + } +} + +func Reply(ctx context.Context, client *opencode.Client, response interface{}) tea.Cmd { + return func() tea.Msg { + err := client.Post(ctx, "/tui/control/response", response, nil) + if err != nil { + return err + } + return nil + } +} diff --git a/packages/tui/internal/tui/tui.go b/packages/tui/internal/tui/tui.go index bd0eaeada..4e654c0c8 100644 --- a/packages/tui/internal/tui/tui.go +++ b/packages/tui/internal/tui/tui.go @@ -2,6 +2,7 @@ package tui import ( "context" + "encoding/json" "fmt" "log/slog" "os" @@ -15,6 +16,7 @@ import ( "github.com/charmbracelet/lipgloss/v2" "github.com/sst/opencode-sdk-go" + "github.com/sst/opencode/internal/api" "github.com/sst/opencode/internal/app" "github.com/sst/opencode/internal/commands" "github.com/sst/opencode/internal/completions" @@ -57,7 +59,7 @@ const ( const interruptDebounceTimeout = 1 * time.Second const exitDebounceTimeout = 1 * time.Second -type appModel struct { +type Model struct { width, height int app *app.App modal layout.Modal @@ -78,7 +80,7 @@ type appModel struct { fileViewer fileviewer.Model } -func (a appModel) Init() tea.Cmd { +func (a Model) Init() tea.Cmd { var cmds []tea.Cmd // https://github.com/charmbracelet/bubbletea/issues/1440 // https://github.com/sst/opencode/issues/127 @@ -102,7 +104,7 @@ func (a appModel) Init() tea.Cmd { return tea.Batch(cmds...) } -func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { +func (a Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { measure := util.Measure("app.Update") defer measure("from", fmt.Sprintf("%T", msg)) @@ -499,6 +501,26 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { a.editor.SetExitKeyInDebounce(false) case dialog.FindSelectedMsg: return a.openFile(msg.FilePath) + + // API + case api.Request: + slog.Info("api", "path", msg.Path) + var response any = true + switch msg.Path { + case "/tui/open-help": + helpDialog := dialog.NewHelpDialog(a.app) + a.modal = helpDialog + case "/tui/prompt": + var body struct { + Text string `json:"text"` + Parts []opencode.Part `json:"parts"` + } + json.Unmarshal((msg.Body), &body) + a.editor.SetValue(body.Text) + default: + break + } + cmds = append(cmds, api.Reply(context.Background(), a.app.Client, response)) } s, cmd := a.status.Update(msg) @@ -532,7 +554,7 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return a, tea.Batch(cmds...) } -func (a appModel) View() string { +func (a Model) View() string { measure := util.Measure("app.View") defer measure() t := theme.CurrentTheme() @@ -569,7 +591,7 @@ func (a appModel) View() string { return mainLayout + "\n" + a.status.View() } -func (a appModel) openFile(filepath string) (tea.Model, tea.Cmd) { +func (a Model) openFile(filepath string) (tea.Model, tea.Cmd) { var cmd tea.Cmd response, err := a.app.Client.File.Read( context.Background(), @@ -589,7 +611,7 @@ func (a appModel) openFile(filepath string) (tea.Model, tea.Cmd) { return a, cmd } -func (a appModel) home() string { +func (a Model) home() string { measure := util.Measure("home.View") defer measure() t := theme.CurrentTheme() @@ -726,7 +748,7 @@ func (a appModel) home() string { return mainLayout } -func (a appModel) chat() string { +func (a Model) chat() string { measure := util.Measure("chat.View") defer measure() effectiveWidth := a.width - 4 @@ -774,7 +796,7 @@ func (a appModel) chat() string { return mainLayout } -func (a appModel) executeCommand(command commands.Command) (tea.Model, tea.Cmd) { +func (a Model) executeCommand(command commands.Command) (tea.Model, tea.Cmd) { var cmd tea.Cmd cmds := []tea.Cmd{ util.CmdHandler(commands.CommandExecutedMsg(command)), @@ -1057,7 +1079,7 @@ func NewModel(app *app.App) tea.Model { leaderBinding = &binding } - model := &appModel{ + model := &Model{ status: status.NewStatusCmp(app), app: app, editor: editor, |
