diff --git a/action.go b/action.go index 9fbc8b740..339d6d14b 100644 --- a/action.go +++ b/action.go @@ -57,12 +57,11 @@ func (a ActionMap) shell(shell string, c Context) map[string]string { } type Context struct { + // CallbackValue contains the (partial) value (or part of it during an ActionMultiParts) currently being completed CallbackValue string - Args []string -} - -type MultipartsContext struct { - Context + // Args contains the positional arguments of current (sub)command (exclusive the one currently being completed) + Args []string + // Parts contains the splitted CallbackValue during an ActionMultiParts (exclusive the part currently being completed) Parts []string } @@ -148,15 +147,15 @@ func (a InvokedAction) ToA() Action { } func (a InvokedAction) ToMultiPartsA(divider string) Action { - return ActionMultiParts(divider, func(mc MultipartsContext) Action { + return ActionMultiParts(divider, func(c Context) Action { uniqueVals := make(map[string]string) for _, val := range a.rawValues { - if strings.HasPrefix(val.Value, strings.Join(mc.Parts, divider)) { - if splitted := strings.Split(val.Value, divider); len(splitted) > len(mc.Parts) { - if len(splitted) == len(mc.Parts)+1 { - uniqueVals[splitted[len(mc.Parts)]] = val.Description + if strings.HasPrefix(val.Value, strings.Join(c.Parts, divider)) { + if splitted := strings.Split(val.Value, divider); len(splitted) > len(c.Parts) { + if len(splitted) == len(c.Parts)+1 { + uniqueVals[splitted[len(c.Parts)]] = val.Description } else { - uniqueVals[splitted[len(mc.Parts)]+divider] = "" + uniqueVals[splitted[len(c.Parts)]+divider] = "" } } } @@ -327,29 +326,24 @@ func ActionMessage(msg string) Action { }) } -// CallbackValue is set to the currently completed flag/positional value during callback (note that this is updated during ActionMultiParts) -//var CallbackValue string // TODO remove - // ActionMultiParts completes multiple parts of words separately where each part is separated by some char (CallbackValue is set to the currently completed part during invocation) -func ActionMultiParts(divider string, callback func(mc MultipartsContext) Action) Action { +func ActionMultiParts(divider string, callback func(c Context) Action) Action { return ActionCallback(func(c Context) Action { - mc := MultipartsContext{Context: c} - index := strings.LastIndex(c.CallbackValue, string(divider)) prefix := "" if len(divider) == 0 { prefix = c.CallbackValue } else if index != -1 { prefix = c.CallbackValue[0 : index+len(divider)] - mc.CallbackValue = c.CallbackValue[index+len(divider):] // update CallbackValue to only contain the currently completed part + c.CallbackValue = c.CallbackValue[index+len(divider):] // update CallbackValue to only contain the currently completed part } parts := strings.Split(prefix, string(divider)) if len(parts) > 0 { parts = parts[0 : len(parts)-1] } - mc.Parts = parts + c.Parts = parts - return callback(mc).Invoke(mc.Context).Prefix(prefix).ToA() + return callback(c).Invoke(c).Prefix(prefix).ToA() }) } diff --git a/docs/src/carapace/action/actionMultiParts.md b/docs/src/carapace/action/actionMultiParts.md index 01ceff39d..a085199e5 100644 --- a/docs/src/carapace/action/actionMultiParts.md +++ b/docs/src/carapace/action/actionMultiParts.md @@ -3,10 +3,10 @@ [`ActionMultiParts`] is a [callback action](./actionCallback.md) where parts of an argument can be completed separately (e.g. `user:group` from chown). Divider can be empty as well, but note that bash and fish will add the space suffix for anything other than `/=@:.,` (it still works, but after each selection backspace is needed to continue the completion). ```go -carapace.ActionMultiParts(":", func(mc carapace.MultipartsContext) carapace.Action { +carapace.ActionMultiParts(":", func(c carapace.Context) carapace.Action { switch len(parts) { case 0: - return ActionUsers().Invoke(mc.Args).Suffix(":").ToA() + return ActionUsers().Invoke(c.Args).Suffix(":").ToA() case 1: return ActionGroups() default: @@ -25,17 +25,17 @@ carapace.ActionMultiParts(":", func(mc carapace.MultipartsContext) carapace.Acti [`ActionMultiParts`] can be nested as well, e.g. completing multiple `KEY=VALUE` pairs separated by `,`. ```go -carapace.ActionMultiParts(",", func(mcEntries carapace.MultipartsContext) carapace.Action { - return carapace.ActionMultiParts("=", func(mc carapace.MultipartsContext) carapace.Action { - switch len(mc.Parts) { +carapace.ActionMultiParts(",", func(cEntries carapace.Context) carapace.Action { + return carapace.ActionMultiParts("=", func(c carapace.Context) carapace.Action { + switch len(c.Parts) { case 0: - keys := make([]string, len(mcEntries.Parts)) - for index, entry := range mcEntries.Parts { + keys := make([]string, len(cEntries.Parts)) + for index, entry := range cEntries.Parts { keys[index] = strings.Split(entry, "=")[0] } - return carapace.ActionValues("FILE", "DIRECTORY", "VALUE").Invoke(mc.Context).Filter(keys).Suffix("=").ToA() + return carapace.ActionValues("FILE", "DIRECTORY", "VALUE").Invoke(c).Filter(keys).Suffix("=").ToA() case 1: - switch mc.Parts[0] { + switch c.Parts[0] { case "FILE": return carapace.ActionFiles("") case "DIRECTORY": diff --git a/docs/src/carapace/invokedAction/filter.md b/docs/src/carapace/invokedAction/filter.md index ca2e3f9ee..f430f527b 100644 --- a/docs/src/carapace/invokedAction/filter.md +++ b/docs/src/carapace/invokedAction/filter.md @@ -4,7 +4,7 @@ E.g. completing a unique list of values in an [ActionMultiParts](../action/actionMultiParts.md): ```go -carapace.ActionMultiParts(",", func(mc carapace.MultipartsContext) carapace.Action { - return carapace.ActionValues("one", "two", "three").Invoke(mc.Context).Filter(c.Parts).ToA() +carapace.ActionMultiParts(",", func(c carapace.Context) carapace.Action { + return carapace.ActionValues("one", "two", "three").Invoke(c).Filter(c.Parts).ToA() } ``` diff --git a/example/cmd/action/os.go b/example/cmd/action/os.go index 1f788ee72..4f946668e 100644 --- a/example/cmd/action/os.go +++ b/example/cmd/action/os.go @@ -110,10 +110,10 @@ func ActionUsers() carapace.Action { } func ActionUserGroup() carapace.Action { - return carapace.ActionMultiParts(":", func(mc carapace.MultipartsContext) carapace.Action { - switch len(mc.Parts) { + return carapace.ActionMultiParts(":", func(c carapace.Context) carapace.Action { + switch len(c.Parts) { case 0: - return ActionUsers().Invoke(mc.Context).Suffix(":").ToA() + return ActionUsers().Invoke(c).Suffix(":").ToA() case 1: return ActionGroups() default: diff --git a/example/cmd/callback.go b/example/cmd/callback.go index 9f0b17d8e..a846c1d71 100644 --- a/example/cmd/callback.go +++ b/example/cmd/callback.go @@ -31,12 +31,12 @@ func init() { carapace.ActionCallback(func(c carapace.Context) carapace.Action { return carapace.ActionValues("callback1", "callback2") }).Cache(30*time.Second), - carapace.ActionMultiParts("=", func(mc carapace.MultipartsContext) carapace.Action { - switch len(mc.Parts) { + carapace.ActionMultiParts("=", func(c carapace.Context) carapace.Action { + switch len(c.Parts) { case 0: return carapace.ActionValues("alpha=", "beta=", "gamma") case 1: - switch mc.Parts[0] { + switch c.Parts[0] { case "alpha": return carapace.ActionValues("one", "two", "three") case "beta": diff --git a/example/cmd/multiparts.go b/example/cmd/multiparts.go index be2b06d7f..59c60d14e 100644 --- a/example/cmd/multiparts.go +++ b/example/cmd/multiparts.go @@ -32,23 +32,23 @@ func init() { "dotdotdot": ActionMultipartsTest("..."), "equals": ActionMultipartsTest("="), "slash": ActionMultipartsTest("/"), - "none": carapace.ActionMultiParts("", func(mc carapace.MultipartsContext) carapace.Action { - return carapace.ActionValuesDescribed("a", "first", "b", "second", "c", "third", "d", "fourth").Invoke(mc.Context).Filter(strings.Split(mc.CallbackValue, "")).ToA() + "none": carapace.ActionMultiParts("", func(c carapace.Context) carapace.Action { + return carapace.ActionValuesDescribed("a", "first", "b", "second", "c", "third", "d", "fourth").Invoke(c).Filter(strings.Split(c.CallbackValue, "")).ToA() }), }) carapace.Gen(multipartsCmd).PositionalCompletion( - carapace.ActionMultiParts(",", func(mcEntries carapace.MultipartsContext) carapace.Action { - return carapace.ActionMultiParts("=", func(mc carapace.MultipartsContext) carapace.Action { - switch len(mc.Parts) { + carapace.ActionMultiParts(",", func(cEntries carapace.Context) carapace.Action { + return carapace.ActionMultiParts("=", func(c carapace.Context) carapace.Action { + switch len(c.Parts) { case 0: - keys := make([]string, len(mcEntries.Parts)) - for index, entry := range mcEntries.Parts { + keys := make([]string, len(cEntries.Parts)) + for index, entry := range cEntries.Parts { keys[index] = strings.Split(entry, "=")[0] } - return carapace.ActionValues("FILE", "DIRECTORY", "VALUE").Invoke(mc.Context).Filter(keys).Suffix("=").ToA() + return carapace.ActionValues("FILE", "DIRECTORY", "VALUE").Invoke(c).Filter(keys).Suffix("=").ToA() case 1: - switch mc.Parts[0] { + switch c.Parts[0] { case "FILE": return carapace.ActionFiles("") case "DIRECTORY": @@ -68,14 +68,14 @@ func init() { } func ActionMultipartsTest(divider string) carapace.Action { - return carapace.ActionMultiParts(divider, func(mc carapace.MultipartsContext) carapace.Action { - switch len(mc.Parts) { + return carapace.ActionMultiParts(divider, func(c carapace.Context) carapace.Action { + switch len(c.Parts) { case 0: - return ActionTestValues().Invoke(mc.Context).Suffix(divider).ToA() + return ActionTestValues().Invoke(c).Suffix(divider).ToA() case 1: - return ActionTestValues().Invoke(mc.Context).Filter(mc.Parts).Suffix(divider).ToA() + return ActionTestValues().Invoke(c).Filter(c.Parts).Suffix(divider).ToA() case 2: - return ActionTestValues().Invoke(mc.Context).Filter(mc.Parts).ToA() + return ActionTestValues().Invoke(c).Filter(c.Parts).ToA() default: return carapace.ActionValues() }