internal/editor/editor.go
package editor
import (
"os"
"os/exec"
)
type Editor struct {
Opts
}
type Opts struct {
// The basename of the editor (i.e. vim)
basename string
// The initial content of the file when opening it.
initialContent string
}
type OptFunc func(*Opts)
func defaultOpts() Opts {
return Opts{
basename: "",
initialContent: "",
}
}
func WithBasename(b string) OptFunc {
return func(opts *Opts) {
opts.basename = b
}
}
func WithInitialContent(i string) OptFunc {
return func(opts *Opts) {
opts.initialContent = i
}
}
func NewEditor(opts ...OptFunc) Editor {
o := defaultOpts()
for _, fn := range opts {
fn(&o)
}
if basename, ok := os.LookupEnv("EDITOR"); ok && o.basename == "" {
o.basename = basename
}
return Editor{Opts: o}
}
func (e Editor) createTempFile() (*os.File, error) {
tmpFile, err := os.CreateTemp("", "")
if err != nil {
return tmpFile, err
}
_, err = tmpFile.WriteString(e.initialContent)
if err != nil {
return tmpFile, err
}
defer tmpFile.Close()
return tmpFile, nil
}
// Edit returns a string which is the contents of the file edited.
func (e Editor) Edit() (string, error) {
content := ""
tmpFile, err := e.createTempFile()
if err != nil {
return content, err
}
defer os.Remove(tmpFile.Name())
c := exec.Command(e.basename, tmpFile.Name())
c.Stdin = os.Stdin
c.Stdout = os.Stdout
err = c.Run()
if err != nil {
return content, err
}
f, err := os.ReadFile(tmpFile.Name())
if err != nil {
return content, err
}
content = string(f)
return content, nil
}
func (e Editor) Cmd() (*exec.Cmd, error) {
tmpFile, err := e.createTempFile()
if err != nil {
return nil, err
}
defer os.Remove(tmpFile.Name())
c := exec.Command(e.basename, tmpFile.Name())
c.Stdin = os.Stdin
c.Stdout = os.Stdout
return c, nil
}