diff --git a/adapter/tty/styler.go b/adapter/tty/styler.go index 092bd3e..a4f1181 100644 --- a/adapter/tty/styler.go +++ b/adapter/tty/styler.go @@ -25,6 +25,14 @@ func (s *Styler) Style(text string, rules ...style.Rule) (string, error) { return color.New(attrs...).Sprint(text), nil } +func (s *Styler) MustStyle(text string, rules ...style.Rule) string { + text, err := s.Style(text, rules...) + if err != nil { + panic(err.Error()) + } + return text +} + // FIXME: User config var themeAliases = map[style.Rule][]style.Rule{ "title": {"bold", "yellow"}, diff --git a/core/note/edit.go b/core/note/edit.go index dfe7b3b..69fe22c 100644 --- a/core/note/edit.go +++ b/core/note/edit.go @@ -3,11 +3,11 @@ 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/exec" "github.com/mickael-menu/zk/util/opt" osutil "github.com/mickael-menu/zk/util/os" ) @@ -30,7 +30,7 @@ func Edit(zk *zk.Zk, path string) error { } args = append(args, path) - cmd := exec.Command(args[0], args[1:]...) + cmd := exec.CommandFromString(editor.String() + " '" + path + "'") cmd.Stdin = os.Stdin cmd.Stdout = os.Stdout diff --git a/util/exec/exec.go b/util/exec/exec.go new file mode 100644 index 0000000..d1313f0 --- /dev/null +++ b/util/exec/exec.go @@ -0,0 +1,3 @@ +// +build !windows + +package exec diff --git a/util/exec/exec_unix.go b/util/exec/exec_unix.go new file mode 100644 index 0000000..5522e9d --- /dev/null +++ b/util/exec/exec_unix.go @@ -0,0 +1,17 @@ +// +build !windows + +package exec + +import ( + "os" + "os/exec" +) + +// CommandFromString returns a Cmd running the given command with $SHELL. +func CommandFromString(command string) *exec.Cmd { + shell := os.Getenv("SHELL") + if len(shell) == 0 { + shell = "sh" + } + return exec.Command(shell, "-c", command) +} diff --git a/util/exec/exec_windows.go b/util/exec/exec_windows.go new file mode 100644 index 0000000..6895ae3 --- /dev/null +++ b/util/exec/exec_windows.go @@ -0,0 +1,18 @@ +package exec + +import ( + "fmt" + "os/exec" + "syscall" +) + +// CommandFromString returns a Cmd running the given command. +func CommandFromString(command string) *exec.Cmd { + cmd := exec.Command("cmd") + cmd.SysProcAttr = &syscall.SysProcAttr{ + HideWindow: false, + CmdLine: fmt.Sprintf(` /v:on/s/c "%s"`, command), + CreationFlags: 0, + } + return cmd +} diff --git a/util/pager/pager.go b/util/pager/pager.go index 57b1e4c..3a14cb1 100644 --- a/util/pager/pager.go +++ b/util/pager/pager.go @@ -11,6 +11,7 @@ import ( "github.com/kballard/go-shellquote" "github.com/mickael-menu/zk/util" "github.com/mickael-menu/zk/util/errors" + executil "github.com/mickael-menu/zk/util/exec" "github.com/mickael-menu/zk/util/opt" osutil "github.com/mickael-menu/zk/util/os" ) @@ -39,11 +40,7 @@ func New(pagerCmd opt.String, logger util.Logger) (*Pager, error) { return PassthroughPager, nil } - args, err := shellquote.Split(pagerCmd.String()) - if err != nil { - return nil, wrap(err) - } - cmd := exec.Command(args[0], args[1:]...) + cmd := executil.CommandFromString(pagerCmd.String()) r, w, err := os.Pipe() if err != nil { diff --git a/util/strings/strings.go b/util/strings/strings.go index a26afee..2475e43 100644 --- a/util/strings/strings.go +++ b/util/strings/strings.go @@ -1,6 +1,9 @@ package strings -import "strings" +import ( + "bufio" + "strings" +) // Prepend prefixes each lines of a string with the given prefix. // It can be used to indent or quote (> ) a paragraph, for example. @@ -25,3 +28,20 @@ func Pluralize(word string, count int) string { return word + "s" } } + +// SplitLines splits a string by the newlines character in a portable way +// Using only `strings.Split(s, "\n")` doesn't work on Windows. +func SplitLines(s string) []string { + var lines []string + scanner := bufio.NewScanner(strings.NewReader(s)) + for scanner.Scan() { + lines = append(lines, scanner.Text()) + } + return lines +} + +// JoinLines joins each lines of the given string by replacing the newlines by +// a single space. +func JoinLines(s string) string { + return strings.Join(SplitLines(s), " ") +} diff --git a/util/strings/strings_test.go b/util/strings/strings_test.go index 5457073..6c7ee35 100644 --- a/util/strings/strings_test.go +++ b/util/strings/strings_test.go @@ -32,3 +32,26 @@ func TestPluralize(t *testing.T) { test("word", 2, "words") test("word", 1000, "words") } + +func TestSplitLines(t *testing.T) { + test := func(text string, expected ...string) { + assert.Equal(t, SplitLines(text), expected) + } + + test("") + test("One line", "One line") + test("One line\nTwo lines", "One line", "Two lines") + test("One line\nTwo lines\n\nThree lines", "One line", "Two lines", "", "Three lines") +} + +func TestJoinLines(t *testing.T) { + test := func(text string, expected string) { + assert.Equal(t, JoinLines(text), expected) + } + + test("", "") + test("One line", "One line") + test("One line\nTwo lines", "One line Two lines") + test("One line\nTwo lines\n\nThree lines", "One line Two lines Three lines") + test("One line\nTwo lines\n Three lines", "One line Two lines Three lines") +}