summaryrefslogtreecommitdiff
path: root/internal
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-06-22 14:25:14 +0300
committerPaul Buetow <paul@buetow.org>2026-06-22 14:25:14 +0300
commita1407cd9c960da7cb7e13b37ec444590319b8908 (patch)
tree007b9f796e05c0043292afedb89c8b6c6f723bd0 /internal
parent6fafae88fd8cfcb972c1ed98d8eb591a910043d2 (diff)
Fix description editor ExecProcess flow for nq0
Diffstat (limited to 'internal')
-rw-r--r--internal/ui/table.go39
-rw-r--r--internal/ui/table_test.go42
2 files changed, 65 insertions, 16 deletions
diff --git a/internal/ui/table.go b/internal/ui/table.go
index e629c20..59eaaeb 100644
--- a/internal/ui/table.go
+++ b/internal/ui/table.go
@@ -237,6 +237,10 @@ type descEditDoneMsg struct {
tempFile string
}
+type descEditLaunchMsg struct {
+ tempFile string
+}
+
type shellDoneMsg struct {
result task.RunResult
err error
@@ -320,7 +324,7 @@ func editCmd(id int) tea.Cmd {
return tea.ExecProcess(c, func(err error) tea.Msg { return editDoneMsg{err: err} })
}
-// editDescriptionCmd returns a command that opens the description in external editor
+// editDescriptionCmd returns a command that prepares the description temp file.
func editDescriptionCmd(description string) tea.Cmd {
return func() tea.Msg {
tmpPath, err := prepareDescriptionTempFile(description, func() (descriptionTempFile, error) {
@@ -330,23 +334,24 @@ func editDescriptionCmd(description string) tea.Cmd {
return descEditDoneMsg{err: err, tempFile: ""}
}
- // Get editor from environment
- editor := os.Getenv("EDITOR")
- if editor == "" {
- editor = "vi" // fallback to vi
- }
-
- // Create the command
- c := exec.Command(editor, tmpPath)
- c.Stdin = os.Stdin
- c.Stdout = os.Stdout
- c.Stderr = os.Stderr
+ return descEditLaunchMsg{tempFile: tmpPath}
+ }
+}
- // Use ExecProcess to properly handle the external TUI editor
- return tea.ExecProcess(c, func(err error) tea.Msg {
- return descEditDoneMsg{err: err, tempFile: tmpPath}
- })()
+func launchDescriptionEditorCmd(tmpPath string) tea.Cmd {
+ editor := os.Getenv("EDITOR")
+ if editor == "" {
+ editor = "vi"
}
+
+ c := exec.Command(editor, tmpPath)
+ c.Stdin = os.Stdin
+ c.Stdout = os.Stdout
+ c.Stderr = os.Stderr
+
+ return tea.ExecProcess(c, func(err error) tea.Msg {
+ return descEditDoneMsg{err: err, tempFile: tmpPath}
+ })
}
func blinkCmd() tea.Cmd {
@@ -608,6 +613,8 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
return m.handleWindowResize(msg)
case editDoneMsg:
return m.handleEditDone(msg)
+ case descEditLaunchMsg:
+ return m, launchDescriptionEditorCmd(msg.tempFile)
case descEditDoneMsg:
return m.handleDescEditDone(msg)
case shellDoneMsg:
diff --git a/internal/ui/table_test.go b/internal/ui/table_test.go
index f255fe3..bfd866d 100644
--- a/internal/ui/table_test.go
+++ b/internal/ui/table_test.go
@@ -203,6 +203,48 @@ func TestHandleDescEditDoneUpdatesDescriptionAndRemovesTempFile(t *testing.T) {
}
}
+func TestEditDescriptionCmdPreparesLaunchWithoutRunningEditor(t *testing.T) {
+ tmp := t.TempDir()
+ editorLog := filepath.Join(tmp, "editor.log")
+ editorPath := filepath.Join(tmp, "editor")
+ editorScript := "#!/bin/sh\n" +
+ "printf ran > " + editorLog + "\n"
+ if err := os.WriteFile(editorPath, []byte(editorScript), 0o755); err != nil {
+ t.Fatal(err)
+ }
+
+ origEditor := os.Getenv("EDITOR")
+ os.Setenv("EDITOR", editorPath)
+ t.Cleanup(func() { os.Setenv("EDITOR", origEditor) })
+
+ cmd := editDescriptionCmd("old description")
+ msg := cmd()
+
+ launchMsg, ok := msg.(descEditLaunchMsg)
+ if !ok {
+ t.Fatalf("editDescriptionCmd returned %T, want descEditLaunchMsg", msg)
+ }
+ defer func() { _ = os.Remove(launchMsg.tempFile) }()
+
+ if _, err := os.Stat(editorLog); !os.IsNotExist(err) {
+ t.Fatalf("editor was run during temp-file preparation: %v", err)
+ }
+
+ content, err := os.ReadFile(launchMsg.tempFile)
+ if err != nil {
+ t.Fatalf("read temp description: %v", err)
+ }
+ if string(content) != "old description" {
+ t.Fatalf("temp description = %q, want %q", content, "old description")
+ }
+
+ m := Model{}
+ _, launchCmd := (&m).Update(launchMsg)
+ if launchCmd == nil {
+ t.Fatalf("descEditLaunchMsg did not return an editor launch command")
+ }
+}
+
func TestPrepareDescriptionTempFileRemovesTempFileOnWriteError(t *testing.T) {
tmp := t.TempDir()
tempFile := filepath.Join(tmp, "desc.txt")