Add a cross-platform way to execute a shell command and string utilities

This commit is contained in:
Mickaël Menu 2021-01-19 19:56:43 +01:00
parent cd2040a74b
commit f1df4320ed
No known key found for this signature in database
GPG Key ID: 53D73664CD359895
8 changed files with 94 additions and 8 deletions

View File

@ -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"},

View File

@ -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

3
util/exec/exec.go Normal file
View File

@ -0,0 +1,3 @@
// +build !windows
package exec

17
util/exec/exec_unix.go Normal file
View File

@ -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)
}

18
util/exec/exec_windows.go Normal file
View File

@ -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
}

View File

@ -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 {

View File

@ -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), " ")
}

View File

@ -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")
}