From 6831823e5d1baa8334dd6b4ae889c377d24ebeb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mickae=CC=88l=20Menu?= Date: Sat, 2 Jan 2021 18:01:30 +0100 Subject: [PATCH] Edit newly created notes --- cmd/new.go | 14 ++++++++----- core/note/edit.go | 45 ++++++++++++++++++++++++++++++++++++++++++ core/note/edit_test.go | 41 ++++++++++++++++++++++++++++++++++++++ main.go | 2 +- util/{ => os}/os.go | 8 +++++++- zk | 2 ++ 6 files changed, 105 insertions(+), 7 deletions(-) create mode 100644 core/note/edit.go create mode 100644 core/note/edit_test.go rename util/{ => os}/os.go (73%) create mode 100755 zk diff --git a/cmd/new.go b/cmd/new.go index fc126a6..e1ee7dd 100644 --- a/cmd/new.go +++ b/cmd/new.go @@ -5,14 +5,14 @@ import ( "github.com/mickael-menu/zk/core/note" "github.com/mickael-menu/zk/core/zk" - "github.com/mickael-menu/zk/util" "github.com/mickael-menu/zk/util/opt" + "github.com/mickael-menu/zk/util/os" ) // New adds a new note to the slip box. type New struct { Directory string `arg optional type:"path" default:"." help:"Directory in which to create the note"` - ShowPath bool `help:"Shows the path of the created note instead of editing it"` + PrintPath bool `help:"Prints the path of the created note to stdin instead of editing it"` Title string `short:"t" help:"Title of the new note" placeholder:"TITLE"` Template string `type:"path" help:"Custom template to use to render the note" placeholder:"PATH"` Extra map[string]string `help:"Extra variables passed to the templates"` @@ -36,7 +36,7 @@ func (cmd *New) Run(container *Container) error { return err } - content, err := util.ReadStdinPipe() + content, err := os.ReadStdinPipe() if err != nil { return err } @@ -51,6 +51,10 @@ func (cmd *New) Run(container *Container) error { return err } - fmt.Printf("%+v\n", file) - return nil + if cmd.PrintPath { + fmt.Printf("%+v\n", file) + return nil + } else { + return note.Edit(zk, file) + } } diff --git a/core/note/edit.go b/core/note/edit.go new file mode 100644 index 0000000..dfe7b3b --- /dev/null +++ b/core/note/edit.go @@ -0,0 +1,45 @@ +package note + +import ( + "fmt" + "os" + "os/exec" + + "github.com/kballard/go-shellquote" + "github.com/mickael-menu/zk/core/zk" + "github.com/mickael-menu/zk/util/errors" + "github.com/mickael-menu/zk/util/opt" + osutil "github.com/mickael-menu/zk/util/os" +) + +// Edit starts the editor with the note at given path. +func Edit(zk *zk.Zk, path string) error { + editor := editor(zk) + if editor.IsNull() { + return fmt.Errorf("no editor set in config") + } + + wrap := errors.Wrapperf("failed to launch editor: %v", editor) + + args, err := shellquote.Split(editor.String()) + if err != nil { + return wrap(err) + } + if len(args) == 0 { + return wrap(fmt.Errorf("editor command is not valid: %v", editor)) + } + args = append(args, path) + + cmd := exec.Command(args[0], args[1:]...) + cmd.Stdin = os.Stdin + cmd.Stdout = os.Stdout + + return wrap(cmd.Run()) +} + +// editor returns the editor command to use to edit a note. +func editor(zk *zk.Zk) opt.String { + return zk.Config.Editor. + Or(osutil.GetOptEnv("VISUAL")). + Or(osutil.GetOptEnv("EDITOR")) +} diff --git a/core/note/edit_test.go b/core/note/edit_test.go new file mode 100644 index 0000000..a9fe3c9 --- /dev/null +++ b/core/note/edit_test.go @@ -0,0 +1,41 @@ +package note + +import ( + "os" + "testing" + + "github.com/mickael-menu/zk/core/zk" + "github.com/mickael-menu/zk/util/assert" + "github.com/mickael-menu/zk/util/opt" +) + +func TestEditorUsesUserConfigFirst(t *testing.T) { + os.Setenv("VISUAL", "editor") + zk := zk.Zk{Config: zk.Config{Editor: opt.NewString("custom-editor")}} + + assert.Equal(t, editor(&zk), opt.NewString("custom-editor")) +} + +func TestEditorFallsbackOnVisual(t *testing.T) { + os.Setenv("VISUAL", "visual") + os.Setenv("EDITOR", "editor") + zk := zk.Zk{} + + assert.Equal(t, editor(&zk), opt.NewString("visual")) +} + +func TestEditorFallsbackOnEditor(t *testing.T) { + os.Unsetenv("VISUAL") + os.Setenv("EDITOR", "editor") + zk := zk.Zk{} + + assert.Equal(t, editor(&zk), opt.NewString("editor")) +} + +func TestEditorWhenUnset(t *testing.T) { + os.Unsetenv("VISUAL") + os.Unsetenv("EDITOR") + zk := zk.Zk{} + + assert.Equal(t, editor(&zk), opt.NullString) +} diff --git a/main.go b/main.go index aee53ea..7b90c13 100644 --- a/main.go +++ b/main.go @@ -10,7 +10,7 @@ var Build = "dev" var cli struct { Init cmd.Init `cmd help:"Create a slip box in the given directory"` - New cmd.New `cmd help:"Add a new note to the slip box"` + New cmd.New `cmd help:"Create a new note in the given slip box directory"` Version kong.VersionFlag `help:"Print zk version"` } diff --git a/util/os.go b/util/os/os.go similarity index 73% rename from util/os.go rename to util/os/os.go index 17ec5ff..dcce62d 100644 --- a/util/os.go +++ b/util/os/os.go @@ -1,4 +1,4 @@ -package util +package os import ( "bufio" @@ -27,3 +27,9 @@ func ReadStdinPipe() (opt.String, error) { return opt.NewNotEmptyString(string(bytes)), nil } + +// Getenv returns an optional String for the environment variable with given +// key. +func GetOptEnv(key string) opt.String { + return opt.NewNotEmptyString(os.Getenv(key)) +} diff --git a/zk b/zk new file mode 100755 index 0000000..c56d9b1 --- /dev/null +++ b/zk @@ -0,0 +1,2 @@ +#!/bin/sh +./go run main.go $@