From 295221d889d435b614b90a5141320984229ae46e Mon Sep 17 00:00:00 2001 From: rsteube Date: Thu, 21 Sep 2023 13:52:19 +0200 Subject: [PATCH] env: conditions --- .gitignore | 3 +- cmd/carapace-generate/gen.go | 94 +++++++++++- cmd/carapace/cmd/root.go | 69 +++++++-- docs/src/development/tools/carapace-fmt.md | 1 + .../development/tools/carapace-generate.md | 1 + docs/src/development/tools/carapace-lint.md | 1 + docs/src/development/tools/carapace-parse.md | 1 + docs/src/environment-condition.cast | 75 ++++++++++ docs/src/environment.md | 29 +++- go.mod | 10 +- go.sum | 30 ++-- internal/condition/condition.go | 19 +++ internal/condition/macro.go | 49 ++++++ pkg/actions/actions.go | 11 ++ pkg/actions/env/aws.go | 7 +- pkg/actions/env/carapace.go | 4 +- pkg/actions/env/cargo.go | 12 +- pkg/actions/env/common.go | 4 +- pkg/actions/env/common_unix.go | 4 +- pkg/actions/env/docker.go | 7 +- pkg/actions/env/env.go | 139 +++++++++++++----- pkg/actions/env/env_test.go | 4 +- pkg/actions/env/gh.go | 7 +- pkg/actions/env/git.go | 7 +- pkg/actions/env/golang.go | 6 +- pkg/actions/env/nocolor.go | 4 +- pkg/actions/env/node.go | 7 +- pkg/actions/env/rust.go | 7 +- pkg/actions/env/starship.go | 4 +- pkg/actions/env/terraform.go | 88 +++++++++++ pkg/actions/env/tofu.go | 88 +++++++++++ pkg/actions/env/xdg.go | 4 +- pkg/conditions/conditions.go | 11 ++ pkg/conditions/fs.go | 18 +++ pkg/conditions/os.go | 45 ++++++ 35 files changed, 748 insertions(+), 122 deletions(-) create mode 100644 docs/src/development/tools/carapace-fmt.md create mode 100644 docs/src/development/tools/carapace-generate.md create mode 100644 docs/src/development/tools/carapace-lint.md create mode 100644 docs/src/development/tools/carapace-parse.md create mode 100644 docs/src/environment-condition.cast create mode 100644 internal/condition/condition.go create mode 100644 internal/condition/macro.go create mode 100644 pkg/actions/actions.go create mode 100644 pkg/actions/env/terraform.go create mode 100644 pkg/actions/env/tofu.go create mode 100644 pkg/conditions/conditions.go create mode 100644 pkg/conditions/fs.go create mode 100644 pkg/conditions/os.go diff --git a/.gitignore b/.gitignore index fdb3c1f917..a10dd2ff61 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,6 @@ cmd/carapace/cmd/completers/description.go cmd/carapace/cmd/completers.go cmd/carapace/cmd/completers/name.go cmd/carapace/cmd/completers_release.go -cmd/carapace/cmd/macros.go cmd/carapace/cmd/shim/*.exe cmd/carapace-fmt/carapace-fmt cmd/carapace-generate/carapace-generate @@ -18,3 +17,5 @@ completers_release dist docs/book out.gif +pkg/actions/actions_generated.go +pkg/conditions/conditions_generated.go diff --git a/cmd/carapace-generate/gen.go b/cmd/carapace-generate/gen.go index f79c0b514c..dbbeb05582 100644 --- a/cmd/carapace-generate/gen.go +++ b/cmd/carapace-generate/gen.go @@ -18,6 +18,7 @@ import ( func main() { macros() + conditions() names, descriptions := readCompleters() @@ -269,23 +270,104 @@ func macros() { } sort.Strings(sortedDescriptions) - content := fmt.Sprintf(`package cmd + content := fmt.Sprintf(`package actions import ( %v spec "github.com/rsteube/carapace-spec" ) -var macros = map[string]spec.Macro{ +func init() { + MacroMap = map[string]spec.Macro{ %v -} + } -var macroDescriptions = map[string]string { + MacroDescriptions = map[string]string { %v + } } `, strings.Join(sortedImports, "\n"), strings.Join(macros, "\n"), strings.Join(sortedDescriptions, "\n")) - os.WriteFile(root+"/cmd/carapace/cmd/macros.go", []byte(content), 0644) - execabs.Command("go", "fmt", root+"/cmd/carapace/cmd/macros.go").Run() + os.WriteFile(root+"/pkg/actions/actions_generated.go", []byte(content), 0644) + execabs.Command("go", "fmt", root+"/pkg/actions/actions_generated.go").Run() + +} + +func conditions() { + root, err := rootDir() + if err != nil { + panic(err.Error) + } + + macros := make([]string, 0) + descriptions := make(map[string]string, 0) + + r := regexp.MustCompile(`^func Condition(?P[^(]+)\((?P[^(]*)\) condition.Condition {$`) + filepath.WalkDir(root+"/pkg/conditions", func(path string, d fs.DirEntry, err error) error { // TODO walkdir not necessary + path = filepath.ToSlash(path) + if !d.IsDir() && strings.HasSuffix(path, ".go") { + file, err := os.Open(path) + if err != nil { + log.Fatal(err) + } + defer file.Close() + + scanner := bufio.NewScanner(file) + for scanner.Scan() { + if t := scanner.Text(); strings.HasPrefix(t, "func Condition") { + if r.MatchString(t) { + matches := r.FindStringSubmatch(t) + + _func := fmt.Sprintf("Condition%v", matches[1]) + + if arg := matches[2]; strings.Contains(arg, ",") { + macros = append(macros, "// TODO unsupported signature: "+t) + continue + } else if arg == "" { + macros = append(macros, fmt.Sprintf(`"%v": condition.MacroN(%v),`, matches[1], _func)) + } else if strings.Contains(arg, "...") { + macros = append(macros, fmt.Sprintf(`"%v": condition.MacroV(%v),`, matches[1], _func)) + } else { + macros = append(macros, fmt.Sprintf(`"%v": condition.MacroI(%v),`, matches[1], _func)) + } + } + } else if strings.HasPrefix(t, "// Condition") { + if splitted := strings.SplitN(strings.TrimPrefix(t, "// Condition"), " ", 2); len(splitted) > 1 { + descriptions[splitted[0]] = splitted[1] + } + } + } + + } + return nil + }) + + sortedDescriptions := make([]string, 0) + for key, value := range descriptions { + sortedDescriptions = append(sortedDescriptions, fmt.Sprintf(`%#v: %#v,`, key, value)) + } + sort.Strings(sortedDescriptions) + + content := fmt.Sprintf(`package conditions + +import ( + "github.com/rsteube/carapace-bin/internal/condition" + "github.com/rsteube/carapace-spec/pkg/macro" +) + +func init() { + MacroMap = macro.MacroMap[condition.Macro]{ +%v + } + + MacroDescriptions = map[string]string { +%v + } + +} +`, strings.Join(macros, "\n"), strings.Join(sortedDescriptions, "\n")) + + os.WriteFile(root+"/pkg/conditions/conditions_generated.go", []byte(content), 0644) + execabs.Command("go", "fmt", root+"/pkg/conditions/conditions_generated.go").Run() } diff --git a/cmd/carapace/cmd/root.go b/cmd/carapace/cmd/root.go index d7c0d09c4a..692d7cd02d 100644 --- a/cmd/carapace/cmd/root.go +++ b/cmd/carapace/cmd/root.go @@ -17,6 +17,8 @@ import ( "github.com/rsteube/carapace" "github.com/rsteube/carapace-bin/cmd/carapace/cmd/completers" "github.com/rsteube/carapace-bin/cmd/carapace/cmd/shim" + "github.com/rsteube/carapace-bin/pkg/actions" + "github.com/rsteube/carapace-bin/pkg/conditions" spec "github.com/rsteube/carapace-spec" "github.com/rsteube/carapace/pkg/ps" "github.com/rsteube/carapace/pkg/style" @@ -63,6 +65,12 @@ var rootCmd = &cobra.Command{ Run: func(cmd *cobra.Command, args []string) { // since flag parsing is disabled do this manually switch args[0] { + case "--conditions": + if len(args) > 1 { + //printCondition(args[1]) // TODO + } else { + printConditions() // TODO + } case "--macros": if len(args) > 1 { printMacro(args[1]) @@ -121,27 +129,42 @@ var rootCmd = &cobra.Command{ fmt.Fprintln(cmd.ErrOrStderr(), err.Error()) } } + + completers := completers.Names() + if os.Getenv("CARAPACE_ENV") == "0" { + filtered := make([]string, 0, len(completers)) + for _, name := range completers { + switch name { + case "get-env", "set-env", "unset-env": + default: + filtered = append(filtered, name) + + } + } + completers = filtered + } + switch shell { case "bash": - fmt.Fprintln(cmd.OutOrStdout(), bash_lazy(completers.Names())) + fmt.Fprintln(cmd.OutOrStdout(), bash_lazy(completers)) case "bash-ble": - fmt.Fprintln(cmd.OutOrStdout(), bash_ble_lazy(completers.Names())) + fmt.Fprintln(cmd.OutOrStdout(), bash_ble_lazy(completers)) case "elvish": - fmt.Fprintln(cmd.OutOrStdout(), elvish_lazy(completers.Names())) + fmt.Fprintln(cmd.OutOrStdout(), elvish_lazy(completers)) case "fish": - fmt.Fprintln(cmd.OutOrStdout(), fish_lazy(completers.Names())) + fmt.Fprintln(cmd.OutOrStdout(), fish_lazy(completers)) case "nushell": - fmt.Fprintln(cmd.OutOrStdout(), nushell_lazy(completers.Names())) + fmt.Fprintln(cmd.OutOrStdout(), nushell_lazy(completers)) case "oil": - fmt.Fprintln(cmd.OutOrStdout(), oil_lazy(completers.Names())) + fmt.Fprintln(cmd.OutOrStdout(), oil_lazy(completers)) case "powershell": - fmt.Fprintln(cmd.OutOrStdout(), powershell_lazy(completers.Names())) + fmt.Fprintln(cmd.OutOrStdout(), powershell_lazy(completers)) case "tcsh": - fmt.Fprintln(cmd.OutOrStdout(), tcsh_lazy(completers.Names())) + fmt.Fprintln(cmd.OutOrStdout(), tcsh_lazy(completers)) case "xonsh": - fmt.Fprintln(cmd.OutOrStdout(), xonsh_lazy(completers.Names())) + fmt.Fprintln(cmd.OutOrStdout(), xonsh_lazy(completers)) case "zsh": - fmt.Fprintln(cmd.OutOrStdout(), zsh_lazy(completers.Names())) + fmt.Fprintln(cmd.OutOrStdout(), zsh_lazy(completers)) default: fmt.Fprintln(os.Stderr, "could not determine shell") } @@ -286,10 +309,26 @@ func printCompletersJson() { } } +func printConditions() { + maxlen := 0 + names := make([]string, 0) + for name := range conditions.MacroMap { + names = append(names, name) + if len := len(name); len > maxlen { + maxlen = len + } + } + + sort.Strings(names) + for _, name := range names { + fmt.Printf("%-"+strconv.Itoa(maxlen)+"v %v\n", name, conditions.MacroDescriptions[name]) + } +} + func printMacros() { maxlen := 0 names := make([]string, 0) - for name := range macros { + for name := range actions.MacroMap { names = append(names, name) if len := len(name); len > maxlen { maxlen = len @@ -298,12 +337,12 @@ func printMacros() { sort.Strings(names) for _, name := range names { - fmt.Printf("%-"+strconv.Itoa(maxlen)+"v %v\n", name, macroDescriptions[name]) + fmt.Printf("%-"+strconv.Itoa(maxlen)+"v %v\n", name, actions.MacroDescriptions[name]) } } func printMacro(name string) { - if m, ok := macros[name]; ok { + if m, ok := actions.MacroMap[name]; ok { path := strings.Replace(name, ".", "/", -1) signature := "" if s := m.Signature(); s != "" { @@ -313,7 +352,7 @@ func printMacro(name string) { fmt.Printf(`signature: $_%v%v description: %v reference: https://pkg.go.dev/github.com/rsteube/carapace-bin/pkg/actions/%v#Action%v -`, name, signature, macroDescriptions[name], filepath.Dir(path), filepath.Base(path)) +`, name, signature, actions.MacroDescriptions[name], filepath.Dir(path), filepath.Base(path)) } } @@ -406,7 +445,7 @@ func init() { rootCmd.Flags().String("scrape", "", "scrape spec to go code") rootCmd.Flags().String("style", "", "set style") - for m, f := range macros { + for m, f := range actions.MacroMap { spec.AddMacro(m, f) } } diff --git a/docs/src/development/tools/carapace-fmt.md b/docs/src/development/tools/carapace-fmt.md new file mode 100644 index 0000000000..761c9238a9 --- /dev/null +++ b/docs/src/development/tools/carapace-fmt.md @@ -0,0 +1 @@ +# carapace-fmt diff --git a/docs/src/development/tools/carapace-generate.md b/docs/src/development/tools/carapace-generate.md new file mode 100644 index 0000000000..6906e62f25 --- /dev/null +++ b/docs/src/development/tools/carapace-generate.md @@ -0,0 +1 @@ +# carapace-generate diff --git a/docs/src/development/tools/carapace-lint.md b/docs/src/development/tools/carapace-lint.md new file mode 100644 index 0000000000..02bc59ead1 --- /dev/null +++ b/docs/src/development/tools/carapace-lint.md @@ -0,0 +1 @@ +# carapace-lint diff --git a/docs/src/development/tools/carapace-parse.md b/docs/src/development/tools/carapace-parse.md new file mode 100644 index 0000000000..04272e4caf --- /dev/null +++ b/docs/src/development/tools/carapace-parse.md @@ -0,0 +1 @@ +# carapace-parse diff --git a/docs/src/environment-condition.cast b/docs/src/environment-condition.cast new file mode 100644 index 0000000000..f69c6f8166 --- /dev/null +++ b/docs/src/environment-condition.cast @@ -0,0 +1,75 @@ +{"version": 2, "width": 108, "height": 24, "timestamp": 1695398869, "env": {"SHELL": "elvish", "TERM": "tmux-256color"}} +[0.092246, "o", "\u001b[?7h\u001b[7m⏎\u001b[m \r \r\u001b[?7l\u001b[?2004h"] +[0.092819, "o", "\u001b[?25l\r???> ???> \r\u001b[5C\u001b[?25h\u001b[?25l\r\u001b[5C\u001b[K\r\u001b[5C\u001b[?25h"] +[0.111124, "o", "\u001b[?25l\r\r\u001b[5C\u001b[?25h"] +[0.111245, "o", "\u001b[?25l\r\u001b[K\r\n\u001b[0;1;36mcarapace-bin\u001b[0;m on \u001b[0;1;35mξ‚  env-condition\u001b[0;m via \u001b[0;1;36m🐹 v1.21.1 \r\n\u001b[0;1;37mesh\u001b[0;m \u001b[0;1;32m❯\u001b[0;m \r\u001b[6C\u001b[?25h"] +[0.681095, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[6C\u001b[0;31ms\u001b[0;m\r\u001b[7C\u001b[?25h\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[7C\u001b[?25h"] +[0.681623, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[7C\u001b[?25h"] +[0.716204, "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.768028, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[7C\u001b[0;31me\u001b[0;m\r\u001b[8C\u001b[?25h\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[8C\u001b[?25h"] +[0.867447, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[6C\u001b[K\u001b[0;32mset\u001b[0;m\r\u001b[9C\u001b[?25h\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[9C\u001b[?25h"] +[0.96114, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[6C\u001b[K\u001b[0;31mset-\u001b[0;m\r\u001b[10C\u001b[?25h"] +[0.961535, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[10C\u001b[?25h"] +[0.962133, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[10C\u001b[?25h"] +[1.076815, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[10C\u001b[0;31me\u001b[0;m\r\u001b[11C\u001b[?25h\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[11C\u001b[?25h"] +[1.172287, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[11C\u001b[0;31mn\u001b[0;m\r\u001b[12C\u001b[?25h\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[12C\u001b[?25h"] +[1.291771, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[6C\u001b[K\u001b[0;32mset-env\u001b[0;m\r\u001b[13C\u001b[?25h\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[13C\u001b[?25h"] +[1.383674, "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.722694, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[14C\u001b[0;4mAR \r\n\u001b[0;1;37;45m COMPLETING argument \u001b[0;m \r\n\u001b[0;7mAR\u001b[0;2;7m (The command to use to manipulate library archives when building with the gccg...)\u001b[0;m \u001b[0;34mDOCKER_HIDE_LEGACY_CO\r\nASCIINEMA_REC\u001b[0;2m (1) \u001b[0;m \u001b[0;34mEDITOR\u001b[0;2m (/usr/bin/heli\r\n\u001b[0;mAWS_ FC\u001b[0;2m (The command to us\r\n\u001b[0;mBUILDKIT_ GCCGO\u001b[0;2m (The gccgo comm\r\n\u001b[0;mCARAPACE_ GCCGOTOOLDIR\u001b[0;2m (If set,\r\n\u001b[0;34mCARAPACE_MATCH\u001b[0;2m (1) \u001b[0;m GH_ \r\nCARGO_ GIT_ \r\nCC\u001b[0;2m (The command to use to compile C code) \u001b[0;m GO111MODULE\u001b[0;2m (Controls\r\n\u001b[0;mCGO_ GO386\u001b[0;2m (For GOARCH=386\r\n\u001b[0;34mCLOUDSDK_PYTHON\u001b[0;2m (/usr/bin/python) \u001b[0;m GOAMD64\u001b[0;2m (For GOARCH=a\r\n\u001b[0;34mCLOUDSDK_PYTHON_ARGS\u001b[0;2m (-S) \u001b[0;m GOARCH\u001b[0;2m (The architect\r\n\u001b[0;34mCLOUDSDK_ROOT_DIR\u001b[0;2m (/opt/google-cloud-cli) \u001b[0;m GOARM\u001b[0;2m (For GOARCH=arm\r\n\u001b[0;34mCOLORTERM\u001b[0;2m (truecolor) \u001b[0;m GOBIN\u001b[0;2m (The directory \r\n\u001b[0;mCUSTOM_ GOCACHE\u001b[0;2m (The director\r\n\u001b[0;mCXX\u001b[0;2m (The command to use to compile C++ code) \u001b[0;m GOCOVERDIR\u001b[0;2m (Directory\r\n\u001b[0;34mDBUS_SESSION_BUS_ADDRESS\u001b[0;2m (unix:path=/run/user/1000/bus) \u001b[0;m GODEBUG\u001b[0;2m (Enable vario\r\n\u001b[0;34mDEBUGINFOD_URLS\u001b[0;2m (https://debuginfod.archlinux.org) \u001b[0;m GOENV\u001b[0;2m (The location o\r\n\u001b[0;34mDISPLAY\u001b[0;2m (:0) \u001b[0;m GOEXE\u001b[0;2m (The executable\r\n\u001b[0;mDOCKER_ GOEXPERIMENT\u001b[0;2m (Comma-s\r\n\u001b[0;7;35m \u001b[0;35m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0;m\u001b[20A\r\u001b[22C\u001b[?25h"] +[2.049261, "o", "\u001b[?25l\u001b[3A\r\r\n\r\n\r\n\u001b[22Cc\r\n\u001b[87C\u001b[KGO111MODULE\u001b[0;2m (Controls\r\n\u001b[87C\u001b[0;m\u001b[KGO386\u001b[0;2m (For GOARCH=386\r\n\u001b[0;m\u001b[KCARAPACE_ GOAMD64\u001b[0;2m (For GOARCH=a\r\n\u001b[0;m\u001b[K\u001b[0;34mCARAPACE_MATCH\u001b[0;2m (1) \u001b[0;m GOARCH\u001b[0;2m (The architect\r\n\u001b[3C\u001b[0;m\u001b[KGO_ GOARM\u001b[0;2m (For GOARCH=arm\r\n\u001b[0;m\u001b[KCC\u001b[0;2m (The command to use to compile C code) \u001b[0;m GOBIN\u001b[0;2m (The directory \r\n\u001b[1C\u001b[0;m\u001b[KGO_ GOCACHE\u001b[0;2m (The director\r\n\u001b[0;m\u001b[K\u001b[0;34mCLOUDSDK_PYTHON\u001b[0;2m (/usr/bin/python) \u001b[0;m GOCOVERDIR\u001b[0;2m (Directory\r\n\u001b[0;m\u001b[K\u001b[0;34mCLOUDSDK_PYTHON_ARGS\u001b[0;2m (-S) \u001b[0;m GODEBUG\u001b[0;2m (Enable vario\r\n\u001b[9C\u001b[0;m\u001b[K\u001b[0;34mROOT_DIR\u001b[0;2m (/opt/google-cloud-cli) \u001b[0;m GOENV\u001b[0;2m (The location o\r\n\u001b[1C\u001b[0;m\u001b[K\u001b[0;34mOLORTERM\u001b[0;2m (truecolor) \u001b[0;m GOEXE\u001b[0;2m (The executable\r\n\u001b[0;m\u001b[KCUSTOM_ GOEXPERIMENT\u001b[0;2m (Comma-s\r\n\u001b[0;m\u001b[KCXX\u001b[0;2m (The command to use to compile C++ code) \u001b[0;m GOFLAGS\u001b[0;2m (A space-sepa\r\n\u001b[0;m\u001b[K\u001b[0;34mDEBUGINFOD_URLS\u001b[0;2m (https://debuginfod.archlinux.org) \u001b[0;m GOGCCFLAGS\u001b[0;2m (A space-s\r\n\u001b[0;m\u001b[KDOCKER_ GOHOSTARCH\u001b[0;2m (The archi\r\n\u001b[1C\u001b[0;m\u001b[K\u001b[0;34mOCKER_HIDE_LEGACY_COMMANDS\u001b[0;2m (1) \u001b[0;m GOHOSTOS\u001b[0;2m (The operati\r\n\u001b[0;m\u001b[KFC\u001b[0;2m (The command to use to compile Fortran code) \u001b[0;m GOINSECURE\u001b[0;2m (Comma-sep\r\n\u001b[0;m\u001b[KGCCGO\u001b[0;2m (The gccgo command to run for 'go build -compiler=gccgo') \u001b[0;m GOMIPS\u001b[0;2m (For GOARCH=mi\r\n\u001b[0;m\u001b[KGCCGOTOOLDIR\u001b[0;2m (If set, where to find gccgo tools, such as cgo) \u001b[0;m GOMIPS64\u001b[0;2m (For GOARCH=\r\n\u001b[32C\u001b[0;m\u001b[K\u001b[0;7;35m \u001b[0;35m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0;m\u001b[20A\r\u001b[23C\u001b[?25h"] +[2.050627, "o", "\u001b[?25l\u001b[3A\r\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\u001b[20A\r\u001b[23C\u001b[?25h"] +[2.055688, "o", "\u001b[?25l\u001b[3A\r\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\u001b[20A\r\u001b[23C\u001b[?25h"] +[2.126031, "o", "\u001b[?25l\u001b[3A\r\r\n\r\n\u001b[14C\u001b[K\u001b[0;4mCUSTOM_\r\n\u001b[23C\u001b[0;mu\r\n\u001b[K\u001b[0;7mCUSTOM_ \r\n\u001b[0;m\u001b[KGOEXE\u001b[0;2m (The executable file name suffix (\".exe\" on Windows, \"\" on other systems))\r\n\u001b[0;m\u001b[KGOINSECURE\u001b[0;2m (Comma-separated list of glob patterns) \r\n\u001b[0;m\u001b[K\u001b[0;34mPWD\u001b[0;2m (/home/rsteube/Documents/development/github/carapace-bin) \r\n\u001b[0;m\u001b[K\u001b[0;34mXCURSOR_SIZE\u001b[0;2m (24) \r\n\u001b[0;m\u001b[K\u001b[0;34mXDG_CURRENT_DESKTOP\u001b[0;2m (sway) \u001b[0;m\r\n\u001b[J\u001b[A\u001b[6A\r\u001b[24C\u001b[?25h"] +[2.260879, "o", "\u001b[?25l\u001b[3A\r\r\n\r\n\r\n\u001b[24Cs\r\n\u001b[7C\u001b[K\r\n\u001b[J\u001b[A\u001b[1A\r\u001b[25C\u001b[?25h"] +[2.731591, "o", "\u001b[?25l\u001b[3A\r\r\n\r\n\u001b[14C\u001b[KCUSTOM_\r\n\u001b[J\u001b[A\r\u001b[21C\u001b[?25h\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[21C\u001b[?25h"] +[2.731749, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[21C\u001b[?25h"] +[2.976598, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[14C\u001b[K\u001b[0;4mCUSTOM_CONDITION \r\n\u001b[0;1;37;45m COMPLETING argument \u001b[0;m \r\n\u001b[0;7mCUSTOM_CONDITION\u001b[0;2;7m (condition example) \u001b[0;m CUSTOM_MACRO\u001b[0;2m (macro example)\r\n\u001b[0;mCUSTOM_EXAMPLE\u001b[0;2m (example environment variable)\u001b[0;m\u001b[2A\r\u001b[22C\u001b[?25h"] +[2.976935, "o", "\u001b[?25l\u001b[3A\r\r\n\r\n\r\n\r\n\r\n\u001b[2A\r\u001b[22C\u001b[?25h"] +[2.977079, "o", "\u001b[?25l\u001b[3A\r\r\n\r\n\r\n\r\n\r\n\u001b[2A\r\u001b[22C\u001b[?25h"] +[3.647594, "o", "\u001b[?25l\u001b[3A\r\r\n\r\n\u001b[14C\u001b[KCUSTOM_CONDITION \r\n\u001b[J\u001b[A\r\u001b[31C\u001b[?25h"] +[3.966445, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[31C\u001b[0;4mgit \r\n\u001b[0;1;37;45m COMPLETING argument \u001b[0;m \r\n\u001b[0;7mgit\u001b[0;m repo within\u001b[1A\r\u001b[22C\u001b[?25h"] +[6.040677, "o", "\u001b[?25l\u001b[3A\r\r\n\r\n\u001b[31C\u001b[K\r\n\u001b[J\u001b[A\r\u001b[31C\u001b[?25h"] +[6.273995, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[6C\u001b[K\r\u001b[6C\u001b[?25h\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[6C\u001b[?25h"] +[6.274588, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[6C\u001b[?25h"] +[6.30132, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[6C\u001b[?25h"] +[6.301403, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[6C\u001b[?25h"] +[6.846963, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[6C\u001b[0;31mc\u001b[0;m\r\u001b[7C\u001b[?25h\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[7C\u001b[?25h"] +[6.900399, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[6C\u001b[K\u001b[0;32mcd\u001b[0;m\r\u001b[8C\u001b[?25h\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[8C\u001b[?25h"] +[6.963468, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[8C \r\u001b[9C\u001b[?25h\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[9C\u001b[?25h"] +[7.115758, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[9C/\r\u001b[10C\u001b[?25h\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[10C\u001b[?25h"] +[7.245796, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[10Ct\r\u001b[11C\u001b[?25h\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[11C\u001b[?25h"] +[7.337438, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[11Cm\r\u001b[12C\u001b[?25h\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[12C\u001b[?25h"] +[7.441723, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[12Cp/\r\u001b[14C\u001b[?25h"] +[7.863996, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\r\n\r\u001b[?25h\u001b[?7h\u001b[?2004l\r"] +[7.924335, "o", "\u001b[?7h\u001b[7m⏎\u001b[m \r \r\u001b[?7l\u001b[?2004h"] +[7.92561, "o", "\u001b[?25l\r\r\n\u001b[0;1;36mcarapace-bin\u001b[0;m on \u001b[0;1;35mξ‚  env-condition\u001b[0;m via \u001b[0;1;36m🐹 v1.21.1 \r\n\u001b[0;1;37mesh\u001b[0;m \u001b[0;1;32m❯\u001b[0;m \r\u001b[6C\u001b[?25h"] +[7.927035, "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"] +[7.942635, "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"] +[7.942696, "o", "\u001b[?25l\u001b[2A\r\r\n\u001b[K\u001b[0;1;36m/tmp\u001b[0;m \r\n\r\u001b[6C\u001b[?25h"] +[8.317012, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[6C\u001b[0;31ms\u001b[0;m\r\u001b[7C\u001b[?25h\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"] +[8.32724, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[7C\u001b[?25h"] +[8.327358, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[7C\u001b[?25h"] +[8.374677, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[7C\u001b[0;31me\u001b[0;m\r\u001b[8C\u001b[?25h"] +[8.456446, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[6C\u001b[K\u001b[0;32mset\u001b[0;m\r\u001b[9C\u001b[?25h\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[9C\u001b[?25h"] +[8.539056, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[6C\u001b[K\u001b[0;31mset-\u001b[0;m\r\u001b[10C\u001b[?25h\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[10C\u001b[?25h"] +[8.645899, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[10C\u001b[0;31me\u001b[0;m\r\u001b[11C\u001b[?25h\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[11C\u001b[?25h"] +[8.780566, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[11C\u001b[0;31mn\u001b[0;m\r\u001b[12C\u001b[?25h\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[12C\u001b[?25h"] +[8.881374, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[6C\u001b[K\u001b[0;32mset-env\u001b[0;m\r\u001b[13C\u001b[?25h\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[13C\u001b[?25h"] +[8.989185, "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"] +[9.710983, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[14C\u001b[0;4mAR \r\n\u001b[0;1;37;45m COMPLETING argument \u001b[0;m \r\n\u001b[0;7mAR\u001b[0;2;7m (The command to use to manipulate library archives when building with the gccg...)\u001b[0;m \u001b[0;34mDOCKER_HIDE_LEGACY_CO\r\nASCIINEMA_REC\u001b[0;2m (1) \u001b[0;m \u001b[0;34mEDITOR\u001b[0;2m (/usr/bin/heli\r\n\u001b[0;mAWS_ FC\u001b[0;2m (The command to us\r\n\u001b[0;mBUILDKIT_ GCCGO\u001b[0;2m (The gccgo comm\r\n\u001b[0;mCARAPACE_ GCCGOTOOLDIR\u001b[0;2m (If set,\r\n\u001b[0;34mCARAPACE_MATCH\u001b[0;2m (1) \u001b[0;m GH_ \r\nCARGO_ GIT_ \r\nCC\u001b[0;2m (The command to use to compile C code) \u001b[0;m GO111MODULE\u001b[0;2m (Controls\r\n\u001b[0;mCGO_ GO386\u001b[0;2m (For GOARCH=386\r\n\u001b[0;34mCLOUDSDK_PYTHON\u001b[0;2m (/usr/bin/python) \u001b[0;m GOAMD64\u001b[0;2m (For GOARCH=a\r\n\u001b[0;34mCLOUDSDK_PYTHON_ARGS\u001b[0;2m (-S) \u001b[0;m GOARCH\u001b[0;2m (The architect\r\n\u001b[0;34mCLOUDSDK_ROOT_DIR\u001b[0;2m (/opt/google-cloud-cli) \u001b[0;m GOARM\u001b[0;2m (For GOARCH=arm\r\n\u001b[0;34mCOLORTERM\u001b[0;2m (truecolor) \u001b[0;m GOBIN\u001b[0;2m (The directory \r\n\u001b[0;mCUSTOM_ GOCACHE\u001b[0;2m (The director\r\n\u001b[0;mCXX\u001b[0;2m (The command to use to compile C++ code) \u001b[0;m GOCOVERDIR\u001b[0;2m (Directory\r\n\u001b[0;34mDBUS_SESSION_BUS_ADDRESS\u001b[0;2m (unix:path=/run/user/1000/bus) \u001b[0;m GODEBUG\u001b[0;2m (Enable vario\r\n\u001b[0;34mDEBUGINFOD_URLS\u001b[0;2m (https://debuginfod.archlinux.org) \u001b[0;m GOENV\u001b[0;2m (The location o\r\n\u001b[0;34mDISPLAY\u001b[0;2m (:0) \u001b[0;m GOEXE\u001b[0;2m (The executable\r\n\u001b[0;mDOCKER_ GOEXPERIMENT\u001b[0;2m (Comma-s\r\n\u001b[0;7;35m \u001b[0;35m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0;m\u001b[20A\r\u001b[22C\u001b[?25h"] +[10.310527, "o", "\u001b[?25l\u001b[3A\r\r\n\r\n\r\n\u001b[22Cc\r\n\u001b[87C\u001b[KGO111MODULE\u001b[0;2m (Controls\r\n\u001b[87C\u001b[0;m\u001b[KGO386\u001b[0;2m (For GOARCH=386\r\n\u001b[0;m\u001b[KCARAPACE_ GOAMD64\u001b[0;2m (For GOARCH=a\r\n\u001b[0;m\u001b[K\u001b[0;34mCARAPACE_MATCH\u001b[0;2m (1) \u001b[0;m GOARCH\u001b[0;2m (The architect\r\n\u001b[3C\u001b[0;m\u001b[KGO_ GOARM\u001b[0;2m (For GOARCH=arm\r\n\u001b[0;m\u001b[KCC\u001b[0;2m (The command to use to compile C code) \u001b[0;m GOBIN\u001b[0;2m (The directory \r\n\u001b[1C\u001b[0;m\u001b[KGO_ GOCACHE\u001b[0;2m (The director\r\n\u001b[0;m\u001b[K\u001b[0;34mCLOUDSDK_PYTHON\u001b[0;2m (/usr/bin/python) \u001b[0;m GOCOVERDIR\u001b[0;2m (Directory\r\n\u001b[0;m\u001b[K\u001b[0;34mCLOUDSDK_PYTHON_ARGS\u001b[0;2m (-S) \u001b[0;m GODEBUG\u001b[0;2m (Enable vario\r\n\u001b[9C\u001b[0;m\u001b[K\u001b[0;34mROOT_DIR\u001b[0;2m (/opt/google-cloud-cli) \u001b[0;m GOENV\u001b[0;2m (The location o\r\n\u001b[1C\u001b[0;m\u001b[K\u001b[0;34mOLORTERM\u001b[0;2m (truecolor) \u001b[0;m GOEXE\u001b[0;2m (The executable\r\n\u001b[0;m\u001b[KCUSTOM_ GOEXPERIMENT\u001b[0;2m (Comma-s\r\n\u001b[0;m\u001b[KCXX\u001b[0;2m (The command to use to compile C++ code) \u001b[0;m GOFLAGS\u001b[0;2m (A space-sepa\r\n\u001b[0;m\u001b[K\u001b[0;34mDEBUGINFOD_URLS\u001b[0;2m (https://debuginfod.archlinux.org) \u001b[0;m GOGCCFLAGS\u001b[0;2m (A space-s\r\n\u001b[0;m\u001b[KDOCKER_ GOHOSTARCH\u001b[0;2m (The archi\r\n\u001b[1C\u001b[0;m\u001b[K\u001b[0;34mOCKER_HIDE_LEGACY_COMMANDS\u001b[0;2m (1) \u001b[0;m GOHOSTOS\u001b[0;2m (The operati\r\n\u001b[0;m\u001b[KFC\u001b[0;2m (The command to use to compile Fortran code) \u001b[0;m GOINSECURE\u001b[0;2m (Comma-sep\r\n\u001b[0;m\u001b[KGCCGO\u001b[0;2m (The gccgo command to run for 'go build -compiler=gccgo') \u001b[0;m GOMIPS\u001b[0;2m (For GOARCH=mi\r\n\u001b[0;m\u001b[KGCCGOTOOLDIR\u001b[0;2m (If set, where to find gccgo tools, such as cgo) \u001b[0;m GOMIPS64\u001b[0;2m (For GOARCH=\r\n\u001b[32C\u001b[0;m\u001b[K\u001b[0;7;35m \u001b[0;35m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0;m\u001b[20A\r\u001b[23C\u001b[?25h"] +[10.403602, "o", "\u001b[?25l\u001b[3A\r\r\n\r\n\u001b[14C\u001b[K\u001b[0;4mCUSTOM_\r\n\u001b[23C\u001b[0;mu\r\n\u001b[K\u001b[0;7mCUSTOM_ \r\n\u001b[0;m\u001b[KGOEXE\u001b[0;2m (The executable file name suffix (\".exe\" on Windows, \"\" on other systems))\r\n\u001b[0;m\u001b[KGOINSECURE\u001b[0;2m (Comma-separated list of glob patterns) \r\n\u001b[0;m\u001b[K\u001b[0;34mXCURSOR_SIZE\u001b[0;2m (24) \r\n\u001b[0;m\u001b[K\u001b[0;34mXDG_CURRENT_DESKTOP\u001b[0;2m (sway) \u001b[0;m\r\n\u001b[J\u001b[A\u001b[5A\r\u001b[24C\u001b[?25h"] +[10.465209, "o", "\u001b[?25l\u001b[3A\r\r\n\r\n\r\n\u001b[24Cs\r\n\u001b[7C\u001b[K\r\n\u001b[J\u001b[A\u001b[1A\r\u001b[25C\u001b[?25h"] +[10.972623, "o", "\u001b[?25l\u001b[3A\r\r\n\r\n\u001b[14C\u001b[KCUSTOM_\r\n\u001b[J\u001b[A\r\u001b[21C\u001b[?25h\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[21C\u001b[?25h"] +[11.243591, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\u001b[14C\u001b[K\u001b[0;4mCUSTOM_EXAMPLE \r\n\u001b[0;1;37;45m COMPLETING argument \u001b[0;m \r\n\u001b[0;7mCUSTOM_EXAMPLE\u001b[0;2;7m (example environment variable)\u001b[0;m CUSTOM_MACRO\u001b[0;2m (macro example)\u001b[0;m\u001b[1A\r\u001b[22C\u001b[?25h"] +[14.872308, "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"] +[14.872715, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[6C\u001b[?25h"] +[14.873279, "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\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[6C\u001b[?25h"] +[14.87414, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[6C\u001b[?25h"] +[14.874521, "o", "\u001b[?25l\u001b[2A\r\r\n\r\n\r\u001b[6C\u001b[?25h"] +[14.891848, "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"] +[15.118188, "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"] +[15.317512, "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"] +[15.46072, "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"] +[15.571217, "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"] +[15.687253, "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/environment.md b/docs/src/environment.md index b4dbe59969..dcb98cd1bd 100644 --- a/docs/src/environment.md +++ b/docs/src/environment.md @@ -7,24 +7,39 @@ Complex environment variable completion is provided with `get-env`, `set-env` an In `elvish` the completion is simply overridden. For other shells custom functions are added. -> Setting the environment variable `CARAPACE_ENV` to `0` -> before sourcing `carapace _carapace` disables this behaviour. +> Setting `CARAPACE_ENV=0` before sourcing `carapace _carapace` disables this behaviour. ![](./environment.cast) ## Custom variables -Custom variables can be defined in `~/.config/carapace/env.yaml` +Custom variables can be defined in `~/.config/carapace/variables/{group}.yaml` ```yaml -names: +variables: CUSTOM_EXAMPLE: example environment variable CUSTOM_MACRO: macro example HTTPS_PROXY: override existing variable completion: - CUSTOM_EXAMPLE: ["0\tdisabled\tred", "1\tenabled\tgreen"] - CUSTOM_MACRO: ["$_tools.gh.Labels({owner: rsteube, name: carapace}) ||| $uniquelist(,)"] - HTTPS_PROXY: ["https://localhost:8443\tdevelopment", "https://proxy.company:443\tproduction"] + variable: + CUSTOM_EXAMPLE: ["0\tdisabled\tred", "1\tenabled\tgreen"] + CUSTOM_MACRO: ["$_tools.gh.Labels({owner: rsteube, name: carapace}) ||| $uniquelist(,)"] + HTTPS_PROXY: ["https://localhost:8443\tdevelopment", "https://proxy.company:443\tproduction"] ``` ![](./environment-custom.cast) + +It is also possible to define conditions. + +```yaml +condition: ["$Parent([.git])"] +variables: + CUSTOM_CONDITION: condition example +completion: + variable: + CUSTOM_CONDITION: ["within", "git", "repo"] +``` + +![](./environment-condition.cast) + +> TODO document conditions \ No newline at end of file diff --git a/go.mod b/go.mod index b502bf235d..92c4fa2547 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/rsteube/carapace v0.43.5 github.com/rsteube/carapace-bridge v0.1.4 github.com/rsteube/carapace-shlex v0.0.4 - github.com/rsteube/carapace-spec v0.11.0 + github.com/rsteube/carapace-spec v0.11.1 github.com/spf13/cobra v1.7.0 github.com/spf13/pflag v1.0.5 golang.org/x/mod v0.12.0 @@ -16,10 +16,12 @@ require ( ) require ( - github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0 // indirect + github.com/bahlo/generic-list-go v0.2.0 // indirect + github.com/buger/jsonparser v1.1.1 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/invopop/jsonschema v0.8.0 // indirect - github.com/stretchr/testify v1.7.0 // indirect + github.com/invopop/jsonschema v0.9.0 // indirect + github.com/mailru/easyjson v0.7.7 // indirect + github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect ) replace github.com/spf13/pflag => github.com/rsteube/carapace-pflag v0.2.0 diff --git a/go.sum b/go.sum index 6cec21db27..4c376808f0 100644 --- a/go.sum +++ b/go.sum @@ -1,12 +1,17 @@ +github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= +github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= +github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= +github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0 h1:i462o439ZjprVSFSZLZxcsoAe592sZB1rci2Z8j4wdk= -github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0/go.mod h1:N0Wam8K1arqPXNWjMo21EXnBPOPp36vB07FNRdD2geA= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/invopop/jsonschema v0.8.0 h1:9Vblm5uNqURXUSaX0QUYcI/Hcu5rrvOz5MbpWgw0VkM= -github.com/invopop/jsonschema v0.8.0/go.mod h1:O9uiLokuu0+MGFlyiaqtWxwqJm41/+8Nj0lD7A36YH0= +github.com/invopop/jsonschema v0.9.0 h1:m1Fe5PN4X9V7P1TCF+pA8Xly3Vj3pY905klC++8oOpM= +github.com/invopop/jsonschema v0.9.0/go.mod h1:uMhbTEOXoPcOKzdYRfk914W6UTGA/cVcgEQxXh1MJ7g= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -20,21 +25,20 @@ github.com/rsteube/carapace-pflag v0.2.0 h1:EYqFO9Haib3NDCPqKu0VxOGi9YQBkXk1IzlH github.com/rsteube/carapace-pflag v0.2.0/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/rsteube/carapace-shlex v0.0.4 h1:3GVn8PaM2RCxPTAiwVy9vDQI8Mi7DqrbdpDgf5ZzQmY= github.com/rsteube/carapace-shlex v0.0.4/go.mod h1:zPw1dOFwvLPKStUy9g2BYKanI6bsQMATzDMYQQybo3o= -github.com/rsteube/carapace-spec v0.11.0 h1:SMMivfa2OXK/pTtJrx2fqqLgJgh2EuF/uchcLaH/6AM= -github.com/rsteube/carapace-spec v0.11.0/go.mod h1:tZIZjpCdeb8WClSdHDf95FN1LB168CrFD1ImROUZnds= +github.com/rsteube/carapace-spec v0.11.1 h1:LUNFbGOucWj4C74JMLvPuqKDFNGFGMHunWyiUfTM0BU= +github.com/rsteube/carapace-spec v0.11.1/go.mod h1:1rjCeoupGdnfPaMMfYr7PQDDHk8G8HeL9sSdyHO5UHU= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.3.1-0.20190311161405-34c6fa2dc709/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc= +github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/condition/condition.go b/internal/condition/condition.go new file mode 100644 index 0000000000..d18cfee875 --- /dev/null +++ b/internal/condition/condition.go @@ -0,0 +1,19 @@ +package condition + +import ( + "github.com/rsteube/carapace" +) + +type Condition func(c carapace.Context) bool + +// Of combines different conditions. +func Of(conditions ...Condition) Condition { + return func(c carapace.Context) bool { + for _, condition := range conditions { + if !condition(c) { + return false + } + } + return true + } +} diff --git a/internal/condition/macro.go b/internal/condition/macro.go new file mode 100644 index 0000000000..24cdc212ec --- /dev/null +++ b/internal/condition/macro.go @@ -0,0 +1,49 @@ +package condition + +import ( + "github.com/rsteube/carapace" + "github.com/rsteube/carapace-spec/pkg/macro" +) + +type Macro struct { + macro macro.Macro[Condition] +} + +func (m Macro) Parse(s string) Condition { + return func(c carapace.Context) bool { + b, err := m.macro.Parse(s) + if err != nil { + return false + } + return (*b)(c) + } +} + +func (m Macro) Signature() string { return m.macro.Signature() } + +func MacroI[A any](f func(arg A) Condition) Macro { + return Macro{ + macro: macro.MacroI[A, Condition](func(arg A) (*Condition, error) { + a := f(arg) + return &a, nil + }), + } +} + +func MacroN(f func() Condition) Macro { + return Macro{ + macro: macro.MacroN[Condition](func() (*Condition, error) { + a := f() + return &a, nil + }), + } +} + +func MacroV[A any](f func(args ...A) Condition) Macro { + return Macro{ + macro: macro.MacroV[A, Condition](func(args ...A) (*Condition, error) { + a := f(args...) + return &a, nil + }), + } +} diff --git a/pkg/actions/actions.go b/pkg/actions/actions.go new file mode 100644 index 0000000000..52b6c22ea8 --- /dev/null +++ b/pkg/actions/actions.go @@ -0,0 +1,11 @@ +package actions + +import ( + spec "github.com/rsteube/carapace-spec" + "github.com/rsteube/carapace-spec/pkg/macro" +) + +var ( + MacroMap = make(macro.MacroMap[spec.Macro]) + MacroDescriptions = make(map[string]string) +) diff --git a/pkg/actions/env/aws.go b/pkg/actions/env/aws.go index 67f31a5667..867f164c30 100644 --- a/pkg/actions/env/aws.go +++ b/pkg/actions/env/aws.go @@ -5,6 +5,7 @@ import ( "github.com/rsteube/carapace" "github.com/rsteube/carapace-bin/pkg/actions/tools/aws" + "github.com/rsteube/carapace-bin/pkg/conditions" "github.com/rsteube/carapace-bridge/pkg/actions/bridge" "github.com/rsteube/carapace/pkg/style" ) @@ -12,8 +13,8 @@ import ( func init() { _bool := carapace.ActionValues("true", "false").StyleF(style.ForKeyword) knownVariables["aws"] = variables{ - Condition: checkPath("aws"), - Names: map[string]string{ + Condition: conditions.ConditionPath("aws"), + Variables: map[string]string{ "AWS_ACCESS_KEY_ID": "Specifies an AWS access key associated with an IAM account", "AWS_CA_BUNDLE": "Specifies the path to a certificate bundle to use for HTTPS certificate validation", "AWS_CLI_AUTO_PROMPT": "Enables the auto-prompt for the AWS CLI version 2", @@ -40,7 +41,7 @@ func init() { "AWS_USE_FIPS_ENDPOINT": "Federal Information Processing Standard (FIPS) endoint", "AWS_WEB_IDENTITY_TOKEN_FILE": "Specifies the path to a file that contains an OAuth 2.0 access token", }, - Completion: map[string]carapace.Action{ + VariableCompletion: map[string]carapace.Action{ "AWS_CA_BUNDLE": carapace.ActionFiles(), "AWS_CLI_AUTO_PROMPT": carapace.ActionValuesDescribed( "on", "full auto-prompt mode each time you attempt to run an aws command", diff --git a/pkg/actions/env/carapace.go b/pkg/actions/env/carapace.go index 25a64b33e5..58810b3c22 100644 --- a/pkg/actions/env/carapace.go +++ b/pkg/actions/env/carapace.go @@ -8,7 +8,7 @@ import ( func init() { _bool := carapace.ActionValuesDescribed("0", "disabled", "1", "enabled").StyleF(style.ForKeyword) knownVariables["carapace"] = variables{ - Names: map[string]string{ + Variables: map[string]string{ "CARAPACE_COVERDIR": "coverage directory for sandbox tests", "CARAPACE_ENV": "register get-env, set-env and unset-env", "CARAPACE_HIDDEN": "show hidden commands/flags", @@ -18,7 +18,7 @@ func init() { "CARAPACE_SANDBOX": "mock context for sandbox tests", "CARAPACE_ZSH_HASH_DIRS": "zsh hash directories", }, - Completion: map[string]carapace.Action{ + VariableCompletion: map[string]carapace.Action{ "CARAPACE_COVERDIR": carapace.ActionDirectories(), "CARAPACE_ENV": _bool, "CARAPACE_HIDDEN": _bool, diff --git a/pkg/actions/env/cargo.go b/pkg/actions/env/cargo.go index eaf4d60566..988c48de6a 100644 --- a/pkg/actions/env/cargo.go +++ b/pkg/actions/env/cargo.go @@ -2,12 +2,14 @@ package env import ( "github.com/rsteube/carapace" + "github.com/rsteube/carapace-bin/pkg/actions/net/http" "github.com/rsteube/carapace/pkg/style" ) func init() { + _bool := carapace.ActionValues("true", "false").StyleF(style.ForKeyword) knownVariables["cargo"] = variables{ - Names: map[string]string{ + Variables: map[string]string{ "CARGO_BIN_NAME": "The name of the binary that is currently being compiled", "CARGO_BUILD_DEP_INFO_BASEDIR": "Dep-info relative directory, see build.dep-info-basedir", "CARGO_BUILD_INCREMENTAL": "Incremental compilation, see build.incremental", @@ -80,7 +82,7 @@ func init() { "CARGO_TERM_QUIET": "Quiet mode, see term.quiet", "CARGO_TERM_VERBOSE": "The default terminal verbosity, see term.verbose", }, - Completion: map[string]carapace.Action{ + VariableCompletion: map[string]carapace.Action{ "CARGO_BUILD_DEP_INFO_BASEDIR": carapace.ActionDirectories(), "CARGO_LOG": carapace.ActionValues("debug", "info", "warn", "error", "trace").StyleF(style.ForLogLevel), "CARGO_HOME": carapace.ActionDirectories(), @@ -89,7 +91,11 @@ func init() { "0", "force disabled,", style.Red, "1", "force enabled", style.Green, ), - "CARGO_CARGO_NEW_VCS": carapace.ActionValues("git", "hg", "pijul", "fossil", "none"), + "CARGO_CARGO_NEW_VCS": carapace.ActionValues("git", "hg", "pijul", "fossil", "none"), + "CARGO_HTTP_USER_AGENT": http.ActionUserAgents(), + "CARGO_TERM_COLOR": carapace.ActionValues("auto", "always", "never").StyleF(style.ForKeyword), + "CARGO_TERM_QUIET": _bool, + "CARGO_TERM_VERBOSE": _bool, // TODO more completions }, } diff --git a/pkg/actions/env/common.go b/pkg/actions/env/common.go index f33613c344..230af98368 100644 --- a/pkg/actions/env/common.go +++ b/pkg/actions/env/common.go @@ -9,7 +9,7 @@ import ( func init() { knownVariables["common"] = variables{ - Names: map[string]string{ + Variables: map[string]string{ "BROWSER": "the browser to use", "EDITOR": "the editor to use", "HTTP_PROXY": "http proxy server", @@ -18,7 +18,7 @@ func init() { "PAGER": "the pager to use", "PATH": "A list of directories to be searched when executing commands", }, - Completion: map[string]carapace.Action{ + VariableCompletion: map[string]carapace.Action{ "BROWSER": bridge.ActionCarapaceBin().Split(), "EDITOR": bridge.ActionCarapaceBin().Split(), "PAGER": bridge.ActionCarapaceBin().Split(), diff --git a/pkg/actions/env/common_unix.go b/pkg/actions/env/common_unix.go index c36140cf02..7970feabae 100644 --- a/pkg/actions/env/common_unix.go +++ b/pkg/actions/env/common_unix.go @@ -7,7 +7,7 @@ import ( func init() { knownVariables["common_unix"] = variables{ - Names: map[string]string{ + Variables: map[string]string{ "USER": "The current logged in user", "HOME": "The home directory of the current user", "EDITOR": "The default file editor to be used", @@ -17,7 +17,7 @@ func init() { "TERM": "The current terminal emulation", "MAIL": "Location of where the current user’s mail is stored", }, - Completion: map[string]carapace.Action{ + VariableCompletion: map[string]carapace.Action{ "HOME": carapace.ActionDirectories(), "LANG": os.ActionLanguages(), "LOGNAME": os.ActionUsers(), diff --git a/pkg/actions/env/docker.go b/pkg/actions/env/docker.go index 3aeb088df0..844f650eda 100644 --- a/pkg/actions/env/docker.go +++ b/pkg/actions/env/docker.go @@ -2,13 +2,14 @@ package env import ( "github.com/rsteube/carapace" + "github.com/rsteube/carapace-bin/pkg/conditions" "github.com/rsteube/carapace/pkg/style" ) func init() { knownVariables["docker"] = variables{ - Condition: checkPath("docker"), - Names: map[string]string{ + Condition: conditions.ConditionPath("docker"), + Variables: map[string]string{ "DOCKER_API_VERSION": "Override the negotiated API version to use for debugging", "DOCKER_CERT_PATH": "Location of your authentication keys", "DOCKER_CONFIG": "The location of your client configuration files", @@ -21,7 +22,7 @@ func init() { "DOCKER_TLS_VERIFY": "When set Docker uses TLS and verifies the remote", "BUILDKIT_PROGRESS": "Set type of progress output", }, - Completion: map[string]carapace.Action{ + VariableCompletion: map[string]carapace.Action{ "DOCKER_CERT_PATH": carapace.ActionDirectories(), "DOCKER_CONFIG": carapace.ActionFiles(), "DOCKER_HIDE_LEGACY_COMMANDS": carapace.ActionStyledValuesDescribed( diff --git a/pkg/actions/env/env.go b/pkg/actions/env/env.go index 08549270a5..09ce37e894 100644 --- a/pkg/actions/env/env.go +++ b/pkg/actions/env/env.go @@ -2,9 +2,11 @@ package env import ( "os" - "os/exec" + "strings" "github.com/rsteube/carapace" + "github.com/rsteube/carapace-bin/internal/condition" + "github.com/rsteube/carapace-bin/pkg/conditions" spec "github.com/rsteube/carapace-spec" "github.com/rsteube/carapace/pkg/xdg" "github.com/spf13/cobra" @@ -12,32 +14,41 @@ import ( ) type variables struct { - Condition func(c carapace.Context) bool - Names map[string]string - Completion map[string]carapace.Action + Condition condition.Condition + Variables map[string]string + VariableCompletion map[string]carapace.Action + // PlaceholderCompletion map[string]carapace.Action // TODO } func (v *variables) UnmarshalYAML(unmarshal func(interface{}) error) error { var env struct { - Names map[string]string - Completion map[string][]string + Condition []string + Variables map[string]string + Completion struct { + Variable map[string][]string + // Placeholder map[string][]string // TODO + } } if err := unmarshal(&env); err != nil { return err } - v.Names = env.Names - v.Completion = make(map[string]carapace.Action) - for name, completion := range env.Completion { - v.Completion[name] = spec.NewAction(completion).Parse(&cobra.Command{}) + + conds := make([]condition.Condition, 0) + for _, c := range env.Condition { + m, err := conditions.MacroMap.Lookup(c) + if err != nil { + return err + } + conds = append(conds, m.Parse(c)) } - return nil -} -func checkPath(s string) func(c carapace.Context) bool { - return func(c carapace.Context) bool { - _, err := exec.LookPath(s) // TODO copy function to carapace as this needs to use carapace.Context$Env - return err == nil + v.Condition = condition.Of(conds...) + v.Variables = env.Variables + v.VariableCompletion = make(map[string]carapace.Action) + for name, completion := range env.Completion.Variable { + v.VariableCompletion[name] = spec.NewAction(completion).Parse(&cobra.Command{}) } + return nil } var knownVariables = map[string]variables{} @@ -61,7 +72,7 @@ func actionKnownEnvironmentVariables() carapace.Action { continue } - for name, description := range v.Names { + for name, description := range v.Variables { vals = append(vals, name, description) } } @@ -72,50 +83,100 @@ func actionKnownEnvironmentVariables() carapace.Action { // ActionEnvironmentVariableValues completes values for given environment variable func ActionEnvironmentVariableValues(s string) carapace.Action { return carapace.ActionCallback(func(c carapace.Context) carapace.Action { - if custom, err := loadCustomVariables(); err == nil { - if action, ok := custom.Completion[s]; ok { - return action - } + dir, err := xdg.UserConfigDir() + if err != nil { + return carapace.ActionMessage(err.Error()) } - for _, v := range knownVariables { - if action, ok := v.Completion[s]; ok { - return action + entries, err := os.ReadDir(dir + "/carapace/variables") + if err != nil { + return carapace.ActionMessage(err.Error()) // TODO ignore if not exists + } + + found := false + batch := carapace.Batch() + for _, entry := range entries { + if !entry.IsDir() && strings.HasSuffix(entry.Name(), ".yaml") { + file := dir + "/carapace/variables/" + entry.Name() + batch = append(batch, carapace.ActionCallback(func(c carapace.Context) carapace.Action { + custom, err := loadCustomVariables(file) + if err != nil { + return carapace.ActionMessage(err.Error()) + } + + if custom.Condition == nil || custom.Condition(c) { + if action, ok := custom.VariableCompletion[s]; ok { + found = true + return action + } + } + + for _, v := range knownVariables { + if action, ok := v.VariableCompletion[s]; ok { + found = true + return action + } + } + return carapace.ActionValues() + })) } } - return carapace.ActionFiles() + + if a := batch.Invoke(c).Merge().ToA(); found { + return a + } + return carapace.ActionFiles() // fallback }) } func actionCustomEnvironmentVariables() carapace.Action { return carapace.ActionCallback(func(c carapace.Context) carapace.Action { - v, err := loadCustomVariables() + dir, err := xdg.UserConfigDir() if err != nil { return carapace.ActionMessage(err.Error()) } - vals := make([]string, 0) - for name, description := range v.Names { - vals = append(vals, name, description) + entries, err := os.ReadDir(dir + "/carapace/variables") + if err != nil { + return carapace.ActionMessage(err.Error()) // TODO ignore if not exists } - return carapace.ActionValuesDescribed(vals...) + + batch := carapace.Batch() + for _, entry := range entries { + if !entry.IsDir() && strings.HasSuffix(entry.Name(), ".yaml") { + file := dir + "/carapace/variables/" + entry.Name() + batch = append(batch, carapace.ActionCallback(func(c carapace.Context) carapace.Action { + custom, err := loadCustomVariables(file) + if err != nil { + return carapace.ActionMessage(err.Error()) + } + + if custom.Condition != nil && !custom.Condition(c) { + return carapace.ActionValues() // skip when condition failed + } + + vals := make([]string, 0) + for name, description := range custom.Variables { + vals = append(vals, name, description) + } + return carapace.ActionValuesDescribed(vals...) + + })) + } + } + return batch.ToA() }).Tag("custom environment variables") } -func loadCustomVariables() (*variables, error) { - dir, err := xdg.UserConfigDir() - if err != nil { - return nil, err - } - - content, err := os.ReadFile(dir + "/carapace/env.yaml") +func loadCustomVariables(file string) (*variables, error) { + content, err := os.ReadFile(file) if err != nil { if !os.IsNotExist(err) { return nil, err } return &variables{ - Names: map[string]string{}, - Completion: make(map[string]carapace.Action), + Variables: map[string]string{}, + VariableCompletion: make(map[string]carapace.Action), }, nil } diff --git a/pkg/actions/env/env_test.go b/pkg/actions/env/env_test.go index 78ff4e25a7..5203523e06 100644 --- a/pkg/actions/env/env_test.go +++ b/pkg/actions/env/env_test.go @@ -4,8 +4,8 @@ import "testing" func TestKnownVariables(t *testing.T) { for k, v := range knownVariables { - for name := range v.Completion { - if _, ok := v.Names[name]; !ok { + for name := range v.VariableCompletion { + if _, ok := v.Variables[name]; !ok { t.Errorf("variables %#v is unknown in %#v", name, k) } } diff --git a/pkg/actions/env/gh.go b/pkg/actions/env/gh.go index 0fcefafca8..b42b9e2bc3 100644 --- a/pkg/actions/env/gh.go +++ b/pkg/actions/env/gh.go @@ -3,13 +3,14 @@ package env import ( "github.com/rsteube/carapace" "github.com/rsteube/carapace-bin/pkg/actions/tools/gh" + "github.com/rsteube/carapace-bin/pkg/conditions" "github.com/rsteube/carapace-bridge/pkg/actions/bridge" ) func init() { knownVariables["gh"] = variables{ - Condition: checkPath("gh"), - Names: map[string]string{ + Condition: conditions.ConditionPath("gh"), + Variables: map[string]string{ "GH_TOKEN": "an authentication token for github.com API requests", "GH_ENTERPRISE_TOKEN": "an authentication token for API requests to GitHub Enterprise", "GH_HOST": "specify the GitHub hostname", @@ -24,7 +25,7 @@ func init() { "GH_PROMPT_DISABLED": "set to any value to disable interactive prompting in the terminal", "GH_PATH": "set the path to the gh executable", }, - Completion: map[string]carapace.Action{ + VariableCompletion: map[string]carapace.Action{ "GH_REPO": gh.ActionOwnerRepositories(gh.HostOpts{}), "GH_EDITOR": bridge.ActionCarapaceBin().Split(), "GH_BROWSER": bridge.ActionCarapaceBin().Split(), diff --git a/pkg/actions/env/git.go b/pkg/actions/env/git.go index 2608a8f1db..29cd7c1168 100644 --- a/pkg/actions/env/git.go +++ b/pkg/actions/env/git.go @@ -5,6 +5,7 @@ import ( "github.com/rsteube/carapace-bin/pkg/actions/net/http" "github.com/rsteube/carapace-bin/pkg/actions/time" "github.com/rsteube/carapace-bin/pkg/actions/tools/git" + "github.com/rsteube/carapace-bin/pkg/conditions" "github.com/rsteube/carapace/pkg/style" "github.com/spf13/cobra" ) @@ -12,8 +13,8 @@ import ( func init() { _bool := carapace.ActionValues("true", "false").StyleF(style.ForKeyword) knownVariables["git"] = variables{ - Condition: checkPath("git"), - Names: map[string]string{ + Condition: conditions.ConditionPath("git"), + Variables: map[string]string{ "GIT_ALTERNATE_OBJECT_DIRECTORIES": "is a colon-separated list which tells Git where to check for objects", "GIT_ASKPASS": "is an override for the core.askpass configuration value", "GIT_AUTHOR_DATE": "is the timestamp used for the β€œauthor” field", @@ -53,7 +54,7 @@ func init() { "GIT_TRACE_SETUP": "shows information about what Git is discovering about the repository and environment it’s interacting with", "GIT_WORK_TREE": "is the location of the root of the working directory for a non-bare repository", }, - Completion: map[string]carapace.Action{ + VariableCompletion: map[string]carapace.Action{ // TODO complete more variables "GIT_ALTERNATE_OBJECT_DIRECTORIES": carapace.ActionDirectories().MultiParts(":"), "GIT_ASKPASS": git.ActionConfigValues("core.askpass"), diff --git a/pkg/actions/env/golang.go b/pkg/actions/env/golang.go index ef2d3946fb..c9f3bbb835 100644 --- a/pkg/actions/env/golang.go +++ b/pkg/actions/env/golang.go @@ -3,13 +3,15 @@ package env import ( "github.com/rsteube/carapace" "github.com/rsteube/carapace-bin/pkg/actions/tools/golang" + "github.com/rsteube/carapace-bin/pkg/conditions" "github.com/rsteube/carapace-bridge/pkg/actions/bridge" "github.com/rsteube/carapace/pkg/style" ) func init() { knownVariables["golang"] = variables{ - Names: map[string]string{ + Condition: conditions.ConditionPath("go"), + Variables: map[string]string{ "AR": "The command to use to manipulate library archives when building with the gccgo compiler", "CC": "The command to use to compile C code", "CGO_CFFLAGS_ALLOW": "Like CGO_CFLAGS_ALLOW but for the Fortran compiler", @@ -73,7 +75,7 @@ func init() { "GOWORK": "In module aware mode, use the given go.work file as a workspace file", "PKG_CONFIG": "Path to pkg-config tool", }, - Completion: map[string]carapace.Action{ + VariableCompletion: map[string]carapace.Action{ // TODO more flags "AR": bridge.ActionCarapaceBin().Split(), "CC": bridge.ActionCarapaceBin().Split(), diff --git a/pkg/actions/env/nocolor.go b/pkg/actions/env/nocolor.go index 87f2938600..f6fa3c2042 100644 --- a/pkg/actions/env/nocolor.go +++ b/pkg/actions/env/nocolor.go @@ -7,10 +7,10 @@ import ( func init() { knownVariables["nocolor"] = variables{ - Names: map[string]string{ + Variables: map[string]string{ "NO_COLOR": "disable colors in supported commands", }, - Completion: map[string]carapace.Action{ + VariableCompletion: map[string]carapace.Action{ "NO_COLOR": carapace.ActionStyledValuesDescribed( "0", "show colors", style.Carapace.KeywordNegative, "1", "do not show colors", style.Carapace.KeywordPositive, diff --git a/pkg/actions/env/node.go b/pkg/actions/env/node.go index a5734f73d4..6b3e55f873 100644 --- a/pkg/actions/env/node.go +++ b/pkg/actions/env/node.go @@ -2,14 +2,15 @@ package env import ( "github.com/rsteube/carapace" + "github.com/rsteube/carapace-bin/pkg/conditions" "github.com/rsteube/carapace/pkg/style" ) func init() { _bool := carapace.ActionValuesDescribed("0", "disabled", "1", "enabled").StyleF(style.ForKeyword) knownVariables["node"] = variables{ - Condition: checkPath("node"), - Names: map[string]string{ + Condition: conditions.ConditionPath("node"), + Variables: map[string]string{ "NODE_DEBUG": "Comma-separated list of core modules that should print debug information", "NODE_DEBUG_NATIVE": "Comma-separated list of C++ core modules that should print debug information", "NODE_DISABLE_COLORS": "When set to 1, colors will not be used in the REPL", @@ -27,7 +28,7 @@ func init() { "NODE_TLS_REJECT_UNAUTHORIZED": "When set to 0, TLS certificate validation is disabled", "NODE_V8_COVERAGE": "When set, Node.js writes JavaScript code coverage information to dir", }, - Completion: map[string]carapace.Action{ + VariableCompletion: map[string]carapace.Action{ // TODO more completions "NODE_DISABLE_COLORS": _bool, "NODE_NO_WARNINGS": _bool, diff --git a/pkg/actions/env/rust.go b/pkg/actions/env/rust.go index 3223015e32..478b40f750 100644 --- a/pkg/actions/env/rust.go +++ b/pkg/actions/env/rust.go @@ -2,20 +2,21 @@ package env import ( "github.com/rsteube/carapace" + "github.com/rsteube/carapace-bin/pkg/conditions" "github.com/rsteube/carapace/pkg/style" ) func init() { _bool := carapace.ActionValuesDescribed("0", "disabled", "1", "enabled").StyleF(style.ForKeyword) knownVariables["rust"] = variables{ - Condition: checkPath("rustc"), - Names: map[string]string{ + Condition: conditions.ConditionPath("rustc"), + Variables: map[string]string{ "RUST_TEST_THREADS": "The test framework Rust provides executes tests in parallel", "RUST_TEST_NOCAPTURE": "Synonym for the --nocapture flag", "RUST_MIN_STACK": "Sets the minimum stack size for new threads", "RUST_BACKTRACE": "Produces a backtrace in the output of a program which panics", }, - Completion: map[string]carapace.Action{ + VariableCompletion: map[string]carapace.Action{ "RUST_TEST_THREADS": carapace.ActionValues(), "RUST_TEST_NOCAPTURE": _bool, "RUST_MIN_STACK": carapace.ActionValues(), diff --git a/pkg/actions/env/starship.go b/pkg/actions/env/starship.go index e9280fca1f..746707dd65 100644 --- a/pkg/actions/env/starship.go +++ b/pkg/actions/env/starship.go @@ -7,7 +7,7 @@ import ( func init() { knownVariables["starship"] = variables{ - Names: map[string]string{ + Variables: map[string]string{ "STARSHIP_CACHE": "cache location", "STARSHIP_CONFIG": "config location", "STARSHIP_LOG": "log level", @@ -15,7 +15,7 @@ func init() { "STARSHIP_SESSION_KEY": "session key", "STARSHIP_SHELL": "shell", }, - Completion: map[string]carapace.Action{ + VariableCompletion: map[string]carapace.Action{ "STARSHIP_CACHE": carapace.ActionDirectories(), "STARSHIP_CONFIG": carapace.ActionFiles(), "STARSHIP_LOG": carapace.ActionValues("debug", "error", "info", "trace", "warn").StyleF(style.ForLogLevel), diff --git a/pkg/actions/env/terraform.go b/pkg/actions/env/terraform.go new file mode 100644 index 0000000000..e419f1552d --- /dev/null +++ b/pkg/actions/env/terraform.go @@ -0,0 +1,88 @@ +package env + +import ( + "github.com/rsteube/carapace" + "github.com/rsteube/carapace-bin/pkg/actions/tools/terraform" + "github.com/rsteube/carapace-bridge/pkg/actions/bridge" + "github.com/rsteube/carapace/pkg/style" +) + +func init() { + _bool := carapace.ActionValues("true", "false").StyleF(style.ForKeyword) + knownVariables["terraform"] = variables{ + Variables: map[string]string{ + "TF_LOG": "Enables detailed logs to appear on stderr which is useful for debugging", + "TF_LOG_PATH": "This specifies where the log should persist its output to", + "TF_INPUT": "If set to \"false\" or \"0\", causes terraform commands to behave as if the -input=false flag was specified", + "TF_CLI_ARGS": "Additional cli arguments", + "TF_CLI_ARGS_init": "Additional cli arguments to init", + "TF_CLI_ARGS_validate": "Additional cli arguments to validate", + "TF_CLI_ARGS_plan": "Additional cli arguments to plan", + "TF_CLI_ARGS_apply": "Additional cli arguments to apply", + "TF_CLI_ARGS_destroy": "Additional cli arguments to destroy", + "TF_CLI_ARGS_console": "Additional cli arguments to console", + "TF_CLI_ARGS_fmt": "Additional cli arguments to fmt", + "TF_CLI_ARGS_force-unlock": "Additional cli arguments to force-unlock", + "TF_CLI_ARGS_get": "Additional cli arguments to get", + "TF_CLI_ARGS_graph": "Additional cli arguments to graph", + "TF_CLI_ARGS_import": "Additional cli arguments to import", + "TF_CLI_ARGS_login": "Additional cli arguments to login", + "TF_CLI_ARGS_logout": "Additional cli arguments to logout", + "TF_CLI_ARGS_metadata": "Additional cli arguments to metadata", + "TF_CLI_ARGS_output": "Additional cli arguments to output", + "TF_CLI_ARGS_providers": "Additional cli arguments to providers", + "TF_CLI_ARGS_refresh": "Additional cli arguments to refresh", + "TF_CLI_ARGS_show": "Additional cli arguments to show", + "TF_CLI_ARGS_state": "Additional cli arguments to state", + "TF_CLI_ARGS_taint": "Additional cli arguments to taint", + "TF_CLI_ARGS_test": "Additional cli arguments to test", + "TF_CLI_ARGS_untaint": "Additional cli arguments to untaint", + "TF_CLI_ARGS_version": "Additional cli arguments to version", + "TF_CLI_ARGS_workspace": "Additional cli arguments to workspace", + "TF_DATA_DIR": "Changes the location where Terraform keeps its per-working-directory data", + "TF_WORKSPACE": "Selects the workspace", + "TF_IN_AUTOMATION": "Adjusts its output to avoid suggesting specific commands to run next", + "TF_REGISTRY_DISCOVERY_RETRY": "Max number of request retries the remote registry client will attempt", + "TF_REGISTRY_CLIENT_TIMEOUT": "Client timeout for requests ", + "TF_CLI_CONFIG_FILE": "Location of the Terraform CLI configuration file", + "TF_PLUGIN_CACHE_DIR": "Plugin cache directory", + "TF_IGNORE": "When set to \"trace\", Terraform will output debug messages to display ignored files and folder", + }, + VariableCompletion: map[string]carapace.Action{ + "TF_LOG": _bool, + "TF_LOG_PATH": carapace.ActionValues(), + "TF_INPUT": carapace.ActionFiles(), + "TF_CLI_ARGS": bridge.ActionCarapaceBin("terraform").Split(), + "TF_CLI_ARGS_init": bridge.ActionCarapaceBin("terraform", "init").Split(), + "TF_CLI_ARGS_validate": bridge.ActionCarapaceBin("terraform", "validate").Split(), + "TF_CLI_ARGS_plan": bridge.ActionCarapaceBin("terraform", "plan").Split(), + "TF_CLI_ARGS_apply": bridge.ActionCarapaceBin("terraform", "apply").Split(), + "TF_CLI_ARGS_destroy": bridge.ActionCarapaceBin("terraform", "destroy").Split(), + "TF_CLI_ARGS_console": bridge.ActionCarapaceBin("terraform", "console").Split(), + "TF_CLI_ARGS_fmt": bridge.ActionCarapaceBin("terraform", "fmt").Split(), + "TF_CLI_ARGS_force-unlock": bridge.ActionCarapaceBin("terraform", "force-unlock").Split(), + "TF_CLI_ARGS_get": bridge.ActionCarapaceBin("terraform", "get").Split(), + "TF_CLI_ARGS_graph": bridge.ActionCarapaceBin("terraform", "graph").Split(), + "TF_CLI_ARGS_import": bridge.ActionCarapaceBin("terraform", "import").Split(), + "TF_CLI_ARGS_login": bridge.ActionCarapaceBin("terraform", "login").Split(), + "TF_CLI_ARGS_logout": bridge.ActionCarapaceBin("terraform", "logout").Split(), + "TF_CLI_ARGS_metadata": bridge.ActionCarapaceBin("terraform", "metadata").Split(), + "TF_CLI_ARGS_output": bridge.ActionCarapaceBin("terraform", "output").Split(), + "TF_CLI_ARGS_providers": bridge.ActionCarapaceBin("terraform", "providers").Split(), + "TF_CLI_ARGS_refresh": bridge.ActionCarapaceBin("terraform", "refresh").Split(), + "TF_CLI_ARGS_show": bridge.ActionCarapaceBin("terraform", "show").Split(), + "TF_CLI_ARGS_state": bridge.ActionCarapaceBin("terraform", "state").Split(), + "TF_CLI_ARGS_taint": bridge.ActionCarapaceBin("terraform", "taint").Split(), + "TF_CLI_ARGS_test": bridge.ActionCarapaceBin("terraform", "test").Split(), + "TF_CLI_ARGS_untaint": bridge.ActionCarapaceBin("terraform", "untaint").Split(), + "TF_CLI_ARGS_version": bridge.ActionCarapaceBin("terraform", "version").Split(), + "TF_CLI_ARGS_workspace": bridge.ActionCarapaceBin("terraform", "workspace").Split(), + "TF_DATA_DIR": carapace.ActionDirectories(), + "TF_WORKSPACE": terraform.ActionWorkspaces(), + "TF_IN_AUTOMATION": _bool, + "TF_CLI_CONFIG_FILE": carapace.ActionFiles(), + "TF_PLUGIN_CACHE_DIR": carapace.ActionDirectories(), + "TF_IGNORE": carapace.ActionValues("trace").StyleF(style.ForLogLevel), + }, + } +} diff --git a/pkg/actions/env/tofu.go b/pkg/actions/env/tofu.go new file mode 100644 index 0000000000..d9ce49289f --- /dev/null +++ b/pkg/actions/env/tofu.go @@ -0,0 +1,88 @@ +package env + +import ( + "github.com/rsteube/carapace" + "github.com/rsteube/carapace-bin/pkg/actions/tools/tofu" + "github.com/rsteube/carapace-bridge/pkg/actions/bridge" + "github.com/rsteube/carapace/pkg/style" +) + +func init() { + _bool := carapace.ActionValues("true", "false").StyleF(style.ForKeyword) + knownVariables["tofu"] = variables{ + Variables: map[string]string{ + "TF_LOG": "Enables detailed logs to appear on stderr which is useful for debugging", + "TF_LOG_PATH": "This specifies where the log should persist its output to", + "TF_INPUT": "If set to \"false\" or \"0\", causes tofu commands to behave as if the -input=false flag was specified", + "TF_CLI_ARGS": "Additional cli arguments", + "TF_CLI_ARGS_init": "Additional cli arguments to init", + "TF_CLI_ARGS_validate": "Additional cli arguments to validate", + "TF_CLI_ARGS_plan": "Additional cli arguments to plan", + "TF_CLI_ARGS_apply": "Additional cli arguments to apply", + "TF_CLI_ARGS_destroy": "Additional cli arguments to destroy", + "TF_CLI_ARGS_console": "Additional cli arguments to console", + "TF_CLI_ARGS_fmt": "Additional cli arguments to fmt", + "TF_CLI_ARGS_force-unlock": "Additional cli arguments to force-unlock", + "TF_CLI_ARGS_get": "Additional cli arguments to get", + "TF_CLI_ARGS_graph": "Additional cli arguments to graph", + "TF_CLI_ARGS_import": "Additional cli arguments to import", + "TF_CLI_ARGS_login": "Additional cli arguments to login", + "TF_CLI_ARGS_logout": "Additional cli arguments to logout", + "TF_CLI_ARGS_metadata": "Additional cli arguments to metadata", + "TF_CLI_ARGS_output": "Additional cli arguments to output", + "TF_CLI_ARGS_providers": "Additional cli arguments to providers", + "TF_CLI_ARGS_refresh": "Additional cli arguments to refresh", + "TF_CLI_ARGS_show": "Additional cli arguments to show", + "TF_CLI_ARGS_state": "Additional cli arguments to state", + "TF_CLI_ARGS_taint": "Additional cli arguments to taint", + "TF_CLI_ARGS_test": "Additional cli arguments to test", + "TF_CLI_ARGS_untaint": "Additional cli arguments to untaint", + "TF_CLI_ARGS_version": "Additional cli arguments to version", + "TF_CLI_ARGS_workspace": "Additional cli arguments to workspace", + "TF_DATA_DIR": "Changes the location where tofu keeps its per-working-directory data", + "TF_WORKSPACE": "Selects the workspace", + "TF_IN_AUTOMATION": "Adjusts its output to avoid suggesting specific commands to run next", + "TF_REGISTRY_DISCOVERY_RETRY": "Max number of request retries the remote registry client will attempt", + "TF_REGISTRY_CLIENT_TIMEOUT": "Client timeout for requests ", + "TF_CLI_CONFIG_FILE": "Location of the tofu CLI configuration file", + "TF_PLUGIN_CACHE_DIR": "Plugin cache directory", + "TF_IGNORE": "When set to \"trace\", tofu will output debug messages to display ignored files and folder", + }, + VariableCompletion: map[string]carapace.Action{ + "TF_LOG": _bool, + "TF_LOG_PATH": carapace.ActionValues(), + "TF_INPUT": carapace.ActionFiles(), + "TF_CLI_ARGS": bridge.ActionCarapaceBin("tofu").Split(), + "TF_CLI_ARGS_init": bridge.ActionCarapaceBin("tofu", "init").Split(), + "TF_CLI_ARGS_validate": bridge.ActionCarapaceBin("tofu", "validate").Split(), + "TF_CLI_ARGS_plan": bridge.ActionCarapaceBin("tofu", "plan").Split(), + "TF_CLI_ARGS_apply": bridge.ActionCarapaceBin("tofu", "apply").Split(), + "TF_CLI_ARGS_destroy": bridge.ActionCarapaceBin("tofu", "destroy").Split(), + "TF_CLI_ARGS_console": bridge.ActionCarapaceBin("tofu", "console").Split(), + "TF_CLI_ARGS_fmt": bridge.ActionCarapaceBin("tofu", "fmt").Split(), + "TF_CLI_ARGS_force-unlock": bridge.ActionCarapaceBin("tofu", "force-unlock").Split(), + "TF_CLI_ARGS_get": bridge.ActionCarapaceBin("tofu", "get").Split(), + "TF_CLI_ARGS_graph": bridge.ActionCarapaceBin("tofu", "graph").Split(), + "TF_CLI_ARGS_import": bridge.ActionCarapaceBin("tofu", "import").Split(), + "TF_CLI_ARGS_login": bridge.ActionCarapaceBin("tofu", "login").Split(), + "TF_CLI_ARGS_logout": bridge.ActionCarapaceBin("tofu", "logout").Split(), + "TF_CLI_ARGS_metadata": bridge.ActionCarapaceBin("tofu", "metadata").Split(), + "TF_CLI_ARGS_output": bridge.ActionCarapaceBin("tofu", "output").Split(), + "TF_CLI_ARGS_providers": bridge.ActionCarapaceBin("tofu", "providers").Split(), + "TF_CLI_ARGS_refresh": bridge.ActionCarapaceBin("tofu", "refresh").Split(), + "TF_CLI_ARGS_show": bridge.ActionCarapaceBin("tofu", "show").Split(), + "TF_CLI_ARGS_state": bridge.ActionCarapaceBin("tofu", "state").Split(), + "TF_CLI_ARGS_taint": bridge.ActionCarapaceBin("tofu", "taint").Split(), + "TF_CLI_ARGS_test": bridge.ActionCarapaceBin("tofu", "test").Split(), + "TF_CLI_ARGS_untaint": bridge.ActionCarapaceBin("tofu", "untaint").Split(), + "TF_CLI_ARGS_version": bridge.ActionCarapaceBin("tofu", "version").Split(), + "TF_CLI_ARGS_workspace": bridge.ActionCarapaceBin("tofu", "workspace").Split(), + "TF_DATA_DIR": carapace.ActionDirectories(), + "TF_WORKSPACE": tofu.ActionWorkspaces(), + "TF_IN_AUTOMATION": _bool, + "TF_CLI_CONFIG_FILE": carapace.ActionFiles(), + "TF_PLUGIN_CACHE_DIR": carapace.ActionDirectories(), + "TF_IGNORE": carapace.ActionValues("trace").StyleF(style.ForLogLevel), + }, + } +} diff --git a/pkg/actions/env/xdg.go b/pkg/actions/env/xdg.go index d65f030f48..880843cfbb 100644 --- a/pkg/actions/env/xdg.go +++ b/pkg/actions/env/xdg.go @@ -6,7 +6,7 @@ import ( func init() { knownVariables["xdg"] = variables{ - Names: map[string]string{ + Variables: map[string]string{ "XDG_DATA_HOME": "base directory relative to which user-specific data files should be stored", "XDG_CONFIG_HOME": "base directory relative to which user-specific configuration files should be stored", "XDG_STATE_HOME": "base directory relative to which user-specific state files should be stored", @@ -15,7 +15,7 @@ func init() { "XDG_CACHE_HOME": "base directory relative to which user-specific non-essential data files should be stored", "XDG_RUNTIME_DIR": "base directory relative to which user-specific non-essential runtime files should be stored", }, - Completion: map[string]carapace.Action{ + VariableCompletion: map[string]carapace.Action{ "XDG_DATA_HOME": carapace.ActionDirectories(), "XDG_CONFIG_HOME": carapace.ActionDirectories(), "XDG_STATE_HOME": carapace.ActionDirectories(), diff --git a/pkg/conditions/conditions.go b/pkg/conditions/conditions.go new file mode 100644 index 0000000000..8eab42c13a --- /dev/null +++ b/pkg/conditions/conditions.go @@ -0,0 +1,11 @@ +package conditions + +import ( + "github.com/rsteube/carapace-bin/internal/condition" + "github.com/rsteube/carapace-spec/pkg/macro" +) + +var ( + MacroMap = make(macro.MacroMap[condition.Macro]) + MacroDescriptions = make(map[string]string) +) diff --git a/pkg/conditions/fs.go b/pkg/conditions/fs.go new file mode 100644 index 0000000000..d2ec0cb10b --- /dev/null +++ b/pkg/conditions/fs.go @@ -0,0 +1,18 @@ +package conditions + +import ( + "github.com/rsteube/carapace" + "github.com/rsteube/carapace-bin/internal/condition" + "github.com/rsteube/carapace/pkg/traverse" +) + +// ConditionParent checks if any parent directory contains one of the given file/directory +// +// ConditionParent(".git") +// ConditionParent("go.mod", "go.sum") +func ConditionParent(s ...string) condition.Condition { + return func(c carapace.Context) bool { + _, err := traverse.Parent(s...)(carapace.NewContext()) + return err == nil + } +} diff --git a/pkg/conditions/os.go b/pkg/conditions/os.go new file mode 100644 index 0000000000..ec0b705bd6 --- /dev/null +++ b/pkg/conditions/os.go @@ -0,0 +1,45 @@ +package conditions + +import ( + "os/exec" + "runtime" + "slices" + + "github.com/rsteube/carapace" + "github.com/rsteube/carapace-bin/internal/condition" +) + +// ConditionArch checks if the given names contain current `runtime.GOARCH` +// +// ConditionArch("amd64") +// ConditionArch("arm", "arm64") +func ConditionArch(s ...string) condition.Condition { + return func(c carapace.Context) bool { + return slices.Contains(s, runtime.GOARCH) + } +} + +// ConditionOs checks if the given names contain current `runtime.GOOS` +// +// ConditionOs("windows") +// ConditionOs("darwin", "linux") +func ConditionOs(s ...string) condition.Condition { + return func(c carapace.Context) bool { + return slices.Contains(s, runtime.GOOS) + } +} + +// ConditionPath checks if any of the given executables are in PATH +// +// ConditionPath("git") +// ConditionPath("carapace", "go") +func ConditionPath(s ...string) condition.Condition { + return func(c carapace.Context) bool { + for _, file := range s { + if _, err := exec.LookPath(file); err == nil { + return true + } + } + return false + } +}