From 79cfc1e70a0f124f6b6bea5101211f79e1656c8c Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 23 Sep 2022 12:30:41 +0530 Subject: [PATCH] Move kitty-tool __complete__ to use the new CLI framework --- tools/cli/help.go | 11 ++++++-- tools/cli/option-from-string.go | 4 +-- tools/cli/parse-args.go | 8 +++--- tools/cli/types.go | 49 ++++++++++++++++----------------- tools/cmd/main.go | 24 +++++----------- tools/completion/main.go | 22 ++++++--------- 6 files changed, 54 insertions(+), 64 deletions(-) diff --git a/tools/cli/help.go b/tools/cli/help.go index 41dfb8fa2..4234818c6 100644 --- a/tools/cli/help.go +++ b/tools/cli/help.go @@ -41,8 +41,8 @@ func (self *Command) FormatSubCommands(output io.Writer, formatter *markup.Conte if !g.HasVisibleSubCommands() { continue } - fmt.Fprintln(output) if g.Title != "" { + fmt.Fprintln(output) fmt.Fprintln(output, formatter.Title(g.Title)) } for _, c := range g.SubCommands { @@ -57,6 +57,7 @@ func (self *Command) FormatSubCommands(output io.Writer, formatter *markup.Conte } func (self *Option) FormatOption(output io.Writer, formatter *markup.Context, screen_width int) { + fmt.Fprint(output, " ") for i, a := range self.Aliases { fmt.Fprint(output, formatter.Opt(a.String())) if i != len(self.Aliases)-1 { @@ -102,7 +103,11 @@ func (self *Command) ShowHelp() { fmt.Fprintln(&output, formatter.Title("Usage")+":", formatter.Exe(strings.TrimSpace(self.CommandStringForUsage())), strings.TrimSpace(formatter.Prettify(self.Usage))) fmt.Fprintln(&output) - format_with_indent(&output, formatter.Prettify(prepare_help_text_for_display(self.HelpText)), "", screen_width) + if self.HelpText != "" { + format_with_indent(&output, formatter.Prettify(prepare_help_text_for_display(self.HelpText)), "", screen_width) + } else if self.ShortDescription != "" { + format_with_indent(&output, formatter.Prettify(self.ShortDescription), "", screen_width) + } if self.HasVisibleSubCommands() { fmt.Fprintln(&output) @@ -118,8 +123,8 @@ func (self *Command) ShowHelp() { fmt.Fprintln(&output) fmt.Fprintln(&output, formatter.Title("Options")+":") for _, title := range group_titles { - fmt.Fprintln(&output) if title != "" { + fmt.Fprintln(&output) fmt.Fprintln(&output, formatter.Title(title)) } for _, opt := range gmap[title] { diff --git a/tools/cli/option-from-string.go b/tools/cli/option-from-string.go index fed84de8c..d0595614e 100644 --- a/tools/cli/option-from-string.go +++ b/tools/cli/option-from-string.go @@ -107,7 +107,7 @@ func option_from_spec(spec OptionSpec) (*Option, error) { } parts := strings.Split(spec.Name, " ") ans.Name = camel_case_dest(parts[0]) - ans.Aliases = make([]Alias, 0, len(parts)) + ans.Aliases = make([]Alias, len(parts)) for i, x := range parts { ans.Aliases[i] = Alias{NameWithoutHyphens: strings.TrimLeft(x, "-"), IsShort: !strings.HasPrefix(x, "--")} } @@ -198,7 +198,7 @@ func prepare_help_text_for_display(raw string) string { } } prev_indent = current_indent - if !strings.HasSuffix(help.String(), "\n") { + if help.Len() > 0 && !strings.HasSuffix(help.String(), "\n") { help.WriteString(" ") } help.WriteString(line) diff --git a/tools/cli/parse-args.go b/tools/cli/parse-args.go index 2e53637d2..7ddb3b4be 100644 --- a/tools/cli/parse-args.go +++ b/tools/cli/parse-args.go @@ -10,7 +10,7 @@ import ( var _ = fmt.Print func (self *Command) parse_args(ctx *Context, args []string) error { - args_to_parse := make([]string, 0, len(args)) + args_to_parse := make([]string, len(args)) copy(args_to_parse, args) ctx.SeenCommands = append(ctx.SeenCommands, self) @@ -39,7 +39,7 @@ func (self *Command) parse_args(ctx *Context, args []string) error { return nil } - for len(self.Args) > 0 { + for len(args_to_parse) > 0 { arg := consume_arg() if expecting_arg_for == nil { @@ -49,10 +49,10 @@ func (self *Command) parse_args(ctx *Context, args []string) error { options_allowed = false continue } - opt_str := "" + opt_str := arg opt_val := "" has_val := false - if strings.HasPrefix(opt_str, "--") || len(opt_str) == 2 { + if strings.HasPrefix(opt_str, "--") { parts := strings.SplitN(arg, "=", 2) if len(parts) > 1 { has_val = true diff --git a/tools/cli/types.go b/tools/cli/types.go index a9cff46e3..c723a5958 100644 --- a/tools/cli/types.go +++ b/tools/cli/types.go @@ -5,6 +5,7 @@ package cli import ( "fmt" "os" + "path/filepath" "reflect" "strconv" "strings" @@ -206,16 +207,12 @@ func (self *CommandGroup) Clone(parent *Command) *CommandGroup { return &ans } -func (self *CommandGroup) AddSubCommand(parent *Command, name string) (*Command, error) { - for _, c := range self.SubCommands { - if c.Name == name { - return nil, fmt.Errorf("A subcommand with the name %#v already exists in the parent command: %#v", name, parent.Name) - } - } +func (self *CommandGroup) AddSubCommand(parent *Command, name string) *Command { ans := NewRootCommand() ans.Parent = parent + ans.Name = name self.SubCommands = append(self.SubCommands, ans) - return ans, nil + return ans } func (self *CommandGroup) FindSubCommand(name string) *Command { @@ -246,6 +243,7 @@ func (self *OptionGroup) AddOption(parent *Command, spec OptionSpec) (*Option, e ans, err := option_from_spec(spec) if err == nil { ans.Parent = parent + self.Options = append(self.Options, ans) } return ans, err } @@ -254,6 +252,7 @@ func (self *OptionGroup) AddOptionFromString(parent *Command, items ...string) ( ans, err := OptionFromString(items...) if err == nil { ans.Parent = parent + self.Options = append(self.Options, ans) } return ans, err } @@ -320,6 +319,7 @@ func (self *Command) AddClone(group string, src *Command) (*Command, error) { func NewRootCommand() *Command { ans := Command{ + Name: filepath.Base(os.Args[0]), SubCommandGroups: make([]*CommandGroup, 0, 8), OptionGroups: make([]*OptionGroup, 0, 8), Args: make([]string, 0, 8), @@ -338,7 +338,7 @@ func (self *Command) AddSubCommandGroup(title string) *CommandGroup { return &ans } -func (self *Command) AddSubCommand(group string, name string) (*Command, error) { +func (self *Command) AddSubCommand(group string, name string) *Command { return self.AddSubCommandGroup(group).AddSubCommand(self, name) } @@ -363,6 +363,7 @@ func (self *Command) Validate() error { if seen_dests[o.Name] { return &ParseError{Message: fmt.Sprintf("The option :yellow:`%s` occurs twice inside %s", o.Name, self.Name)} } + seen_dests[o.Name] = true for _, a := range o.Aliases { q := a.String() if seen_flags[q] { @@ -372,25 +373,23 @@ func (self *Command) Validate() error { } } } - if self.Parent != nil { - if !seen_dests["Help"] { - if seen_flags["-h"] || seen_flags["--help"] { - return &ParseError{Message: fmt.Sprintf("The --help or -h flags are assigned to an option other than Help in %s", self.Name)} - } - _, err := self.Add(OptionSpec{Name: "--help -h", Type: "bool-set", Help: "Show help for this command"}) - if err != nil { - return err - } + if !seen_dests["Help"] { + if seen_flags["-h"] || seen_flags["--help"] { + return &ParseError{Message: fmt.Sprintf("The --help or -h flags are assigned to an option other than Help in %s", self.Name)} } + _, err := self.Add(OptionSpec{Name: "--help -h", Type: "bool-set", Help: "Show help for this command"}) + if err != nil { + return err + } + } - if self.Parent.Parent == nil && !seen_dests["Version"] { - if seen_flags["--version"] { - return &ParseError{Message: fmt.Sprintf("The --version flag is assigned to an option other than Version in %s", self.Name)} - } - _, err := self.Add(OptionSpec{Name: "--version", Type: "bool-set", Help: "Show version"}) - if err != nil { - return err - } + if self.Parent == nil && !seen_dests["Version"] { + if seen_flags["--version"] { + return &ParseError{Message: fmt.Sprintf("The --version flag is assigned to an option other than Version in %s", self.Name)} + } + _, err := self.Add(OptionSpec{Name: "--version", Type: "bool-set", Help: "Show version"}) + if err != nil { + return err } } diff --git a/tools/cmd/main.go b/tools/cmd/main.go index f0052b7e9..51bdb70d5 100644 --- a/tools/cmd/main.go +++ b/tools/cmd/main.go @@ -3,27 +3,17 @@ package main import ( - "os" - - "github.com/spf13/cobra" - "kitty/tools/cli" - "kitty/tools/cmd/at" + _ "kitty/tools/cmd/at" "kitty/tools/completion" ) func main() { - var root = cli.CreateCommand(&cobra.Command{ - Use: "kitty-tool command [command options] [command args]", - Short: "Fast, statically compiled implementations for various kitty command-line tools", - }) - root.AddCommand(at.EntryPoint(root)) + root := cli.NewRootCommand() + root.ShortDescription = "Fast, statically compiled implementations for various kitty command-line tools" + root.Usage = "command [command options] [command args]" + // root.AddCommand(at.EntryPoint(root)) - root.AddCommand(completion.EntryPoint(root)) - - cli.Init(root) - if err := cli.Execute(root); err != nil { - cli.PrintError(err) - os.Exit(1) - } + completion.EntryPoint(root) + root.Exec() } diff --git a/tools/completion/main.go b/tools/completion/main.go index 2c74362ca..b77db317c 100644 --- a/tools/completion/main.go +++ b/tools/completion/main.go @@ -8,8 +8,6 @@ import ( "io" "os" - "github.com/spf13/cobra" - "kitty/tools/cli" "kitty/tools/tty" "kitty/tools/utils" @@ -95,15 +93,13 @@ func main(args []string) error { return err } -func EntryPoint(tool_root *cobra.Command) *cobra.Command { - complete_command := cli.CreateCommand(&cobra.Command{ - Use: "__complete__ output_type [shell state...]", - Short: "Generate completions for kitty commands", - Long: "Generate completion candidates for kitty commands. The command line is read from STDIN. output_type can be one of the supported shells or 'json' for JSON output.", - Hidden: true, - RunE: func(cmd *cobra.Command, args []string) error { - return main(args) - }, - }) - return complete_command +func EntryPoint(tool_root *cli.Command) { + c := tool_root.AddSubCommand("", "__complete__") + c.Usage = "output_type [shell state...]" + c.Hidden = true + c.ShortDescription = "Generate completions for kitty commands" + c.HelpText = "Generate completion candidates for kitty commands. The command line is read from STDIN. output_type can be one of the supported shells or 'json' for JSON output." + c.Run = func(cmd *cli.Command, args []string) (ret int, err error) { + return ret, main(args) + } }