Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 31 additions & 8 deletions packages/tui/internal/tui/tui.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ import (
// InterruptDebounceTimeoutMsg is sent when the interrupt key debounce timeout expires
type InterruptDebounceTimeoutMsg struct{}

// EditorSuccessMsg is sent when the external editor succeeds and we should clear textarea and send the message
type EditorSuccessMsg struct {
Text string
Attachments []opencode.FilePartParam
}

// InterruptKeyState tracks the state of interrupt key presses for debouncing
type InterruptKeyState int

Expand Down Expand Up @@ -486,6 +492,12 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
// Reset interrupt key state after timeout
a.interruptKeyState = InterruptKeyIdle
a.editor.SetInterruptKeyInDebounce(false)
case EditorSuccessMsg:
// Clear the textarea and send the message when editor succeeds
updated, cmd := a.editor.Clear()
a.editor = updated.(chat.EditorComponent)
cmds = append(cmds, cmd)
cmds = append(cmds, util.CmdHandler(app.SendMsg{Text: msg.Text, Attachments: msg.Attachments}))
case dialog.FindSelectedMsg:
return a.openFile(msg.FilePath)
}
Expand Down Expand Up @@ -773,9 +785,6 @@ func (a appModel) executeCommand(command commands.Command) (tea.Model, tea.Cmd)
}

value := a.editor.Value()
updated, cmd := a.editor.Clear()
a.editor = updated.(chat.EditorComponent)
cmds = append(cmds, cmd)

tmpfile, err := os.CreateTemp("", "msg_*.md")
tmpfile.WriteString(value)
Expand All @@ -789,22 +798,36 @@ func (a appModel) executeCommand(command commands.Command) (tea.Model, tea.Cmd)
c.Stdout = os.Stdout
c.Stderr = os.Stderr
cmd = tea.ExecProcess(c, func(err error) tea.Msg {
defer os.Remove(tmpfile.Name())

// Check if the process exited with non-zero status
if err != nil {
slog.Error("Failed to open editor", "error", err)
return nil
if exitError, ok := err.(*exec.ExitError); ok {
slog.Warn("Editor exited with non-zero status", "exitCode", exitError.ExitCode())
// Don't clear textarea on failure
return nil
} else {
slog.Error("Failed to open editor", "error", err)
// Don't clear textarea on failure
return nil
}
}

content, err := os.ReadFile(tmpfile.Name())
if err != nil {
slog.Error("Failed to read file", "error", err)
// Don't clear textarea on failure
return nil
}
if len(content) == 0 {
slog.Warn("Message is empty")
// Don't clear textarea on failure
return nil
}
os.Remove(tmpfile.Name())
return app.SendMsg{
Text: string(content),
// Only clear and send if everything succeeded
return EditorSuccessMsg{
Text: string(content),
Attachments: []opencode.FilePartParam{}, // attachments,
}
})
cmds = append(cmds, cmd)
Expand Down