Skip to content

Commit

Permalink
fix modifiers
Browse files Browse the repository at this point in the history
  • Loading branch information
rsteube committed Jan 23, 2023
1 parent 9be3677 commit 685af11
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 61 deletions.
86 changes: 33 additions & 53 deletions action.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,12 @@ func ActionMacro(s string) carapace.Action {
return carapace.ActionCallback(func(c carapace.Context) carapace.Action {
r := regexp.MustCompile(`^\$(?P<macro>[^(]*)(\((?P<arg>.*)\))?$`)
if !r.MatchString(s) {
return carapace.ActionMessage("malformed macro: '%v'", s)
return carapace.ActionMessage("malformed macro: %#v", s)
}

matches := findNamedMatches(r, s)
if m, ok := macros[matches["macro"]]; !ok {
return carapace.ActionMessage("unknown macro: '%v'", s)
return carapace.ActionMessage("unknown macro: %#v", s)
} else {
return m.f(matches["arg"])
}
Expand Down Expand Up @@ -104,69 +104,49 @@ func parseAction(cmd *cobra.Command, arr []action) carapace.Action {
c.Setenv(fmt.Sprintf("C_FLAG_%v", strings.ToUpper(f.Name)), f.Value.String())
})

listDelimiter := ""
nospace := ""
chdir := ""
multiparts := ""

// TODO don't alter the map each time, solve this differently
addCoreMacro("chdir", MacroI(func(s string) carapace.Action {
chdir = s
return carapace.ActionValues()
}))
addCoreMacro("list", MacroI(func(s string) carapace.Action {
listDelimiter = s
return carapace.ActionValues()
}))
addCoreMacro("multiparts", MacroI(func(s string) carapace.Action {
multiparts = s
return carapace.ActionValues()
}))
addCoreMacro("nospace", MacroI(func(s string) carapace.Action {
nospace = s
if s == "" {
nospace = "*"
}
return carapace.ActionValues()
}))

batch := carapace.Batch()
action := carapace.ActionCallback(func(c carapace.Context) carapace.Action {
return batch.ToA()
})

vals := make([]string, 0)
for _, elem := range arr {
if elemSubst, err := c.Envsubst(string(elem)); err != nil {
batch = append(batch, carapace.ActionMessage("%v: %v", err.Error(), elem))
batch = append(batch, carapace.ActionMessage("%v: %#v", err.Error(), elem))
} else if strings.HasPrefix(elemSubst, "$") { // macro
batch = append(batch, ActionMacro(elemSubst))
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)
default:
batch = append(batch, ActionMacro(elemSubst))
}
} else {
vals = append(vals, parseValue(elemSubst)...)
}
}
batch = append(batch, carapace.ActionStyledValuesDescribed(vals...))
return action.Invoke(c).ToA()
})
}

action := batch.Invoke(c).Merge().ToA() // invoke eagerly so that the modifier macros are called
if chdir != "" {
action = action.Chdir(chdir)
}
if multiparts != "" {
actionCopy := action
action = carapace.ActionCallback(func(c carapace.Context) carapace.Action {
return actionCopy.Invoke(c).ToMultiPartsA(multiparts)
})
}

if listDelimiter != "" {
return carapace.ActionMultiParts(listDelimiter, func(c carapace.Context) carapace.Action {
for index, arg := range c.Parts {
c.Setenv(fmt.Sprintf("C_PART%v", index), arg)
}
c.Setenv("C_CALLBACK", c.CallbackValue)

return action.Invoke(c).Filter(c.Parts).ToA()
})
} else if nospace != "" {
return action.NoSpace([]rune(nospace)...)
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)
}
return action.Invoke(c).ToA()
c.Setenv("C_CALLBACK", c.CallbackValue)
return a.Invoke(c).ToA()
})
}

Expand Down
7 changes: 7 additions & 0 deletions core.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ import (
)

func init() {
// modifiers added as dummy for completeness
addCoreMacro("chdir", MacroI(func(s string) carapace.Action { return carapace.ActionValues() }))
addCoreMacro("list", MacroI(func(s string) carapace.Action { return carapace.ActionValues() }))
addCoreMacro("multiparts", MacroI(func(s string) carapace.Action { return carapace.ActionValues() }))
addCoreMacro("nospace", MacroI(func(s string) carapace.Action { return carapace.ActionValues() }))
addCoreMacro("uniquelist", MacroI(func(s string) carapace.Action { return carapace.ActionValues() }))

addCoreMacro("directories", MacroN(carapace.ActionDirectories))
addCoreMacro("files", MacroV(carapace.ActionFiles))
addCoreMacro("message", MacroI(func(s string) carapace.Action { return carapace.ActionMessage(s) }))
Expand Down
14 changes: 11 additions & 3 deletions docs/src/carapace-spec/macros/modifier.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,18 @@ Modifiers change the completion for a position in general.

## list

[`$list(<delimiter>)`](https://rsteube.github.io/carapace/carapace/action/actionMultiParts.html) completes values as unique list with given delimiter.
[`$list(<delimiter>)`](https://rsteube.github.io/carapace/carapace/action/actionMultiParts.html) completes values as list with given delimiter.

```yml
["$list(,)", "a", "b", "c", "d"]
```

## multiparts

[`$multiparts(<delimiter>)`](https://rsteube.github.io/carapace/carapace/invokedAction/toMultiPartsA.html) completes values splitted on given delimiter separately.
[`$multiparts(<delimiter>)`](https://rsteube.github.io/carapace/carapace/invokedAction/toMultiPartsA.html) completes values splitted on given delimiters separately.

```yml
["$multiparts(/)", "a", "a/b", "a/c", "b", "b/a"]
["$multiparts([/])", "a", "a/b", "a/c", "b", "b/a"]
```

## nospace
Expand All @@ -41,3 +41,11 @@ Modifiers change the completion for a position in general.
```yml
["$noflag"]
```

## uniquelist

[`$uniquelist(<delimiter>)`](https://rsteube.github.io/carapace/carapace/action/actionMultiParts.html) completes values as unique list with given delimiter.

```yml
["$uniquelist(,)", "a", "b", "c", "d"]
```
8 changes: 6 additions & 2 deletions example/example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,16 @@ commands:
-l, --list=: list flag
--dynamic=: dynamic value
--env=: env
--env-list=: env
--novalue: no value
--chdir=: chdir modifier
--multiparts=: multiparts modifier
-n, --nospace=: nospace
-u, --uniquelist=: uniqelist flag
completion:
flag:
chdir: ["$chdir(/tmp)", "$files"]
multiparts: ["$multiparts(/)", "one/a/1", "one/a/2", "one/b/1", "one/b/2", "two/a/1"]
multiparts: ["$multiparts([/])", "one/a/1", "one/a/2", "one/b/1", "one/b/2", "two/a/1"]
styled:
- "blue\tblue\tblue"
- "cyan\tcyan\tcyan"
Expand All @@ -35,10 +37,12 @@ commands:
- "$(git branch --all | cut -c 3- | sed 's/$/\t\tblue/')"
- "$(git tag | sed 's/$/\t\tyellow/')"
- "static value"
env: ["$(env)"]
env: ["$(env | grep '^C_')"]
env-list: ["$list(,)", "$(env | grep '^C_')", "one\t\tblue", "two\t\tblue", "three\t\tblue"]
list: ["$list(,)", "a", "b", "c", "d"]
nospace: ["$nospace", "1", "2", "3"]
optarg: ["first", "second", "third"]
uniquelist: ["$uniquelist(,)", "a", "b", "c", "d"]
positional:
- ["pos1A", "pos1B"]
- ["$files([.go, go.mod])"]
Expand Down
4 changes: 2 additions & 2 deletions example/pkill.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,10 @@ completion:
- "WINCH\tWindow size change\tblue"
- "XCPU\tCPU time limit exceeded\tmagenta"
- "XFSZ\tFile size limit exceeded\tmagenta"
nslist: ["$list(,)", "ipc", "mnt", "net", "pid", "user", "uts"]
nslist: ["$uniquelist(,)", "ipc", "mnt", "net", "pid", "user", "uts"]
pidfile: ["$files"]
runstates:
- "$list(,)"
- "$uniquelist(,)"
- "D\tuninterruptible sleep (usually IO)"
- "I\tIdle kernel thread"
- "R\trunning or runnable (on run queue)"
Expand Down
11 changes: 10 additions & 1 deletion macro.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package spec
import (
"fmt"
"reflect"
"regexp"
"strings"

"github.com/rsteube/carapace"
Expand All @@ -15,6 +16,14 @@ type Macro struct {
disableFlagParsing bool
}

func (m Macro) parse(s string) carapace.Action {
r := regexp.MustCompile(`^\$(?P<macro>[^(]*)(\((?P<arg>.*)\))?$`)
matches := r.FindStringSubmatch(s)
if matches == nil {
return carapace.ActionMessage("malformed macro: '%v'", s)
}
return m.f(matches[3])
}
func (m Macro) Signature() string { return m.s() }
func (m Macro) NoFlag() Macro { m.disableFlagParsing = true; return m }

Expand Down Expand Up @@ -67,7 +76,7 @@ func MacroI[T any](f func(t T) carapace.Action) Macro {
}
}

// MacroV careates a macro with a variable argument
// MacroV creates a macro with a variable argument
func MacroV[T any](f func(s ...T) carapace.Action) Macro {
return Macro{
f: func(s string) carapace.Action {
Expand Down

0 comments on commit 685af11

Please sign in to comment.