summaryrefslogtreecommitdiff
path: root/internal/editor/editor.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/editor/editor.go')
-rw-r--r--internal/editor/editor.go70
1 files changed, 70 insertions, 0 deletions
diff --git a/internal/editor/editor.go b/internal/editor/editor.go
new file mode 100644
index 0000000..44aa1d4
--- /dev/null
+++ b/internal/editor/editor.go
@@ -0,0 +1,70 @@
+package editor
+
+import (
+ "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
+}
+
+// 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()
+}
+
+// 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
+}