From 3f795098fe964ff5941ea0da694602f24d5139f2 Mon Sep 17 00:00:00 2001 From: rsteube Date: Wed, 12 Jul 2023 11:07:40 +0200 Subject: [PATCH] action: added Retain exposed filter --- action.go | 184 +++++++++++++++------------ docs/src/SUMMARY.md | 2 + docs/src/carapace/action/filter.cast | 41 ++++++ docs/src/carapace/action/filter.md | 16 +++ docs/src/carapace/action/retain.cast | 41 ++++++ docs/src/carapace/action/retain.md | 16 +++ example/cmd/modifier.go | 16 ++- example/cmd/modifier_test.go | 20 +++ internal/common/value.go | 15 +++ invokedAction.go | 11 +- 10 files changed, 277 insertions(+), 85 deletions(-) create mode 100644 docs/src/carapace/action/filter.cast create mode 100644 docs/src/carapace/action/filter.md create mode 100644 docs/src/carapace/action/retain.cast create mode 100644 docs/src/carapace/action/retain.md diff --git a/action.go b/action.go index d9b463017..77f3c51fb 100644 --- a/action.go +++ b/action.go @@ -52,6 +52,32 @@ func (a Action) Cache(timeout time.Duration, keys ...pkgcache.Key) Action { return a } +// Chdir changes the current working directory to the named directory for the duration of invocation. +func (a Action) Chdir(dir string) Action { + return ActionCallback(func(c Context) Action { + abs, err := c.Abs(dir) + if err != nil { + return ActionMessage(err.Error()) + } + if info, err := os.Stat(abs); err != nil { + return ActionMessage(err.Error()) + } else if !info.IsDir() { + return ActionMessage("not a directory: %v", abs) + } + c.Dir = abs + return a.Invoke(c).ToA() + }) +} + +// Filter filters given values. +// +// carapace.ActionValues("A", "B", "C").Filter([]string{"B"}) // ["A", "C"] +func (a Action) Filter(values []string) Action { + return ActionCallback(func(c Context) Action { + return a.Invoke(c).Filter(values).ToA() + }) +} + // Invoke executes the callback of an action if it exists (supports nesting). func (a Action) Invoke(c Context) InvokedAction { if c.Args == nil { @@ -72,6 +98,20 @@ func (a Action) Invoke(c Context) InvokedAction { return InvokedAction{a} } +// List wraps the Action in an ActionMultiParts with given divider. +func (a Action) List(divider string) Action { + return ActionMultiParts(divider, func(c Context) Action { + return a.Invoke(c).ToA().NoSpace() + }) +} + +// MultiParts splits values of an Action by given dividers and completes each segment separately. +func (a Action) MultiParts(dividers ...string) Action { + return ActionCallback(func(c Context) Action { + return a.Invoke(c).ToMultiPartsA(dividers...) + }) +} + // NoSpace disables space suffix for given characters (or all if none are given). func (a Action) NoSpace(suffixes ...rune) Action { return ActionCallback(func(c Context) Action { @@ -83,20 +123,21 @@ func (a Action) NoSpace(suffixes ...rune) Action { }) } -// Usage sets the usage. -func (a Action) Usage(usage string, args ...interface{}) Action { - return a.UsageF(func() string { - return fmt.Sprintf(usage, args...) +// Prefix adds a prefix to values (only the ones inserted, not the display values). +// +// carapace.ActionValues("melon", "drop", "fall").Prefix("water") +func (a Action) Prefix(prefix string) Action { + return ActionCallback(func(c Context) Action { + return a.Invoke(c).Prefix(prefix).ToA() }) } -// Usage sets the usage using a function. -func (a Action) UsageF(f func() string) Action { +// Retain retains given values. +// +// carapace.ActionValues("A", "B", "C").Retain([]string{"A", "C"}) // ["A", "C"] +func (a Action) Retain(values []string) Action { return ActionCallback(func(c Context) Action { - if usage := f(); usage != "" { - a.meta.Usage = usage - } - return a + return a.Invoke(c).Retain(values).ToA() }) } @@ -110,6 +151,20 @@ func (a Action) Style(s string) Action { }) } +// Style sets the style using a function. +// +// ActionValues("dir/", "test.txt").StyleF(style.ForPathExt) +// ActionValues("true", "false").StyleF(style.ForKeyword) +func (a Action) StyleF(f func(s string, sc style.Context) string) Action { + return ActionCallback(func(c Context) Action { + invoked := a.Invoke(c) + for index, v := range invoked.rawValues { + invoked.rawValues[index].Style = f(v.Value, c) + } + return invoked.ToA() + }) +} + // Style sets the style using a reference. // // ActionValues("value").StyleR(&style.Carapace.Value) @@ -123,15 +178,21 @@ func (a Action) StyleR(s *string) Action { }) } -// Style sets the style using a function. +// Suffix adds a suffx to values (only the ones inserted, not the display values). // -// ActionValues("dir/", "test.txt").StyleF(style.ForPathExt) -// ActionValues("true", "false").StyleF(style.ForKeyword) -func (a Action) StyleF(f func(s string, sc style.Context) string) Action { +// carapace.ActionValues("apple", "melon", "orange").Suffix("juice") +func (a Action) Suffix(suffix string) Action { + return ActionCallback(func(c Context) Action { + return a.Invoke(c).Suffix(suffix).ToA() + }) +} + +// Suppress suppresses specific error messages using regular expressions. +func (a Action) Suppress(expr ...string) Action { return ActionCallback(func(c Context) Action { invoked := a.Invoke(c) - for index, v := range invoked.rawValues { - invoked.rawValues[index].Style = f(v.Value, c) + if err := invoked.meta.Messages.Suppress(expr...); err != nil { + return ActionMessage(err.Error()) } return invoked.ToA() }) @@ -161,73 +222,6 @@ func (a Action) TagF(f func(s string) string) Action { }) } -// Chdir changes the current working directory to the named directory for the duration of invocation. -func (a Action) Chdir(dir string) Action { - return ActionCallback(func(c Context) Action { - abs, err := c.Abs(dir) - if err != nil { - return ActionMessage(err.Error()) - } - if info, err := os.Stat(abs); err != nil { - return ActionMessage(err.Error()) - } else if !info.IsDir() { - return ActionMessage("not a directory: %v", abs) - } - c.Dir = abs - return a.Invoke(c).ToA() - }) -} - -// Suppress suppresses specific error messages using regular expressions. -func (a Action) Suppress(expr ...string) Action { - return ActionCallback(func(c Context) Action { - invoked := a.Invoke(c) - if err := invoked.meta.Messages.Suppress(expr...); err != nil { - return ActionMessage(err.Error()) - } - return invoked.ToA() - }) -} - -// MultiParts splits values of an Action by given dividers and completes each segment separately. -func (a Action) MultiParts(dividers ...string) Action { - return ActionCallback(func(c Context) Action { - return a.Invoke(c).ToMultiPartsA(dividers...) - }) -} - -// List wraps the Action in an ActionMultiParts with given divider. -func (a Action) List(divider string) Action { - return ActionMultiParts(divider, func(c Context) Action { - return a.Invoke(c).ToA().NoSpace() - }) -} - -// UniqueList wraps the Action in an ActionMultiParts with given divider. -func (a Action) UniqueList(divider string) Action { - return ActionMultiParts(divider, func(c Context) Action { - return a.Invoke(c).Filter(c.Parts).ToA().NoSpace() - }) -} - -// Prefix adds a prefix to values (only the ones inserted, not the display values). -// -// carapace.ActionValues("melon", "drop", "fall").Prefix("water") -func (a Action) Prefix(prefix string) Action { - return ActionCallback(func(c Context) Action { - return a.Invoke(c).Prefix(prefix).ToA() - }) -} - -// Suffix adds a suffx to values (only the ones inserted, not the display values). -// -// carapace.ActionValues("apple", "melon", "orange").Suffix("juice") -func (a Action) Suffix(suffix string) Action { - return ActionCallback(func(c Context) Action { - return a.Invoke(c).Suffix(suffix).ToA() - }) -} - // Timeout sets the maximum duration an Action may take to invoke. // // carapace.ActionCallback(func(c carapace.Context) carapace.Action { @@ -252,3 +246,27 @@ func (a Action) Timeout(d time.Duration, alternative Action) Action { return result.ToA() }) } + +// UniqueList wraps the Action in an ActionMultiParts with given divider. +func (a Action) UniqueList(divider string) Action { + return ActionMultiParts(divider, func(c Context) Action { + return a.Invoke(c).Filter(c.Parts).ToA().NoSpace() + }) +} + +// Usage sets the usage. +func (a Action) Usage(usage string, args ...interface{}) Action { + return a.UsageF(func() string { + return fmt.Sprintf(usage, args...) + }) +} + +// Usage sets the usage using a function. +func (a Action) UsageF(f func() string) Action { + return ActionCallback(func(c Context) Action { + if usage := f(); usage != "" { + a.meta.Usage = usage + } + return a + }) +} diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index 1272e5f91..efc1bbf83 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -9,11 +9,13 @@ - [Action](./carapace/action.md) - [Cache](./carapace/action/cache.md) - [Chdir](./carapace/action/chdir.md) + - [Filter](./carapace/action/filter.md) - [Invoke](./carapace/action/invoke.md) - [List](./carapace/action/list.md) - [MultiParts](./carapace/action/multiParts.md) - [NoSpace](./carapace/action/noSpace.md) - [Prefix](./carapace/action/prefix.md) + - [Retain](./carapace/action/retain.md) - [Style](./carapace/action/style.md) - [StyleF](./carapace/action/styleF.md) - [StyleR](./carapace/action/styleR.md) diff --git a/docs/src/carapace/action/filter.cast b/docs/src/carapace/action/filter.cast new file mode 100644 index 000000000..6280b77d6 --- /dev/null +++ b/docs/src/carapace/action/filter.cast @@ -0,0 +1,41 @@ +{"version": 2, "width": 108, "height": 24, "timestamp": 1689158161, "env": {"SHELL": "elvish", "TERM": "tmux-256color"}} +[0.065171, "o", "\u001b[?7h\u001b[7m⏎\u001b[m \r \r\u001b[?7l\u001b[?2004h"] +[0.065792, "o", "\u001b[?25l\r???> ???> \r\u001b[5C\u001b[?25h\u001b[?25l\r\u001b[5C\u001b[K\r\u001b[5C\u001b[?25h"] +[0.074083, "o", "\u001b[?25l\r\r\u001b[5C\u001b[?25h"] +[0.074275, "o", "\u001b[?25l\r\u001b[K\r\n\u001b[0;1;36mcarapace/example\u001b[0;m on \u001b[0;1;35m action-retain\u001b[0;m \u001b[0;1;31m[$!?]\u001b[0;m via \u001b[0;1;36m🐹 v1.20.5 \r\n\u001b[0;1;37mesh\u001b[0;m \u001b[0;1;32m❯\u001b[0;m \r\u001b[6C\u001b[?25h"] +[0.587118, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[6C\u001b[0;31me\u001b[0;m\r\u001b[7C\u001b[?25h"] +[0.587557, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[7C\u001b[?25h\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[7C\u001b[?25h"] +[0.600157, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[7C\u001b[?25h"] +[0.600276, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[7C\u001b[?25h"] +[0.769978, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[7C\u001b[0;31mx\u001b[0;m\r\u001b[8C\u001b[?25h\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[8C\u001b[?25h"] +[0.906975, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[6C\u001b[K\u001b[0;32mexa\u001b[0;m\r\u001b[9C\u001b[?25h\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[9C\u001b[?25h"] +[1.008014, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[6C\u001b[K\u001b[0;31mexam\u001b[0;m\r\u001b[10C\u001b[?25h\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[10C\u001b[?25h"] +[1.06184, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[10C\u001b[0;31mp\u001b[0;m\r\u001b[11C\u001b[?25h\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[11C\u001b[?25h"] +[1.198941, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[11C\u001b[0;31ml\u001b[0;m\r\u001b[12C\u001b[?25h\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[12C\u001b[?25h"] +[1.263944, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[6C\u001b[K\u001b[0;32mexample\u001b[0;m\r\u001b[13C\u001b[?25h\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[13C\u001b[?25h"] +[1.328305, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[13C \r\u001b[14C\u001b[?25h\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[14C\u001b[?25h"] +[1.48774, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[14Cm\r\u001b[15C\u001b[?25h\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[15C\u001b[?25h"] +[1.573788, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[15Co\r\u001b[16C\u001b[?25h"] +[1.573866, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[16C\u001b[?25h"] +[1.575372, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[16C\u001b[?25h"] +[1.575431, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[16C\u001b[?25h"] +[1.694119, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[16Cdifier \r\u001b[23C\u001b[?25h"] +[2.106809, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[23C-\r\u001b[24C\u001b[?25h"] +[2.106893, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[24C\u001b[?25h"] +[2.262227, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[24C-\r\u001b[25C\u001b[?25h\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[25C\u001b[?25h"] +[2.516307, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[25Cf\r\u001b[26C\u001b[?25h\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[26C\u001b[?25h"] +[2.642845, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[26Ci\r\u001b[27C\u001b[?25h\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[27C\u001b[?25h"] +[2.824332, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[27Clter \r\u001b[32C\u001b[?25h"] +[3.289998, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[32C\u001b[0;4m1 \r\n\u001b[0;1;37;45m COMPLETING argument \u001b[0;m \r\n\u001b[0;7m1\u001b[0;2;7m (one)\u001b[0;m 3\u001b[0;2m (three)\u001b[0;m\u001b[1A\r\u001b[22C\u001b[?25h"] +[4.228643, "o", "\u001b[?25l\u001b[3A\r\r\n\r\n\u001b[32C\u001b[K\u001b[0;4m3 \r\n\r\n\u001b[0;m\u001b[K1\u001b[0;2m (one)\u001b[0;m \u001b[0;7m3\u001b[0;2;7m (three)\u001b[0;m\u001b[1A\r\u001b[22C\u001b[?25h"] +[5.733904, "o", "\u001b[?25l\u001b[3A\r\r\n\r\n\u001b[6C\u001b[K\r\n\u001b[J\u001b[A\r\u001b[6C\u001b[?25h"] +[5.734661, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[6C\u001b[?25h"] +[5.752609, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[6C\u001b[?25h\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[6C\u001b[?25h"] +[5.752756, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[6C\u001b[?25h"] +[5.969899, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[6C\u001b[0;31me\u001b[0;m\r\u001b[7C\u001b[?25h\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[7C\u001b[?25h"] +[6.212241, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[7C\u001b[0;31mx\u001b[0;m\r\u001b[8C\u001b[?25h"] +[6.212335, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[8C\u001b[?25h"] +[6.3745, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[8C\u001b[0;31mi\u001b[0;m\r\u001b[9C\u001b[?25h\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[9C\u001b[?25h"] +[6.445559, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[6C\u001b[K\u001b[0;32mexit\u001b[0;m\r\u001b[10C\u001b[?25h\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[10C\u001b[?25h"] +[6.624242, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\r\n\r\u001b[?25h"] +[6.624648, "o", "\u001b[?7h\u001b[?2004l\r"] diff --git a/docs/src/carapace/action/filter.md b/docs/src/carapace/action/filter.md new file mode 100644 index 000000000..394e4eaa0 --- /dev/null +++ b/docs/src/carapace/action/filter.md @@ -0,0 +1,16 @@ +# Filter + +[`Filter`] filters given values. + +```go +carapace.ActionValuesDescribed( + "1", "one", + "2", "two", + "3", "three", + "4", "four", +).Filter([]string{"2", "4"}) +``` + +![](./filter.cast) + +[`Filter`]: https://pkg.go.dev/github.com/rsteube/carapace#Action.Filter diff --git a/docs/src/carapace/action/retain.cast b/docs/src/carapace/action/retain.cast new file mode 100644 index 000000000..c0db79cb2 --- /dev/null +++ b/docs/src/carapace/action/retain.cast @@ -0,0 +1,41 @@ +{"version": 2, "width": 108, "height": 24, "timestamp": 1689158181, "env": {"SHELL": "elvish", "TERM": "tmux-256color"}} +[0.070882, "o", "\u001b[?7h\u001b[7m⏎\u001b[m \r \r\u001b[?7l\u001b[?2004h"] +[0.071423, "o", "\u001b[?25l\r???> ???> \r\u001b[5C\u001b[?25h\u001b[?25l\r\u001b[5C\u001b[K\r\u001b[5C\u001b[?25h"] +[0.083515, "o", "\u001b[?25l\r\r\u001b[5C\u001b[?25h"] +[0.083754, "o", "\u001b[?25l\r\u001b[K\r\n\u001b[0;1;36mcarapace/example\u001b[0;m on \u001b[0;1;35m action-retain\u001b[0;m \u001b[0;1;31m[$!?]\u001b[0;m via \u001b[0;1;36m🐹 v1.20.5 \r\n\u001b[0;1;37mesh\u001b[0;m \u001b[0;1;32m❯\u001b[0;m \r\u001b[6C\u001b[?25h"] +[0.412814, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[6C\u001b[0;31me\u001b[0;m\r\u001b[7C\u001b[?25h\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[7C\u001b[?25h"] +[0.41334, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[7C\u001b[?25h"] +[0.423245, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[7C\u001b[?25h\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[7C\u001b[?25h"] +[0.588142, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[7C\u001b[0;31mx\u001b[0;m\r\u001b[8C\u001b[?25h\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[8C\u001b[?25h"] +[0.735276, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[6C\u001b[K\u001b[0;32mexa\u001b[0;m\r\u001b[9C\u001b[?25h"] +[0.735347, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[9C\u001b[?25h"] +[0.837106, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[6C\u001b[K\u001b[0;31mexam\u001b[0;m\r\u001b[10C\u001b[?25h\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[10C\u001b[?25h"] +[0.876364, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[10C\u001b[0;31mp\u001b[0;m\r\u001b[11C\u001b[?25h\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[11C\u001b[?25h"] +[1.038023, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[11C\u001b[0;31ml\u001b[0;m\r\u001b[12C\u001b[?25h\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[12C\u001b[?25h"] +[1.106702, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[6C\u001b[K\u001b[0;32mexample\u001b[0;m\r\u001b[13C\u001b[?25h"] +[1.106807, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[13C\u001b[?25h"] +[1.204027, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[13C \r\u001b[14C\u001b[?25h\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[14C\u001b[?25h"] +[1.343381, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[14Cm\r\u001b[15C\u001b[?25h\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[15C\u001b[?25h"] +[1.410835, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[15Co\r\u001b[16C\u001b[?25h\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[16C\u001b[?25h"] +[1.551868, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[16Cdifier \r\u001b[23C\u001b[?25h"] +[1.919688, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[23C-\r\u001b[24C\u001b[?25h\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[24C\u001b[?25h"] +[2.053776, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[24C-\r\u001b[25C\u001b[?25h"] +[2.053872, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[25C\u001b[?25h"] +[2.378561, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[25Cr\r\u001b[26C\u001b[?25h\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[26C\u001b[?25h"] +[2.466607, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[26Ce\r\u001b[27C\u001b[?25h"] +[2.466684, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[27C\u001b[?25h"] +[2.656245, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[27Ctain \r\u001b[32C\u001b[?25h"] +[3.133397, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[32C\u001b[0;4m2 \r\n\u001b[0;1;37;45m COMPLETING argument \u001b[0;m \r\n\u001b[0;7m2\u001b[0;2;7m (two)\u001b[0;m 4\u001b[0;2m (four)\u001b[0;m\u001b[1A\r\u001b[22C\u001b[?25h"] +[3.774198, "o", "\u001b[?25l\u001b[3A\r\r\n\r\n\u001b[32C\u001b[K\u001b[0;4m4 \r\n\r\n\u001b[0;m\u001b[K2\u001b[0;2m (two)\u001b[0;m \u001b[0;7m4\u001b[0;2;7m (four)\u001b[0;m\u001b[1A\r\u001b[22C\u001b[?25h"] +[5.468723, "o", "\u001b[?25l\u001b[3A\r\r\n\r\n\u001b[6C\u001b[K\r\n\u001b[J\u001b[A\r\u001b[6C\u001b[?25h\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[6C\u001b[?25h"] +[5.469673, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[6C\u001b[?25h"] +[5.486014, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[6C\u001b[?25h\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[6C\u001b[?25h"] +[5.48608, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[6C\u001b[?25h"] +[5.740105, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[6C\u001b[0;31me\u001b[0;m\r\u001b[7C\u001b[?25h"] +[5.740396, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[7C\u001b[?25h"] +[5.943355, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[7C\u001b[0;31mx\u001b[0;m\r\u001b[8C\u001b[?25h"] +[5.94357, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[8C\u001b[?25h"] +[6.054215, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[8C\u001b[0;31mi\u001b[0;m\r\u001b[9C\u001b[?25h\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[9C\u001b[?25h"] +[6.180112, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[6C\u001b[K\u001b[0;32mexit\u001b[0;m\r\u001b[10C\u001b[?25h"] +[6.180364, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[10C\u001b[?25h\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[10C\u001b[?25h"] +[6.333115, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\r\n\r\u001b[?25h\u001b[?7h\u001b[?2004l\r"] diff --git a/docs/src/carapace/action/retain.md b/docs/src/carapace/action/retain.md new file mode 100644 index 000000000..2580d6aae --- /dev/null +++ b/docs/src/carapace/action/retain.md @@ -0,0 +1,16 @@ +# Retain + +[`Retain`] retains given values. + +```go +carapace.ActionValuesDescribed( + "1", "one", + "2", "two", + "3", "three", + "4", "four", +).Retain([]string{"2", "4"}) +``` + +![](./retain.cast) + +[`Retain`]: https://pkg.go.dev/github.com/rsteube/carapace#Action.Retain diff --git a/example/cmd/modifier.go b/example/cmd/modifier.go index 547be49dc..fb246735b 100644 --- a/example/cmd/modifier.go +++ b/example/cmd/modifier.go @@ -25,11 +25,13 @@ func init() { modifierCmd.Flags().String("cache", "", "Cache()") modifierCmd.Flags().String("cache-key", "", "Cache()") modifierCmd.Flags().String("chdir", "", "Chdir()") + modifierCmd.Flags().String("filter", "", "Filter()") modifierCmd.Flags().String("invoke", "", "Invoke()") modifierCmd.Flags().String("list", "", "List()") modifierCmd.Flags().String("multiparts", "", "MultiParts()") modifierCmd.Flags().String("nospace", "", "NoSpace()") modifierCmd.Flags().String("prefix", "", "Prefix()") + modifierCmd.Flags().String("retain", "", "Retain()") modifierCmd.Flags().String("style", "", "Style()") modifierCmd.Flags().String("stylef", "", "StyleF()") modifierCmd.Flags().String("styler", "", "StyleR()") @@ -76,7 +78,13 @@ func init() { } }), "chdir": carapace.ActionFiles().Chdir(os.TempDir()), - "list": carapace.ActionValues("one", "two", "three").List(","), + "filter": carapace.ActionValuesDescribed( + "1", "one", + "2", "two", + "3", "three", + "4", "four", + ).Filter([]string{"2", "4"}), + "list": carapace.ActionValues("one", "two", "three").List(","), "invoke": carapace.ActionCallback(func(c carapace.Context) carapace.Action { if !strings.HasPrefix(c.Value, "file://") { return carapace.ActionValues("file://").NoSpace() @@ -121,6 +129,12 @@ func init() { "drop", "fall", ).Prefix("water"), + "retain": carapace.ActionValuesDescribed( + "1", "one", + "2", "two", + "3", "three", + "4", "four", + ).Retain([]string{"2", "4"}), "style": carapace.ActionValues( "one", "two", diff --git a/example/cmd/modifier_test.go b/example/cmd/modifier_test.go index d462273c4..7539969a7 100644 --- a/example/cmd/modifier_test.go +++ b/example/cmd/modifier_test.go @@ -21,6 +21,26 @@ func TestBatch(t *testing.T) { }) } +func TestFilter(t *testing.T) { + sandbox.Package(t, "github.com/rsteube/carapace/example")(func(s *sandbox.Sandbox) { + s.Run("modifier", "--filter", ""). + Expect(carapace.ActionValuesDescribed( + "1", "one", + "3", "three", + ).Usage("Filter()")) + }) +} + +func TestRetain(t *testing.T) { + sandbox.Package(t, "github.com/rsteube/carapace/example")(func(s *sandbox.Sandbox) { + s.Run("modifier", "--retain", ""). + Expect(carapace.ActionValuesDescribed( + "2", "two", + "4", "four", + ).Usage("Retain()")) + }) +} + func TestTimeout(t *testing.T) { sandbox.Package(t, "github.com/rsteube/carapace/example")(func(s *sandbox.Sandbox) { s.Run("modifier", "--timeout", "1s:"). diff --git a/internal/common/value.go b/internal/common/value.go index a6b11aaec..a67d714f9 100644 --- a/internal/common/value.go +++ b/internal/common/value.go @@ -82,6 +82,21 @@ func (r RawValues) Filter(values ...string) RawValues { return filtered } +// Retain retains given values. +func (r RawValues) Retain(values ...string) RawValues { + toretain := make(map[string]bool) + for _, v := range values { + toretain[v] = true + } + filtered := make([]RawValue, 0) + for _, rawValue := range r { + if _, ok := toretain[rawValue.Value]; ok { + filtered = append(filtered, rawValue) + } + } + return filtered +} + // Decolor clears style for all values. func (r RawValues) Decolor() RawValues { rawValues := make(RawValues, len(r)) diff --git a/invokedAction.go b/invokedAction.go index 0b1d603d6..8b84d93b4 100644 --- a/invokedAction.go +++ b/invokedAction.go @@ -17,7 +17,7 @@ func (a InvokedAction) export() export.Export { return export.Export{Meta: a.meta, Values: a.rawValues} } -// Filter filters given values (this should be done before any call to Prefix/Suffix as those alter the values being filtered) +// Filter filters given values. // // a := carapace.ActionValues("A", "B", "C").Invoke(c) // b := a.Filter([]string{"B"}) // ["A", "C"] @@ -50,6 +50,15 @@ func (a InvokedAction) Prefix(prefix string) InvokedAction { return a } +// Retain retains given values. +// +// a := carapace.ActionValues("A", "B", "C").Invoke(c) +// b := a.Retain([]string{"A", "C"}) // ["A", "C"] +func (a InvokedAction) Retain(values []string) InvokedAction { + a.rawValues = a.rawValues.Retain(values...) + return a +} + // Suffix adds a suffx to values (only the ones inserted, not the display values) // // carapace.ActionValues("apple", "melon", "orange").Invoke(c).Suffix("juice")