diff --git a/cmd/carapace/cmd/action/completer.go b/cmd/carapace/cmd/action/completer.go new file mode 100644 index 0000000000..9b84216bc0 --- /dev/null +++ b/cmd/carapace/cmd/action/completer.go @@ -0,0 +1,38 @@ +package action + +import ( + "encoding/json" + + "github.com/rsteube/carapace" + "github.com/rsteube/carapace/pkg/style" +) + +func ActionCompleters() carapace.Action { + return carapace.ActionCallback(func(c carapace.Context) carapace.Action { + return carapace.ActionExecCommand("carapace", "--list=json")(func(output []byte) carapace.Action { + var completers []struct { + Name string + Description string + Spec string + Overlay string + } + if err := json.Unmarshal(output, &completers); err != nil { + return carapace.ActionMessage(err.Error()) + } + + vals := make([]string, 0, len(completers)) + for _, completer := range completers { + s := style.Default + if completer.Spec != "" { + s = style.Blue + } + if completer.Overlay != "" { + s = style.Of(s, style.Underlined) + } + + vals = append(vals, completer.Name, completer.Description, s) + } + return carapace.ActionStyledValuesDescribed(vals...) + }) + }) +} diff --git a/cmd/carapace/cmd/root.go b/cmd/carapace/cmd/root.go index d7c0d09c4a..d2e13ea8f4 100644 --- a/cmd/carapace/cmd/root.go +++ b/cmd/carapace/cmd/root.go @@ -9,14 +9,15 @@ import ( "io" "os" "path/filepath" + "slices" "sort" "strconv" "strings" "time" "github.com/rsteube/carapace" + "github.com/rsteube/carapace-bin/cmd/carapace/cmd/action" "github.com/rsteube/carapace-bin/cmd/carapace/cmd/completers" - "github.com/rsteube/carapace-bin/cmd/carapace/cmd/shim" spec "github.com/rsteube/carapace-spec" "github.com/rsteube/carapace/pkg/ps" "github.com/rsteube/carapace/pkg/style" @@ -58,164 +59,153 @@ var rootCmd = &cobra.Command{ Config is written to [%v/carapace]. Specs are loaded from [%v/carapace/specs]. `, suppressErr(xdg.UserCacheDir), suppressErr(xdg.UserConfigDir), suppressErr(xdg.UserConfigDir)), - Args: cobra.MinimumNArgs(1), - ValidArgs: completers.Names(), - Run: func(cmd *cobra.Command, args []string) { - // since flag parsing is disabled do this manually - switch args[0] { - case "--macros": - if len(args) > 1 { - printMacro(args[1]) - } else { - printMacros() - } - case "-h", "--help": - cmd.Help() - case "-v", "--version": - println(cmd.Version) - case "--list": - printCompleters() - case "--list=json": - printCompletersJson() - case "--run": - _, spec, err := loadSpec(args[1]) - if err != nil { - fmt.Fprintln(cmd.ErrOrStderr(), err.Error()) - os.Exit(1) - } - - cmd := spec.ToCobra() - cmd.SetArgs(args[2:]) - cmd.Execute() // TODO handle error? - case "--schema": - if schema, err := spec.Schema(); err != nil { - fmt.Fprintln(cmd.ErrOrStderr(), err.Error()) // TODO fail / exit 1 ? - } else { - fmt.Fprintln(cmd.OutOrStdout(), schema) - } - case "--scrape": - if len(args) > 1 { - scrape(args[1]) - } - case "--style": - if len(args) > 1 { - if err := setStyle(args[1]); err != nil { - fmt.Fprintln(cmd.ErrOrStderr(), err.Error()) - } - } - case "_carapace": - shell := ps.DetermineShell() - if len(args) > 1 { - shell = args[1] - } - if len(args) <= 2 { - if err := shim.Update(); err != nil { - fmt.Fprintln(cmd.ErrOrStderr(), err.Error()) // TODO fail / exit 1 ? - } - - if err := updateSchema(); err != nil { // TODO do this only if needed - fmt.Fprintln(cmd.ErrOrStderr(), err.Error()) - } + CompletionOptions: cobra.CompletionOptions{ + DisableDefaultCmd: true, + }, + RunE: func(cmd *cobra.Command, args []string) error { + if len(os.Args) == 1 { + return cmd.Usage() + } - if err := createOverlayDir(); err != nil { // TODO do this only if needed - fmt.Fprintln(cmd.ErrOrStderr(), err.Error()) - } - } - switch shell { - case "bash": - fmt.Fprintln(cmd.OutOrStdout(), bash_lazy(completers.Names())) - case "bash-ble": - fmt.Fprintln(cmd.OutOrStdout(), bash_ble_lazy(completers.Names())) - case "elvish": - fmt.Fprintln(cmd.OutOrStdout(), elvish_lazy(completers.Names())) - case "fish": - fmt.Fprintln(cmd.OutOrStdout(), fish_lazy(completers.Names())) - case "nushell": - fmt.Fprintln(cmd.OutOrStdout(), nushell_lazy(completers.Names())) - case "oil": - fmt.Fprintln(cmd.OutOrStdout(), oil_lazy(completers.Names())) - case "powershell": - fmt.Fprintln(cmd.OutOrStdout(), powershell_lazy(completers.Names())) - case "tcsh": - fmt.Fprintln(cmd.OutOrStdout(), tcsh_lazy(completers.Names())) - case "xonsh": - fmt.Fprintln(cmd.OutOrStdout(), xonsh_lazy(completers.Names())) - case "zsh": - fmt.Fprintln(cmd.OutOrStdout(), zsh_lazy(completers.Names())) + switch { + case cmd.Flag("list").Changed: + // TODO pass value to printCompleters and handle variants there + switch cmd.Flag("list").Value.String() { + case "json": + printCompletersJson() default: - fmt.Fprintln(os.Stderr, "could not determine shell") + printCompleters() } - default: - if overlayPath, err := overlayPath(args[0]); err == nil && len(args) > 2 { // and arg[1] is a known shell - cmd := &cobra.Command{ - DisableFlagParsing: true, - CompletionOptions: cobra.CompletionOptions{ - DisableDefaultCmd: true, - }, - } - // TODO yuck - command := args[0] - shell := args[1] - args[0] = "_carapace" - args[1] = "export" - os.Args[1] = "_carapace" - os.Args[2] = "export" - os.Setenv("CARAPACE_LENIENT", "1") - - carapace.Gen(cmd).PositionalAnyCompletion( - carapace.ActionCallback(func(c carapace.Context) carapace.Action { - batch := carapace.Batch() - specPath, err := completers.SpecPath(command) - if err != nil { - batch = append(batch, carapace.ActionImport([]byte(invokeCompleter(command)))) - } else { - out, err := specCompletion(specPath, args[1:]...) - if err != nil { - return carapace.ActionMessage(err.Error()) - } - - batch = append(batch, carapace.ActionImport([]byte(out))) - } - - batch = append(batch, overlayCompletion(overlayPath, args[1:]...)) - return batch.ToA() - }), - ) - - cmd.SetArgs(append([]string{"_carapace", shell}, args[2:]...)) - cmd.Execute() - } else { - if specPath, err := completers.SpecPath(args[0]); err == nil { - out, err := specCompletion(specPath, args[1:]...) - if err != nil { - fmt.Fprintln(cmd.ErrOrStderr(), err.Error()) - return - } - - // TODO revert the patching from specCompletion to use the integrated version for overlay to work (should move this somewhere else - best in specCompletion) - // TODO only patch completion script - out = strings.Replace(out, fmt.Sprintf("--spec '%v'", specPath), args[0], -1) - out = strings.Replace(out, fmt.Sprintf("'--spec', '%v'", specPath), fmt.Sprintf("'%v'", args[0]), -1) // xonsh callback - fmt.Fprint(cmd.OutOrStdout(), out) - } else { - fmt.Print(invokeCompleter(args[0])) - } - } } + return nil }, - FParseErrWhitelist: cobra.FParseErrWhitelist{ - UnknownFlags: true, - }, - DisableFlagParsing: true, - CompletionOptions: cobra.CompletionOptions{ - DisableDefaultCmd: true, - }, +} + +func Execute(version string) error { + rootCmd.Version = version + return rootCmd.Execute() +} + +func init() { + rootCmd.Flags().SetInterspersed(false) + + rootCmd.Flags().Bool("macros", false, "TODO") + rootCmd.Flags().String("list", "", "list completers") + rootCmd.Flags().String("run", "", "run spec") + rootCmd.Flags().String("schema", "", "TODO") // TODO + rootCmd.Flags().String("scrape", "", "scrape spec to go code") + rootCmd.Flags().String("style", "", "set style") + + rootCmd.Flag("list").NoOptDefVal = " " + + rootCmd.MarkFlagsMutuallyExclusive( + "macros", + "list", + "run", + "schema", + "scrape", + "style", + ) + + carapace.Gen(rootCmd).FlagCompletion(carapace.ActionMap{ + "list": carapace.ActionValues("json"), + "run": carapace.ActionFiles(), + "scrape": carapace.ActionFiles(), + "style": carapace.ActionStyleConfig(), + }) + + carapace.Gen(rootCmd).PositionalCompletion( + action.ActionCompleters(), // TODO not when flags are set + ) + + if len(os.Args) > 1 && !strings.HasPrefix(os.Args[1], "-") { + // TODO needs to be add only for current completer/spec + rootCmd.AddCommand(&cobra.Command{ + Use: os.Args[1], + Hidden: true, + DisableFlagParsing: true, + CompletionOptions: cobra.CompletionOptions{ + DisableDefaultCmd: true, + }, + Run: func(cmd *cobra.Command, args []string) { + specs, _ := completers.Specs() + switch { + case slices.Contains(specs, cmd.Name()): + // TODO invoke spec + panic("TODO invoke spec") + case slices.Contains(completers.Names(), cmd.Name()): + fmt.Fprint(cmd.OutOrStdout(), invokeCompleter(cmd.Name())) + } + }, + }) + } + + for m, f := range macros { + spec.AddMacro(m, f) + } + + overrideInitScripts(rootCmd) } func suppressErr(f func() (string, error)) string { s, _ := f(); return s } +func overrideInitScripts(cmd *cobra.Command) { + carapaceCmd, _, _ := cmd.Find([]string{"_carapace"}) + oldRun := carapaceCmd.Run + carapaceCmd.Run = func(cmd *cobra.Command, args []string) { + carapace.LOG.Printf("%#v", args) + if len(args) > 1 { + oldRun(cmd, args) + return + } + + shell := ps.DetermineShell() + if len(args) > 0 { + shell = args[0] + } + // TODO renable (fix args length) + // if len(args) <= 2 { + // if err := shim.Update(); err != nil { + // fmt.Fprintln(cmd.ErrOrStderr(), err.Error()) // TODO fail / exit 1 ? + // } + + // if err := updateSchema(); err != nil { // TODO do this only if needed + // fmt.Fprintln(cmd.ErrOrStderr(), err.Error()) + // } + + // if err := createOverlayDir(); err != nil { // TODO do this only if needed + // fmt.Fprintln(cmd.ErrOrStderr(), err.Error()) + // } + // } + switch shell { + case "bash": + fmt.Fprintln(cmd.OutOrStdout(), bash_lazy(completers.Names())) + case "bash-ble": + fmt.Fprintln(cmd.OutOrStdout(), bash_ble_lazy(completers.Names())) + case "elvish": + fmt.Fprintln(cmd.OutOrStdout(), elvish_lazy(completers.Names())) + case "fish": + fmt.Fprintln(cmd.OutOrStdout(), fish_lazy(completers.Names())) + case "nushell": + fmt.Fprintln(cmd.OutOrStdout(), nushell_lazy(completers.Names())) + case "oil": + fmt.Fprintln(cmd.OutOrStdout(), oil_lazy(completers.Names())) + case "powershell": + fmt.Fprintln(cmd.OutOrStdout(), powershell_lazy(completers.Names())) + case "tcsh": + fmt.Fprintln(cmd.OutOrStdout(), tcsh_lazy(completers.Names())) + case "xonsh": + fmt.Fprintln(cmd.OutOrStdout(), xonsh_lazy(completers.Names())) + case "zsh": + fmt.Fprintln(cmd.OutOrStdout(), zsh_lazy(completers.Names())) + default: + fmt.Fprintln(os.Stderr, "could not determine shell") + } + } +} + func printCompleters() { maxlen := 0 for _, name := range completers.Names() { @@ -395,18 +385,149 @@ func updateSchema() error { return nil } -func Execute(version string) error { - rootCmd.Version = version - return rootCmd.Execute() -} - -func init() { - rootCmd.Flags().Bool("list", false, "list completers") - rootCmd.Flags().String("run", "", "run spec") - rootCmd.Flags().String("scrape", "", "scrape spec to go code") - rootCmd.Flags().String("style", "", "set style") - - for m, f := range macros { - spec.AddMacro(m, f) - } -} +// func(cmd *cobra.Command, args []string) { +// // since flag parsing is disabled do this manually +// switch args[0] { +// case "--macros": +// if len(args) > 1 { +// printMacro(args[1]) +// } else { +// printMacros() +// } +// case "-h", "--help": +// cmd.Help() +// case "-v", "--version": +// println(cmd.Version) +// case "--list": +// printCompleters() +// case "--list=json": +// printCompletersJson() +// case "--run": +// _, spec, err := loadSpec(args[1]) +// if err != nil { +// fmt.Fprintln(cmd.ErrOrStderr(), err.Error()) +// os.Exit(1) +// } + +// cmd := spec.ToCobra() +// cmd.SetArgs(args[2:]) +// cmd.Execute() // TODO handle error? +// case "--schema": +// if schema, err := spec.Schema(); err != nil { +// fmt.Fprintln(cmd.ErrOrStderr(), err.Error()) // TODO fail / exit 1 ? +// } else { +// fmt.Fprintln(cmd.OutOrStdout(), schema) +// } +// case "--scrape": +// if len(args) > 1 { +// scrape(args[1]) +// } +// case "--style": +// if len(args) > 1 { +// if err := setStyle(args[1]); err != nil { +// fmt.Fprintln(cmd.ErrOrStderr(), err.Error()) +// } +// } +// case "_carapace": +// shell := ps.DetermineShell() +// if len(args) > 1 { +// shell = args[1] +// } +// if len(args) <= 2 { +// if err := shim.Update(); err != nil { +// fmt.Fprintln(cmd.ErrOrStderr(), err.Error()) // TODO fail / exit 1 ? +// } + +// if err := updateSchema(); err != nil { // TODO do this only if needed +// fmt.Fprintln(cmd.ErrOrStderr(), err.Error()) +// } + +// if err := createOverlayDir(); err != nil { // TODO do this only if needed +// fmt.Fprintln(cmd.ErrOrStderr(), err.Error()) +// } +// } +// switch shell { +// case "bash": +// fmt.Fprintln(cmd.OutOrStdout(), bash_lazy(completers.Names())) +// case "bash-ble": +// fmt.Fprintln(cmd.OutOrStdout(), bash_ble_lazy(completers.Names())) +// case "elvish": +// fmt.Fprintln(cmd.OutOrStdout(), elvish_lazy(completers.Names())) +// case "fish": +// fmt.Fprintln(cmd.OutOrStdout(), fish_lazy(completers.Names())) +// case "nushell": +// fmt.Fprintln(cmd.OutOrStdout(), nushell_lazy(completers.Names())) +// case "oil": +// fmt.Fprintln(cmd.OutOrStdout(), oil_lazy(completers.Names())) +// case "powershell": +// fmt.Fprintln(cmd.OutOrStdout(), powershell_lazy(completers.Names())) +// case "tcsh": +// fmt.Fprintln(cmd.OutOrStdout(), tcsh_lazy(completers.Names())) +// case "xonsh": +// fmt.Fprintln(cmd.OutOrStdout(), xonsh_lazy(completers.Names())) +// case "zsh": +// fmt.Fprintln(cmd.OutOrStdout(), zsh_lazy(completers.Names())) +// default: +// fmt.Fprintln(os.Stderr, "could not determine shell") +// } +// default: +// if overlayPath, err := overlayPath(args[0]); err == nil && len(args) > 2 { // and arg[1] is a known shell +// cmd := &cobra.Command{ +// DisableFlagParsing: true, +// CompletionOptions: cobra.CompletionOptions{ +// DisableDefaultCmd: true, +// }, +// } + +// // TODO yuck +// command := args[0] +// shell := args[1] +// args[0] = "_carapace" +// args[1] = "export" +// os.Args[1] = "_carapace" +// os.Args[2] = "export" +// os.Setenv("CARAPACE_LENIENT", "1") + +// carapace.Gen(cmd).PositionalAnyCompletion( +// carapace.ActionCallback(func(c carapace.Context) carapace.Action { +// batch := carapace.Batch() +// specPath, err := completers.SpecPath(command) +// if err != nil { +// batch = append(batch, carapace.ActionImport([]byte(invokeCompleter(command)))) +// } else { +// out, err := specCompletion(specPath, args[1:]...) +// if err != nil { +// return carapace.ActionMessage(err.Error()) +// } + +// batch = append(batch, carapace.ActionImport([]byte(out))) +// } + +// batch = append(batch, overlayCompletion(overlayPath, args[1:]...)) +// return batch.ToA() +// }), +// ) + +// cmd.SetArgs(append([]string{"_carapace", shell}, args[2:]...)) +// cmd.Execute() +// } else { +// if specPath, err := completers.SpecPath(args[0]); err == nil { +// out, err := specCompletion(specPath, args[1:]...) +// if err != nil { +// fmt.Fprintln(cmd.ErrOrStderr(), err.Error()) +// return +// } + +// // TODO revert the patching from specCompletion to use the integrated version for overlay to work (should move this somewhere else - best in specCompletion) +// // TODO only patch completion script +// out = strings.Replace(out, fmt.Sprintf("--spec '%v'", specPath), args[0], -1) +// out = strings.Replace(out, fmt.Sprintf("'--spec', '%v'", specPath), fmt.Sprintf("'%v'", args[0]), -1) // xonsh callback +// fmt.Fprint(cmd.OutOrStdout(), out) +// } else { +// fmt.Print(invokeCompleter(args[0])) +// } +// } +// } + +// +// } diff --git a/completers/carapace_completer/cmd/backup.txt b/completers/carapace_completer/cmd/backup.txt new file mode 100644 index 0000000000..dbc2b92473 --- /dev/null +++ b/completers/carapace_completer/cmd/backup.txt @@ -0,0 +1,187 @@ +package cmd + +import ( + "encoding/json" + "strings" + + "github.com/rsteube/carapace" + spec "github.com/rsteube/carapace-spec" + "github.com/rsteube/carapace/pkg/style" + "github.com/spf13/cobra" + "github.com/spf13/pflag" +) + +var rootCmd = &cobra.Command{ + Use: "carapace", + Short: "multi-shell multi-command argument completer", + Long: "https://github.com/rsteube/carapace-bin", + DisableFlagParsing: true, + CompletionOptions: cobra.CompletionOptions{ + DisableDefaultCmd: true, + }, + Run: func(cmd *cobra.Command, args []string) {}, +} + +func flagCmd(args []string) *cobra.Command { + cmd := &cobra.Command{ + Use: "carapace", + CompletionOptions: cobra.CompletionOptions{ + DisableDefaultCmd: true, + }, + Run: func(cmd *cobra.Command, args []string) {}, + } + + cmd.Flags().BoolP("help", "h", false, "help for carapace") + cmd.Flags().String("list", "", "list completers") + cmd.Flags().String("macros", "test local json schema", "list spec macros") + cmd.Flags().String("run", "", "run spec") + cmd.Flags().Bool("schema", false, "json schema for spec files") + cmd.Flags().String("scrape", "", "scrape spec to go code") + cmd.Flags().String("style", "", "set style") + cmd.Flags().BoolP("version", "v", false, "version for carapace") + + cmd.Flag("list").NoOptDefVal = " " + + if len(args) > 0 { + if f := cmd.Flag(strings.TrimPrefix(args[0], "--")); len(args) > 1 || f != nil && f.Value.Type() == "bool" { + cmd.Flags().VisitAll(func(f *pflag.Flag) { + f.Changed = true // only one flag shall be completed so fake the changed state + }) + } + } + + carapace.Gen(cmd).FlagCompletion(carapace.ActionMap{ + "list": carapace.ActionValues("json"), + "macros": carapace.ActionExecCommand("carapace", "--macros")(func(output []byte) carapace.Action { + lines := strings.Split(string(output), "\n") + + vals := make([]string, 0) + for _, line := range lines[:len(lines)-1] { + if fields := strings.Fields(line); len(fields) > 1 { + vals = append(vals, fields[0], strings.Join(fields[1:], " ")) + } else { + vals = append(vals, fields[0], "") + } + } + return carapace.ActionValuesDescribed(vals...).Invoke(carapace.Context{}).ToMultiPartsA(".") + }), + "run": carapace.ActionFiles(".yaml"), + "scrape": carapace.ActionFiles(".yaml"), + "style": carapace.ActionStyleConfig().NoSpace(), + }) + + carapace.Gen(cmd).PositionalAnyCompletion( + carapace.ActionCallback(func(c carapace.Context) carapace.Action { + if len(args) > 0 && args[0] == "--macros" { + c.Args = args[2:] + return spec.ActionMacro("$_" + args[1]).Invoke(c).ToA() + } + return carapace.ActionValues() + }), + ) + + return cmd +} + +func posCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "carapace", + DisableFlagParsing: true, + CompletionOptions: cobra.CompletionOptions{ + DisableDefaultCmd: true, + }, + Run: func(cmd *cobra.Command, args []string) {}, + } + + carapace.Gen(cmd).PositionalCompletion( + ActionCompleters(), + carapace.ActionStyledValues( + "bash", "#d35673", + "bash-ble", "#c2039a", + "elvish", "#ffd6c9", + "export", style.Default, + "fish", "#7ea8fc", + "ion", "#0e5d6d", + "nushell", "#29d866", + "oil", "#373a36", + "powershell", "#e8a16f", + "spec", style.Default, + "tcsh", "#412f09", + "xonsh", "#a8ffa9", + "zsh", "#efda53", + ), + carapace.ActionCallback(func(c carapace.Context) carapace.Action { + return carapace.ActionValues(c.Args[0]) + }), + ) + + carapace.Gen(cmd).PositionalAnyCompletion( + carapace.ActionCallback(func(c carapace.Context) carapace.Action { + args := []string{c.Args[0], "export", c.Args[0]} + args = append(args, c.Args[3:]...) + args = append(args, c.Value) + return carapace.ActionExecCommand("carapace", args...)(func(output []byte) carapace.Action { + if string(output) == "" { + return carapace.ActionValues() + } + return carapace.ActionImport(output) + }) + }), + ) + + return cmd +} + +func Execute() error { + return rootCmd.Execute() +} + +func init() { + carapace.Gen(rootCmd).Standalone() + + carapace.Gen(rootCmd).PositionalAnyCompletion( + carapace.ActionCallback(func(c carapace.Context) carapace.Action { + if len(c.Args) == 0 { + return carapace.Batch( + carapace.ActionExecute(flagCmd(c.Args)), + carapace.ActionExecute(posCmd()), + ).ToA() + } + + if strings.HasPrefix(c.Args[0], "-") { + return carapace.ActionExecute(flagCmd(c.Args)) + } + return carapace.ActionExecute(posCmd()) + }), + ) +} + +func ActionCompleters() carapace.Action { + return carapace.ActionCallback(func(c carapace.Context) carapace.Action { + return carapace.ActionExecCommand("carapace", "--list=json")(func(output []byte) carapace.Action { + var completers []struct { + Name string + Description string + Spec string + Overlay string + } + if err := json.Unmarshal(output, &completers); err != nil { + return carapace.ActionMessage(err.Error()) + } + + vals := make([]string, 0, len(completers)) + for _, completer := range completers { + s := style.Default + if completer.Spec != "" { + s = style.Blue + } + if completer.Overlay != "" { + s = style.Of(s, style.Underlined) + } + + vals = append(vals, completer.Name, completer.Description, s) + } + return carapace.ActionStyledValuesDescribed(vals...) + }) + }) +} diff --git a/completers/carapace_completer/cmd/root.go b/completers/carapace_completer/cmd/root.go index dbc2b92473..92024a99a1 100644 --- a/completers/carapace_completer/cmd/root.go +++ b/completers/carapace_completer/cmd/root.go @@ -1,14 +1,9 @@ package cmd import ( - "encoding/json" - "strings" - "github.com/rsteube/carapace" - spec "github.com/rsteube/carapace-spec" - "github.com/rsteube/carapace/pkg/style" + "github.com/rsteube/carapace-bridge/pkg/actions/bridge" "github.com/spf13/cobra" - "github.com/spf13/pflag" ) var rootCmd = &cobra.Command{ @@ -22,116 +17,6 @@ var rootCmd = &cobra.Command{ Run: func(cmd *cobra.Command, args []string) {}, } -func flagCmd(args []string) *cobra.Command { - cmd := &cobra.Command{ - Use: "carapace", - CompletionOptions: cobra.CompletionOptions{ - DisableDefaultCmd: true, - }, - Run: func(cmd *cobra.Command, args []string) {}, - } - - cmd.Flags().BoolP("help", "h", false, "help for carapace") - cmd.Flags().String("list", "", "list completers") - cmd.Flags().String("macros", "test local json schema", "list spec macros") - cmd.Flags().String("run", "", "run spec") - cmd.Flags().Bool("schema", false, "json schema for spec files") - cmd.Flags().String("scrape", "", "scrape spec to go code") - cmd.Flags().String("style", "", "set style") - cmd.Flags().BoolP("version", "v", false, "version for carapace") - - cmd.Flag("list").NoOptDefVal = " " - - if len(args) > 0 { - if f := cmd.Flag(strings.TrimPrefix(args[0], "--")); len(args) > 1 || f != nil && f.Value.Type() == "bool" { - cmd.Flags().VisitAll(func(f *pflag.Flag) { - f.Changed = true // only one flag shall be completed so fake the changed state - }) - } - } - - carapace.Gen(cmd).FlagCompletion(carapace.ActionMap{ - "list": carapace.ActionValues("json"), - "macros": carapace.ActionExecCommand("carapace", "--macros")(func(output []byte) carapace.Action { - lines := strings.Split(string(output), "\n") - - vals := make([]string, 0) - for _, line := range lines[:len(lines)-1] { - if fields := strings.Fields(line); len(fields) > 1 { - vals = append(vals, fields[0], strings.Join(fields[1:], " ")) - } else { - vals = append(vals, fields[0], "") - } - } - return carapace.ActionValuesDescribed(vals...).Invoke(carapace.Context{}).ToMultiPartsA(".") - }), - "run": carapace.ActionFiles(".yaml"), - "scrape": carapace.ActionFiles(".yaml"), - "style": carapace.ActionStyleConfig().NoSpace(), - }) - - carapace.Gen(cmd).PositionalAnyCompletion( - carapace.ActionCallback(func(c carapace.Context) carapace.Action { - if len(args) > 0 && args[0] == "--macros" { - c.Args = args[2:] - return spec.ActionMacro("$_" + args[1]).Invoke(c).ToA() - } - return carapace.ActionValues() - }), - ) - - return cmd -} - -func posCmd() *cobra.Command { - cmd := &cobra.Command{ - Use: "carapace", - DisableFlagParsing: true, - CompletionOptions: cobra.CompletionOptions{ - DisableDefaultCmd: true, - }, - Run: func(cmd *cobra.Command, args []string) {}, - } - - carapace.Gen(cmd).PositionalCompletion( - ActionCompleters(), - carapace.ActionStyledValues( - "bash", "#d35673", - "bash-ble", "#c2039a", - "elvish", "#ffd6c9", - "export", style.Default, - "fish", "#7ea8fc", - "ion", "#0e5d6d", - "nushell", "#29d866", - "oil", "#373a36", - "powershell", "#e8a16f", - "spec", style.Default, - "tcsh", "#412f09", - "xonsh", "#a8ffa9", - "zsh", "#efda53", - ), - carapace.ActionCallback(func(c carapace.Context) carapace.Action { - return carapace.ActionValues(c.Args[0]) - }), - ) - - carapace.Gen(cmd).PositionalAnyCompletion( - carapace.ActionCallback(func(c carapace.Context) carapace.Action { - args := []string{c.Args[0], "export", c.Args[0]} - args = append(args, c.Args[3:]...) - args = append(args, c.Value) - return carapace.ActionExecCommand("carapace", args...)(func(output []byte) carapace.Action { - if string(output) == "" { - return carapace.ActionValues() - } - return carapace.ActionImport(output) - }) - }), - ) - - return cmd -} - func Execute() error { return rootCmd.Execute() } @@ -140,48 +25,6 @@ func init() { carapace.Gen(rootCmd).Standalone() carapace.Gen(rootCmd).PositionalAnyCompletion( - carapace.ActionCallback(func(c carapace.Context) carapace.Action { - if len(c.Args) == 0 { - return carapace.Batch( - carapace.ActionExecute(flagCmd(c.Args)), - carapace.ActionExecute(posCmd()), - ).ToA() - } - - if strings.HasPrefix(c.Args[0], "-") { - return carapace.ActionExecute(flagCmd(c.Args)) - } - return carapace.ActionExecute(posCmd()) - }), + bridge.ActionCarapace("carapace"), ) } - -func ActionCompleters() carapace.Action { - return carapace.ActionCallback(func(c carapace.Context) carapace.Action { - return carapace.ActionExecCommand("carapace", "--list=json")(func(output []byte) carapace.Action { - var completers []struct { - Name string - Description string - Spec string - Overlay string - } - if err := json.Unmarshal(output, &completers); err != nil { - return carapace.ActionMessage(err.Error()) - } - - vals := make([]string, 0, len(completers)) - for _, completer := range completers { - s := style.Default - if completer.Spec != "" { - s = style.Blue - } - if completer.Overlay != "" { - s = style.Of(s, style.Underlined) - } - - vals = append(vals, completer.Name, completer.Description, s) - } - return carapace.ActionStyledValuesDescribed(vals...) - }) - }) -} diff --git a/go.mod b/go.mod index 35f7f7ea4d..e335ee870b 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/rsteube/carapace-bin -go 1.21 +go 1.21.1 require ( github.com/pelletier/go-toml v1.9.5