Skip to content

Commit

Permalink
Merge pull request #218 from rsteube/expose-macros
Browse files Browse the repository at this point in the history
expose custom macros
  • Loading branch information
rsteube authored Dec 20, 2023
2 parents 3d7ef96 + c3ada19 commit 9144c56
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 6 deletions.
45 changes: 41 additions & 4 deletions action.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package spec
import (
"fmt"
"os"
"path/filepath"
"regexp"
"sort"
"strings"
Expand Down Expand Up @@ -47,14 +48,50 @@ func (value) JSONSchema() *jsonschema.Schema {
}
}

func executable() string {
s, err := os.Executable()
if err != nil {
panic(err.Error()) // TODO handle error, eval symlink, how to handle "go test"
}

return filepath.Base(s)
}

// ActionMacro completes given macro
func ActionMacro(s string) carapace.Action {
return carapace.ActionCallback(func(c carapace.Context) carapace.Action {
m, err := macros.Lookup(s)
if err != nil {
return carapace.ActionMessage(err.Error())
r := regexp.MustCompile(`^\$(?P<macro>[^(]*)(\((?P<arg>.*)\))?$`)
matches := r.FindStringSubmatch(s)
if matches == nil {
return carapace.ActionMessage("malformed macro: %#v", s)
}
if strings.HasPrefix(matches[1], "_") && !strings.HasPrefix(matches[1], "_.") {
return carapace.ActionMessage(`"$_" deprecated: replace %#v with %#v`, "$"+matches[1], "$carapace."+strings.TrimPrefix(matches[1], "_"))
}
prefix := fmt.Sprintf("$%v.", executable())

switch {
case !strings.HasPrefix(matches[1], "_.") && strings.Contains(matches[1], ".") && !strings.HasPrefix(s, prefix):
splitted := strings.SplitN(strings.TrimPrefix(s, "$"), ".", 2)
args := []string{"_carapace", "macro"}
args = append(args, splitted[1])
args = append(args, c.Args...)
args = append(args, c.Value)
carapace.LOG.Printf("%#v", args)
return carapace.ActionExecCommand(splitted[0], args...)(func(output []byte) carapace.Action {
return carapace.ActionImport(output)
})

default:
if strings.HasPrefix(s, prefix) {
s = "$_." + strings.TrimPrefix(s, prefix)
}
m, err := macros.Lookup(s)
if err != nil {
return carapace.ActionMessage(err.Error())
}
return m.Parse(s)
}
return m.Parse(s)
})
}

Expand Down
4 changes: 4 additions & 0 deletions cmd/carapace-spec/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,11 @@ func init() {
default:
cmd.Flags().Parse(args[:1]) // TODO unnecessary
}

})

spec.AddMacro("Spec", spec.MacroI(spec.ActionSpec))
spec.Register(rootCmd)
}

func bridgeCompletion(cmd *cobra.Command, spec string, args ...string) {
Expand Down
2 changes: 1 addition & 1 deletion docs/src/carapace-spec/macros/custom.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Custom

Custom macros can be added with [`AddMacro`](https://pkg.go.dev/github.com/rsteube/carapace-spec#AddMacro) (names are prefixed with `$_`).
Custom macros can be added with [`AddMacro`](https://pkg.go.dev/github.com/rsteube/carapace-spec#AddMacro).

```go
// `$_noarg` without argument
Expand Down
2 changes: 1 addition & 1 deletion macro.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func addCoreMacro(s string, m Macro) {

// AddMacro adds a custom macro
func AddMacro(s string, m Macro) {
macros["_"+s] = m
macros["_."+s] = m
}

func MacroN(f func() carapace.Action) Macro {
Expand Down
82 changes: 82 additions & 0 deletions register.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package spec

import (
"fmt"
"sort"
"strings"

"github.com/rsteube/carapace"
"github.com/spf13/cobra"
)

func Register(cmd *cobra.Command) {
carapace.Gen(cmd)

carapaceCmd, _, err := cmd.Find([]string{"_carapace"}) // TODO provide access to it using `carapace.Gen`
if err != nil {
carapace.LOG.Println(err.Error())
return // should never happen
}

macroCmd := &cobra.Command{
Use: "macro",
RunE: func(cmd *cobra.Command, args []string) error {
switch len(args) {
case 0:
keys := make([]string, 0, len(macros))
for k := range macros {
keys = append(keys, k)
}
sort.Strings(keys)

for _, key := range keys {
if strings.HasPrefix(key, "_") {
fmt.Fprintln(cmd.OutOrStdout(), strings.TrimPrefix(key, "_"))
}
}
case 1:
m, ok := macros["_."+args[0]]
if !ok {
return fmt.Errorf("unknown macro: %v", args[0])
}
fmt.Fprintln(cmd.OutOrStdout(), m.Signature())
default:
mCmd := &cobra.Command{
DisableFlagParsing: true,
}
carapace.Gen(mCmd).Standalone()
carapace.Gen(mCmd).PositionalAnyCompletion(
ActionMacro("$_." + args[0]),
)
carapace.LOG.Printf("%#v", args)
mCmd.SetArgs(append([]string{"_carapace", "export", ""}, args[1:]...))
mCmd.SetOut(cmd.OutOrStdout())
mCmd.SetErr(cmd.ErrOrStderr())
return mCmd.Execute()
}
return nil
},
}

macroCmd.Flags().SetInterspersed(false)

carapaceCmd.AddCommand(macroCmd)

carapace.Gen(macroCmd).PositionalCompletion(
carapace.ActionCallback(func(c carapace.Context) carapace.Action {
vals := make([]string, 0, len(macros))
for key := range macros {
if strings.HasPrefix(key, "_.") {
vals = append(vals, strings.TrimPrefix(key, "_."))
}
}
return carapace.ActionValues(vals...).MultiParts(".")
}),
)

carapace.Gen(macroCmd).PositionalAnyCompletion(
carapace.ActionCallback(func(c carapace.Context) carapace.Action {
return ActionMacro("$_." + c.Args[0]).Shift(1)
}),
)
}

0 comments on commit 9144c56

Please sign in to comment.