Skip to content

Commit

Permalink
Merge pull request #196 from rsteube/modifier
Browse files Browse the repository at this point in the history
support direct modifiers
  • Loading branch information
rsteube authored Aug 30, 2023
2 parents 280adb0 + 884c8b8 commit e18c257
Show file tree
Hide file tree
Showing 4 changed files with 290 additions and 24 deletions.
51 changes: 27 additions & 24 deletions action.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,21 +118,34 @@ func (a action) parse(cmd *cobra.Command) carapace.Action {
batch = append(batch, carapace.ActionMessage("%v: %#v", err.Error(), elem))
} else if strings.HasPrefix(elemSubst, "$") { // macro
switch strings.SplitN(elemSubst, "(", 2)[0] {
case "$chdir":
action = MacroI(action.Chdir).parse(elemSubst)
case "$list":
action = MacroI(updateEnv(action).List).parse(elemSubst)
case "$multiparts":
action = MacroV(action.MultiParts).parse(elemSubst)
case "$nospace":
localAction := action
action = MacroI(func(s string) carapace.Action {
return localAction.NoSpace([]rune(s)...)
}).parse(elemSubst)
case "$uniquelist":
action = MacroI(updateEnv(action).UniqueList).parse(elemSubst)
case // TODO list in modifier.go
"$chdir",
"$filter",
"$filterargs",
"$list",
"$multiparts",
"$nospace",
"$prefix",
"$retain",
"$shift",
"$split",
"$splitp",
"$suffix",
"$suppress",
"$style",
"$tag",
"$uniquelist",
"$usage":
action = modifier{action}.Parse(elemSubst) // TODO does this need a local reference?
default:
batch = append(batch, ActionMacro(elemSubst))
splitted := strings.Split(elemSubst, " ||| ")
a := ActionMacro(splitted[0])
if len(splitted) > 1 {
for _, m := range splitted[1:] {
a = modifier{a}.Parse(m) // TODO does this need a local reference?
}
}
batch = append(batch, a)
}
} else {
vals = append(vals, parseValue(elemSubst)...)
Expand All @@ -143,16 +156,6 @@ func (a action) parse(cmd *cobra.Command) carapace.Action {
})
}

func updateEnv(a carapace.Action) carapace.Action {
return carapace.ActionCallback(func(c carapace.Context) carapace.Action {
for index, arg := range c.Parts {
c.Setenv(fmt.Sprintf("C_PART%v", index), arg)
}
c.Setenv("C_VALUE", c.Value)
return a.Invoke(c).ToA()
})
}

func parseValue(s string) []string {
if splitted := strings.SplitN(s, "\t", 3); len(splitted) > 2 {
return splitted
Expand Down
40 changes: 40 additions & 0 deletions example/modifier.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: modifier
description:
flags:
--chdir=: "$chdir"
--filter=: "$filter"
--filterargs=: "$filterargs"
--list=: "$list"
--multiparts=: "$multiparts"
--nospace=: "$nospace"
--prefix=: "$prefix"
--retain=: "$retain"
--shift=: "$shift"
--split=: "$split"
--splitp=: "$splitp"
--style=: "$style"
--suffix=: "$suffix"
--suppress=: "$suppress"
--tag=: "$tag"
--uniquelist=: "$uniquelist"
--usage=: "$usage"
completion:
flag:
chdir: ["$files ||| $chdir(/tmp)"]
filter: ["$(printf '%s\\n' one two three) ||| $filter([two])"]
filterargs: ["$files ||| $filterargs"]
list: ["$(printf '%s\\n' one two three) ||| $list(,)"]
multiparts: ["$(echo one/two/three) ||| $multiparts([/])"]
nospace: ["$(printf '%s\\n' one two/ three,) ||| $nospace(/,)"]
prefix: ["$files ||| $prefix(file://)"]
retain: ["$(printf '%s\\n' one two three) ||| $retain([two])"]
shift: ["$(printf '%s\\n' one two three) ||| $filterargs ||| $shift(1)"]
split: ["$(printf '%s\\n' one two three) ||| $filterargs ||| $split"]
splitp: ["$(printf '%s\\n' one two three) ||| $filterargs ||| $splitp"]
style: ["$(printf '%s\\n' one two three) ||| $style(underlined)"]
suffix: ["$(printf '%s\\n' apple melon orange) ||| $suffix(juice)"]
suppress: ["$message(fail) ||| $suppress(fail)"]
tag: ["$(printf '%s\\n' two) ||| $tag(even numbers)", "$(printf '%s\\n' one three) ||| $tag(odd numbers)"]
uniquelist: ["$(printf '%s\\n' one two three) ||| $uniquelist(,)"]
usage: ["$(echo) ||| $usage(custom)"]
positionalany: ["$(printf '%s\\n' one two three) ||| $filterargs"]
58 changes: 58 additions & 0 deletions modifier.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package spec

import (
"fmt"
"strings"

"github.com/rsteube/carapace"
)

type modifier struct {
carapace.Action
}

func (m modifier) Parse(s string) carapace.Action {
return carapace.ActionCallback(func(c carapace.Context) carapace.Action {
m.Action = updateEnv(m.Action) // TODO verify

var err error
if s, err = c.Envsubst(s); err != nil {
return carapace.ActionMessage(err.Error())
}

modifiers := map[string]Macro{
"$chdir": MacroI(m.Action.Chdir),
"$filter": MacroV(m.Action.Filter),
"$filterargs": MacroN(m.Action.FilterArgs),
"$list": MacroI(m.Action.List),
"$multiparts": MacroV(m.Action.MultiParts),
"$nospace": MacroI(func(s string) carapace.Action { return m.Action.NoSpace([]rune(s)...) }),
"$prefix": MacroI(m.Action.Prefix),
"$retain": MacroV(m.Action.Retain),
"$shift": MacroI(m.Action.Shift),
"$split": MacroN(m.Action.Split),
"$splitp": MacroN(m.Action.SplitP),
"$suffix": MacroI(m.Action.Suffix),
"$suppress": MacroI(func(s string) carapace.Action { return m.Action.Suppress(s) }),
"$style": MacroI(m.Action.Style),
"$tag": MacroI(m.Action.Tag),
"$uniquelist": MacroI(m.Action.UniqueList),
"$usage": MacroI(func(s string) carapace.Action { return m.Action.Usage(s) }),
}

if modifier, ok := modifiers[strings.SplitN(s, "(", 2)[0]]; ok {
return modifier.parse(s)
}
return carapace.ActionMessage("unknown macro: %#v", s)
})
}

func updateEnv(a carapace.Action) carapace.Action {
return carapace.ActionCallback(func(c carapace.Context) carapace.Action {
for index, arg := range c.Parts {
c.Setenv(fmt.Sprintf("C_PART%v", index), arg)
}
c.Setenv("C_VALUE", c.Value)
return a.Invoke(c).ToA()
})
}
165 changes: 165 additions & 0 deletions modifier_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
package spec

import (
_ "embed"
"testing"

"github.com/rsteube/carapace"
"github.com/rsteube/carapace/pkg/sandbox"
"github.com/rsteube/carapace/pkg/style"
)

//go:embed example/modifier.yaml
var modifierSpec string

func TestModifier(t *testing.T) {
sandboxSpec(t, modifierSpec)(func(s *sandbox.Sandbox) {
s.Run("--filter", "").
Expect(carapace.ActionValues(
"one",
"three",
).Usage("$filter"))

s.Run("--list", "").
Expect(carapace.ActionValues(
"one",
"two",
"three",
).NoSpace().
Usage("$list"))

s.Run("--list", "one,").
Expect(carapace.ActionValues(
"one",
"two",
"three",
).NoSpace().
Prefix("one,").
Usage("$list"))

s.Run("--multiparts", "").
Expect(carapace.ActionValues(
"one/",
).NoSpace('/').
Usage("$multiparts"))

s.Run("--multiparts", "one/").
Expect(carapace.ActionValues(
"two/",
).NoSpace('/').
Prefix("one/").
Usage("$multiparts"))

s.Run("--nospace", "").
Expect(carapace.ActionValues(
"one",
"two/",
"three,",
).NoSpace('/', ',').
Usage("$nospace"))

s.Run("--retain", "").
Expect(carapace.ActionValues(
"two",
).Usage("$retain"))

s.Run("--split", "").
Expect(carapace.ActionValues(
"one",
"two",
"three",
).NoSpace().
Suffix(" ").
Usage("$split"))

s.Run("--split", "one ").
Expect(carapace.ActionValues(
"two",
"three",
).NoSpace().
Prefix("one ").
Suffix(" ").
Usage("$split"))

s.Run("--splitp", "").
Expect(carapace.ActionValues(
"one",
"two",
"three",
).NoSpace().
Suffix(" ").
Usage("$splitp"))

s.Run("--splitp", "one ").
Expect(carapace.ActionValues(
"two",
"three",
).NoSpace().
Prefix("one ").
Suffix(" ").
Usage("$splitp"))

s.Run("--splitp", "one two | ").
Expect(carapace.ActionValues(
"one",
"two",
"three",
).NoSpace().
Prefix("one two | ").
Suffix(" ").
Usage("$splitp"))

s.Run("--splitp", "one two | one ").
Expect(carapace.ActionValues(
"two",
"three",
).NoSpace().
Prefix("one two | one ").
Suffix(" ").
Usage("$splitp"))

s.Run("--style", "").
Expect(carapace.ActionStyledValues(
"one", style.Underlined,
"two", style.Underlined,
"three", style.Underlined,
).Usage("$style"))

s.Run("--suffix", "").
Expect(carapace.ActionValues(
"apple",
"melon",
"orange",
).Suffix("juice").
Usage("$suffix"))

s.Run("--suppress", "").
Expect(carapace.ActionValues().Usage("$suppress"))

s.Run("--tag", "").
Expect(carapace.Batch(
carapace.ActionValues("two").Tag("even numbers"),
carapace.ActionValues("one", "three").Tag("odd numbers"),
).ToA().
Usage("$tag"))

s.Run("--uniquelist", "").
Expect(carapace.ActionValues(
"one",
"two",
"three",
).NoSpace().
Usage("$uniquelist"))

s.Run("--uniquelist", "one,").
Expect(carapace.ActionValues(
"two",
"three",
).NoSpace().
Prefix("one,").
Usage("$uniquelist"))

s.Run("--usage", "").
Expect(carapace.ActionValues().Usage("custom"))
})
}

0 comments on commit e18c257

Please sign in to comment.