From 798caacf82e9c702b4108b24202805ba1d3cf037 Mon Sep 17 00:00:00 2001 From: rsteube Date: Thu, 5 May 2022 12:54:10 +0200 Subject: [PATCH] macro conversion --- .github/workflows/go.yml | 4 +- .gitignore | 1 + go.mod | 2 +- macro.go | 65 ++++++++++++++++++++++++++-- spec.go | 92 +++++++++++++++++----------------------- 5 files changed, 104 insertions(+), 60 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 3f81832..e424340 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -22,7 +22,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v2 with: - go-version: 1.17 + go-version: 1.18 - name: Build run: go build -v ./... @@ -34,7 +34,7 @@ jobs: run: '[ "$(gofmt -d -s . | tee -a /dev/stderr)" = "" ]' - name: "staticcheck" - run: go install honnef.co/go/tools/cmd/staticcheck@2021.1.1 && staticcheck ./... + run: go install honnef.co/go/tools/cmd/staticcheck@latest && staticcheck ./... - name: Run GoReleaser uses: goreleaser/goreleaser-action@v2 diff --git a/.gitignore b/.gitignore index 130dd59..c21880e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ +cmd/carapace-spec/carapace-spec dist docs/book diff --git a/go.mod b/go.mod index 2a50900..288f296 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/rsteube/carapace-spec -go 1.17 +go 1.18 replace github.com/spf13/pflag => github.com/cornfeedhobo/pflag v1.1.0 diff --git a/macro.go b/macro.go index a84e7d9..2980987 100644 --- a/macro.go +++ b/macro.go @@ -1,9 +1,66 @@ package spec -import "github.com/rsteube/carapace" +import ( + "fmt" + "reflect" + "regexp" -var macros = make(map[string]func(string) carapace.Action) + "github.com/rsteube/carapace" + "gopkg.in/yaml.v3" +) -func AddMacro(s string, f func(string) carapace.Action) { - macros[s] = f +type Macro func(string) carapace.Action + +var macros = make(map[string]Macro) + +func addCoreMacro(s string, m Macro) { + macros[s] = m +} + +func AddMacro(s string, m Macro) { + macros["_"+s] = m +} + +func parseMacro(s string) carapace.Action { + r := regexp.MustCompile(`^\$(?P[^(]*)(\((?P.*)\))?$`) + if !r.MatchString(s) { + return carapace.ActionMessage(fmt.Sprintf("malformed macro: '%v'", s)) + } + + matches := findNamedMatches(r, s) + if m, ok := macros[matches["macro"]]; !ok { + return carapace.ActionMessage(fmt.Sprintf("unknown macro: '%v'", s)) + } else { + return m(matches["arg"]) + } +} + +func MacroN(f func() carapace.Action) Macro { + return func(s string) carapace.Action { + return f() + } +} + +func MacroI[T any](f func(t T) carapace.Action) Macro { + return func(s string) carapace.Action { + var t T + if err := yaml.Unmarshal([]byte(s), &t); err != nil { + return carapace.ActionMessage(err.Error()) + } + return f(t) + } +} + +func MacroVarI[T any](f func(s ...T) carapace.Action) Macro { + return func(s string) carapace.Action { + if s == "" { + return f() + } + + var t []T + if err := yaml.Unmarshal([]byte(s), &t); err != nil { + return carapace.ActionMessage(fmt.Sprintf("malformed macro arg: '%v', expected '%v'", s, reflect.TypeOf(t))) + } + return f(t...) + } } diff --git a/spec.go b/spec.go index 4a20a01..8a746d7 100644 --- a/spec.go +++ b/spec.go @@ -73,66 +73,52 @@ func (c *Command) ToCobra() *cobra.Command { func parseAction(cmd *cobra.Command, arr []string) carapace.Action { return carapace.ActionCallback(func(c carapace.Context) carapace.Action { - rMacro := regexp.MustCompile(`^\$(?P[^(]*)(\((?P.*)\))?$`) listDelimiter := "" nospace := false + // TODO don't alter the map each time, solve this differently + addCoreMacro("list", func(s string) carapace.Action { + listDelimiter = s + return carapace.ActionValues() + }) + addCoreMacro("nospace", func(s string) carapace.Action { + nospace = true + return carapace.ActionValues() + }) + addCoreMacro("files", MacroVarI(carapace.ActionFiles)) + addCoreMacro("directories", MacroN(carapace.ActionDirectories)) + addCoreMacro("", func(s string) carapace.Action { + return carapace.ActionCallback(func(c carapace.Context) carapace.Action { + for index, arg := range c.Args { + c.Setenv(fmt.Sprintf("CARAPACE_ARG%v", index), arg) + } + for index, arg := range c.Parts { + c.Setenv(fmt.Sprintf("CARAPACE_PART%v", index), arg) + } + c.Setenv("CARAPACE_CALLBACK", c.CallbackValue) + + cmd.Flags().Visit(func(f *pflag.Flag) { + c.Setenv(fmt.Sprintf("CARAPACE_FLAG_%v", strings.ToUpper(f.Name)), f.Value.String()) + }) + + return carapace.ActionExecCommand("sh", "-c", s)(func(output []byte) carapace.Action { + lines := strings.Split(string(output), "\n") + vals := make([]string, 0) + for _, line := range lines { + if line != "" { + vals = append(vals, parseValue(line)...) + } + } + return carapace.ActionStyledValuesDescribed(vals...) + }).Invoke(c).ToA() + }) + }) + batch := carapace.Batch() vals := make([]string, 0) for _, elem := range arr { if strings.HasPrefix(elem, "$") { // macro - match := findNamedMatches(rMacro, elem) // TODO check if matches - macro := match["macro"] - arg := match["arg"] - - if strings.HasPrefix(macro, "_") { // custom macro - if f := macros[strings.TrimPrefix(macro, "_")]; f != nil { - batch = append(batch, carapace.ActionCallback(func(c carapace.Context) carapace.Action { return f(arg) })) - continue - } - return carapace.ActionMessage(fmt.Sprintf("unknown custom macro: '%v'", elem)) - } - - switch macro { - case "nospace": - nospace = true - case "list": - listDelimiter = arg - case "directories": - return carapace.ActionDirectories() - case "files": - if arg != "" { - batch = append(batch, carapace.ActionFiles(strings.Fields(arg)...)) - } - batch = append(batch, carapace.ActionFiles()) - case "": - batch = append(batch, carapace.ActionCallback(func(c carapace.Context) carapace.Action { - for index, arg := range c.Args { - c.Setenv(fmt.Sprintf("CARAPACE_ARG%v", index), arg) - } - for index, arg := range c.Parts { - c.Setenv(fmt.Sprintf("CARAPACE_PART%v", index), arg) - } - c.Setenv("CARAPACE_CALLBACK", c.CallbackValue) - - cmd.Flags().Visit(func(f *pflag.Flag) { - c.Setenv(fmt.Sprintf("CARAPACE_FLAG_%v", strings.ToUpper(f.Name)), f.Value.String()) - }) - - return carapace.ActionExecCommand("sh", "-c", arg)(func(output []byte) carapace.Action { - lines := strings.Split(string(output), "\n") - vals := make([]string, 0) - for _, line := range lines { - if line != "" { - vals = append(vals, parseValue(line)...) - } - } - return carapace.ActionStyledValuesDescribed(vals...) - }).Invoke(c).ToA() - })) - default: - batch = append(batch, carapace.ActionMessage(fmt.Sprintf("malformed macro: '%v'", elem))) - } + batch = append(batch, parseMacro(elem)) } else { vals = append(vals, parseValue(elem)...) }