summaryrefslogtreecommitdiff
path: root/internal/editor
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2025-09-08 12:02:40 +0300
committerPaul Buetow <paul@buetow.org>2025-09-08 12:02:40 +0300
commit75cf6abd55bfb60324fc47cf91eac08dbb8b87b4 (patch)
tree6ef90d8014fe4d9a757d3f7e95bf736b70e4c685 /internal/editor
parent0dcf347c3fbc6e4ffb7e46294f5dd92dbbcd98ef (diff)
docs: move tmux documentation to its own file
Diffstat (limited to 'internal/editor')
-rw-r--r--internal/editor/editor.go102
-rw-r--r--internal/editor/editor_test.go63
2 files changed, 85 insertions, 80 deletions
diff --git a/internal/editor/editor.go b/internal/editor/editor.go
index 44aa1d4..a1af1be 100644
--- a/internal/editor/editor.go
+++ b/internal/editor/editor.go
@@ -1,70 +1,70 @@
package editor
import (
- "errors"
- "os"
- "os/exec"
- "path/filepath"
- "strings"
+ "errors"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "strings"
)
// Resolve returns the editor command from HEXAI_EDITOR or EDITOR.
func Resolve() (string, error) {
- ed := strings.TrimSpace(os.Getenv("HEXAI_EDITOR"))
- if ed == "" {
- ed = strings.TrimSpace(os.Getenv("EDITOR"))
- }
- if ed == "" {
- return "", errors.New("no editor configured (set HEXAI_EDITOR or EDITOR)")
- }
- return ed, nil
+ ed := strings.TrimSpace(os.Getenv("HEXAI_EDITOR"))
+ if ed == "" {
+ ed = strings.TrimSpace(os.Getenv("EDITOR"))
+ }
+ if ed == "" {
+ return "", errors.New("no editor configured (set HEXAI_EDITOR or EDITOR)")
+ }
+ return ed, nil
}
// RunEditor is the seam that invokes the editor on the given file path.
// Override in tests to avoid launching a real editor.
var RunEditor = func(editor, path string) error {
- cmd := exec.Command(editor, path)
- cmd.Stdin = os.Stdin
- cmd.Stdout = os.Stdout
- cmd.Stderr = os.Stderr
- return cmd.Run()
+ cmd := exec.Command(editor, path)
+ cmd.Stdin = os.Stdin
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stderr
+ return cmd.Run()
}
// OpenTempAndEdit creates a temporary .md file, writes initial content if provided,
// opens it in the resolved editor, then reads the final content and removes the file.
// Returns the trimmed content.
func OpenTempAndEdit(initial []byte) (string, error) {
- ed, err := Resolve()
- if err != nil {
- return "", err
- }
- // Create temp file under system temp dir; ensure .md suffix
- dir := os.TempDir()
- f, err := os.CreateTemp(dir, "hexai-*.md")
- if err != nil {
- return "", err
- }
- path := f.Name()
- defer func() { _ = os.Remove(path) }()
- if len(initial) > 0 {
- if _, err := f.Write(initial); err != nil {
- _ = f.Close()
- return "", err
- }
- }
- if err := f.Sync(); err != nil {
- _ = f.Close()
- return "", err
- }
- if err := f.Close(); err != nil {
- return "", err
- }
- if err := RunEditor(ed, path); err != nil {
- return "", err
- }
- b, err := os.ReadFile(filepath.Clean(path))
- if err != nil {
- return "", err
- }
- return strings.TrimSpace(string(b)), nil
+ ed, err := Resolve()
+ if err != nil {
+ return "", err
+ }
+ // Create temp file under system temp dir; ensure .md suffix
+ dir := os.TempDir()
+ f, err := os.CreateTemp(dir, "hexai-*.md")
+ if err != nil {
+ return "", err
+ }
+ path := f.Name()
+ defer func() { _ = os.Remove(path) }()
+ if len(initial) > 0 {
+ if _, err := f.Write(initial); err != nil {
+ _ = f.Close()
+ return "", err
+ }
+ }
+ if err := f.Sync(); err != nil {
+ _ = f.Close()
+ return "", err
+ }
+ if err := f.Close(); err != nil {
+ return "", err
+ }
+ if err := RunEditor(ed, path); err != nil {
+ return "", err
+ }
+ b, err := os.ReadFile(filepath.Clean(path))
+ if err != nil {
+ return "", err
+ }
+ return strings.TrimSpace(string(b)), nil
}
diff --git a/internal/editor/editor_test.go b/internal/editor/editor_test.go
index df6dec7..06cc165 100644
--- a/internal/editor/editor_test.go
+++ b/internal/editor/editor_test.go
@@ -1,39 +1,44 @@
package editor
import (
- "os"
- "path/filepath"
- "testing"
+ "os"
+ "path/filepath"
+ "testing"
)
func TestResolve_EnvPriority(t *testing.T) {
- t.Setenv("HEXAI_EDITOR", "ed1")
- t.Setenv("EDITOR", "ed2")
- ed, err := Resolve()
- if err != nil || ed != "ed1" {
- t.Fatalf("Resolve failed: %v %q", err, ed)
- }
- t.Setenv("HEXAI_EDITOR", "")
- ed, err = Resolve()
- if err != nil || ed != "ed2" {
- t.Fatalf("Resolve fallback failed: %v %q", err, ed)
- }
+ t.Setenv("HEXAI_EDITOR", "ed1")
+ t.Setenv("EDITOR", "ed2")
+ ed, err := Resolve()
+ if err != nil || ed != "ed1" {
+ t.Fatalf("Resolve failed: %v %q", err, ed)
+ }
+ t.Setenv("HEXAI_EDITOR", "")
+ ed, err = Resolve()
+ if err != nil || ed != "ed2" {
+ t.Fatalf("Resolve fallback failed: %v %q", err, ed)
+ }
}
func TestOpenTempAndEdit_UsesRunEditor(t *testing.T) {
- old := RunEditor
- t.Cleanup(func(){ RunEditor = old })
- // Ensure Resolve() succeeds
- t.Setenv("HEXAI_EDITOR", "dummy")
- var capturedPath string
- RunEditor = func(editor, path string) error {
- capturedPath = path
- // simulate user writing content
- return os.WriteFile(path, []byte("Hello\nWorld\n"), 0o600)
- }
- out, err := OpenTempAndEdit([]byte("# Start\n\n"))
- if err != nil { t.Fatalf("OpenTempAndEdit: %v", err) }
- if out != "Hello\nWorld" { t.Fatalf("unexpected content: %q", out) }
- if filepath.Ext(capturedPath) != ".md" { t.Fatalf("expected .md suffix: %s", capturedPath) }
+ old := RunEditor
+ t.Cleanup(func() { RunEditor = old })
+ // Ensure Resolve() succeeds
+ t.Setenv("HEXAI_EDITOR", "dummy")
+ var capturedPath string
+ RunEditor = func(editor, path string) error {
+ capturedPath = path
+ // simulate user writing content
+ return os.WriteFile(path, []byte("Hello\nWorld\n"), 0o600)
+ }
+ out, err := OpenTempAndEdit([]byte("# Start\n\n"))
+ if err != nil {
+ t.Fatalf("OpenTempAndEdit: %v", err)
+ }
+ if out != "Hello\nWorld" {
+ t.Fatalf("unexpected content: %q", out)
+ }
+ if filepath.Ext(capturedPath) != ".md" {
+ t.Fatalf("expected .md suffix: %s", capturedPath)
+ }
}
-