diff --git a/action.go b/action.go index 0344e96..ed4ed3c 100644 --- a/action.go +++ b/action.go @@ -13,6 +13,23 @@ import ( "gopkg.in/yaml.v3" ) +// ActionMacro completes given macro +func ActionMacro(s string) carapace.Action { + return carapace.ActionCallback(func(c carapace.Context) carapace.Action { + r := regexp.MustCompile(`^\$(?P[^(]*)(\((?P.*)\))?$`) + if !r.MatchString(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) + } else { + return m.f(matches["arg"]) + } + }) +} + // ActionSpec completes a spec func ActionSpec(path string) carapace.Action { return carapace.ActionCallback(func(c carapace.Context) carapace.Action { @@ -94,7 +111,7 @@ func parseAction(cmd *cobra.Command, arr []string) carapace.Action { } batch = append(batch, carapace.ActionStyledValuesDescribed(vals...)) - action := batch.ToA() + action := batch.Invoke(c).Merge().ToA() // invoke eagerly so that the modifier macros are called if chdir != "" { action = action.Chdir(chdir) } diff --git a/docs/book.toml b/docs/book.toml index 4a445b6..918fda7 100644 --- a/docs/book.toml +++ b/docs/book.toml @@ -9,5 +9,7 @@ title = "carapace-spec" default-theme = "Mocha" additional-css = ["asciinema/asciinema-player.css", "./theme/catppuccin.css", "./theme/catppuccin-highlight.css"] additional-js = ["asciinema/asciinema-player.min.js", "asciinema/load.js"] +git-repository-url = "https://github.com/rsteube/carapace-spec" +edit-url-template = "https://github.com/rsteube/carapace-spec/edit/master/docs/{path}" #[output.linkcheck] diff --git a/docs/src/carapace-spec/macros.md b/docs/src/carapace-spec/macros.md index 48841ab..13e2265 100644 --- a/docs/src/carapace-spec/macros.md +++ b/docs/src/carapace-spec/macros.md @@ -2,4 +2,4 @@ Macros are basically [Actions](https://rsteube.github.io/carapace/carapace/action.html) exposed to the spec (E.g. [`$files([.go, go.mod])`](https://rsteube.github.io/carapace/carapace/action/actionFiles.html). -The brackets are optional if no argument is passed (so `$files` is equivalent to `$files()`). +> The brackets are optional if no argument is passed (so `$files` is equivalent to `$files()`). diff --git a/docs/src/carapace-spec/macros/core.md b/docs/src/carapace-spec/macros/core.md index 2ed50aa..112b933 100644 --- a/docs/src/carapace-spec/macros/core.md +++ b/docs/src/carapace-spec/macros/core.md @@ -9,7 +9,7 @@ Core macros provided by [carapace-spec](https://github.com/rsteube/carapace-spec ["$directories"] ``` -## execcommand +## exec [`$()`](https://rsteube.github.io/carapace/carapace/action/actionExecCommand.html) executes given command in a `sh` / `pwsh` shell. diff --git a/docs/src/carapace-spec/macros/custom.md b/docs/src/carapace-spec/macros/custom.md index 82be19c..07e7f1d 100644 --- a/docs/src/carapace-spec/macros/custom.md +++ b/docs/src/carapace-spec/macros/custom.md @@ -13,7 +13,7 @@ AddMacro("arg", MacroI(func(u User) carapace.Action { return carapace.ActionValu AddMacro("vararg", MacroV(func(s ...string) carapace.Action { return carapace.ActionValues()})) ``` -Arguments are parsed as `yaml` so only struct keys deviating from the default need to be set. +> Arguments are parsed as `yaml` so only struct keys deviating from the default need to be set. ## Default (experimental) diff --git a/docs/src/carapace-spec/macros/modifier.md b/docs/src/carapace-spec/macros/modifier.md index 05b1cc6..f648dac 100644 --- a/docs/src/carapace-spec/macros/modifier.md +++ b/docs/src/carapace-spec/macros/modifier.md @@ -36,7 +36,7 @@ Modifiers change the completion for a position in general. ## noflag -`$noflag` disables flag parsing for the current command. +`$noflag` disables flag parsing for the corresponding (sub)command. ```yml ["$noflag"] diff --git a/macro.go b/macro.go index 35fb110..fa0b513 100644 --- a/macro.go +++ b/macro.go @@ -3,7 +3,6 @@ package spec import ( "fmt" "reflect" - "regexp" "strings" "github.com/rsteube/carapace" @@ -25,25 +24,12 @@ func addCoreMacro(s string, m Macro) { macros[s] = m } +// AddMacro adds a custom macro func AddMacro(s string, m Macro) { macros["_"+s] = m } -// ActionMacro completes given macro -func ActionMacro(s string) carapace.Action { - r := regexp.MustCompile(`^\$(?P[^(]*)(\((?P.*)\))?$`) - if !r.MatchString(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) - } else { - return m.f(matches["arg"]) - } -} - +// MacroN careates a macro without an argument func MacroN(f func() carapace.Action) Macro { return Macro{ f: func(s string) carapace.Action { @@ -53,6 +39,7 @@ func MacroN(f func() carapace.Action) Macro { } } +// MacroI careates a macro with an argument func MacroI[T any](f func(t T) carapace.Action) Macro { return Macro{ f: func(s string) carapace.Action { @@ -80,6 +67,7 @@ func MacroI[T any](f func(t T) carapace.Action) Macro { } } +// MacroV careates 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 {