Get rid of the cobra dependency
This commit is contained in:
@@ -31,7 +31,6 @@ func (self *Command) ShowVersion() {
|
||||
}
|
||||
|
||||
func format_with_indent(output io.Writer, text string, indent string, screen_width int) {
|
||||
text = formatter.Prettify(text)
|
||||
indented := style.WrapText(text, indent, screen_width, "#placeholder_for_formatting#")
|
||||
io.WriteString(output, indented)
|
||||
}
|
||||
@@ -41,10 +40,12 @@ func (self *Command) FormatSubCommands(output io.Writer, formatter *markup.Conte
|
||||
if !g.HasVisibleSubCommands() {
|
||||
continue
|
||||
}
|
||||
if g.Title != "" {
|
||||
fmt.Fprintln(output)
|
||||
fmt.Fprintln(output, formatter.Title(g.Title))
|
||||
title := g.Title
|
||||
if title == "" {
|
||||
title = "Commands"
|
||||
}
|
||||
fmt.Fprintln(output)
|
||||
fmt.Fprintln(output, formatter.Title(title)+":")
|
||||
for _, c := range g.SubCommands {
|
||||
if c.Hidden {
|
||||
continue
|
||||
@@ -64,22 +65,23 @@ func (self *Option) FormatOption(output io.Writer, formatter *markup.Context, sc
|
||||
fmt.Fprint(output, ", ")
|
||||
}
|
||||
}
|
||||
defval := ""
|
||||
defval := self.Default
|
||||
switch self.OptionType {
|
||||
case BoolOption:
|
||||
default:
|
||||
defval = self.Default
|
||||
fallthrough
|
||||
case StringOption:
|
||||
if self.IsList {
|
||||
defval = ""
|
||||
}
|
||||
case BoolOption, CountOption:
|
||||
defval = ""
|
||||
}
|
||||
if defval != "" {
|
||||
fmt.Fprintf(output, " [=%s]", formatter.Italic(defval))
|
||||
}
|
||||
fmt.Fprintln(output)
|
||||
format_with_indent(output, formatter.Prettify(prepare_help_text_for_display(self.Help)), " ", screen_width)
|
||||
if self.Choices != nil {
|
||||
format_with_indent(output, "Choices: "+strings.Join(self.Choices, ", "), " ", screen_width)
|
||||
}
|
||||
}
|
||||
|
||||
func (self *Command) ShowHelp() {
|
||||
@@ -111,7 +113,6 @@ func (self *Command) ShowHelp() {
|
||||
|
||||
if self.HasVisibleSubCommands() {
|
||||
fmt.Fprintln(&output)
|
||||
fmt.Fprintln(&output, formatter.Title("Commands")+":")
|
||||
self.FormatSubCommands(&output, formatter, screen_width)
|
||||
fmt.Fprintln(&output)
|
||||
format_with_indent(&output, "Get help for an individual command by running:", "", screen_width)
|
||||
@@ -121,12 +122,12 @@ func (self *Command) ShowHelp() {
|
||||
group_titles, gmap := self.GetVisibleOptions()
|
||||
if len(group_titles) > 0 {
|
||||
fmt.Fprintln(&output)
|
||||
fmt.Fprintln(&output, formatter.Title("Options")+":")
|
||||
for _, title := range group_titles {
|
||||
if title != "" {
|
||||
fmt.Fprintln(&output)
|
||||
fmt.Fprintln(&output, formatter.Title(title))
|
||||
ptitle := title
|
||||
if title == "" {
|
||||
ptitle = "Options"
|
||||
}
|
||||
fmt.Fprintln(&output, formatter.Title(ptitle)+":")
|
||||
for _, opt := range gmap[title] {
|
||||
opt.FormatOption(&output, formatter, screen_width)
|
||||
fmt.Fprintln(&output)
|
||||
|
||||
@@ -1,265 +0,0 @@
|
||||
// License: GPLv3 Copyright: 2022, Kovid Goyal, <kovid at kovidgoyal.net>
|
||||
|
||||
package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
"golang.org/x/sys/unix"
|
||||
|
||||
"kitty"
|
||||
"kitty/tools/cli/markup"
|
||||
"kitty/tools/tty"
|
||||
)
|
||||
|
||||
var RootCmd *cobra.Command
|
||||
|
||||
func key_in_slice(vals []string, key string) bool {
|
||||
for _, q := range vals {
|
||||
if q == key {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type ChoicesVal struct {
|
||||
name, Choice string
|
||||
allowed []string
|
||||
}
|
||||
type choicesVal ChoicesVal
|
||||
|
||||
func (i *choicesVal) String() string { return ChoicesVal(*i).Choice }
|
||||
func (i *choicesVal) Type() string { return "string" }
|
||||
func (i *choicesVal) Set(s string) error {
|
||||
(*i).Choice = s
|
||||
return nil
|
||||
}
|
||||
func newChoicesVal(val ChoicesVal, p *ChoicesVal) *choicesVal {
|
||||
*p = val
|
||||
return (*choicesVal)(p)
|
||||
}
|
||||
|
||||
func add_choices(flags *pflag.FlagSet, p *ChoicesVal, choices []string, name string, short string, usage string) {
|
||||
usage = strings.TrimSpace(usage) + "\n" + "Choices: " + strings.Join(choices, ", ")
|
||||
value := ChoicesVal{Choice: choices[0], allowed: choices}
|
||||
flags.VarP(newChoicesVal(value, p), name, short, usage)
|
||||
}
|
||||
|
||||
func Choices(flags *pflag.FlagSet, name string, usage string, choices ...string) *ChoicesVal {
|
||||
p := new(ChoicesVal)
|
||||
add_choices(flags, p, choices, name, "", usage)
|
||||
return p
|
||||
}
|
||||
|
||||
func ChoicesP(flags *pflag.FlagSet, name string, short string, usage string, choices ...string) *ChoicesVal {
|
||||
p := new(ChoicesVal)
|
||||
add_choices(flags, p, choices, name, short, usage)
|
||||
return p
|
||||
}
|
||||
|
||||
var formatter *markup.Context
|
||||
|
||||
func full_command_name(cmd *cobra.Command) string {
|
||||
var parent_names []string
|
||||
cmd.VisitParents(func(p *cobra.Command) {
|
||||
parent_names = append([]string{p.Name()}, parent_names...)
|
||||
})
|
||||
parent_names = append(parent_names, cmd.Name())
|
||||
return strings.Join(parent_names, " ")
|
||||
}
|
||||
|
||||
func show_usage(cmd *cobra.Command, use_pager bool) error {
|
||||
screen_width := 80
|
||||
if formatter.EscapeCodesAllowed() {
|
||||
var sz *unix.Winsize
|
||||
var tty_size_err error
|
||||
for {
|
||||
sz, tty_size_err = unix.IoctlGetWinsize(int(os.Stdout.Fd()), unix.TIOCGWINSZ)
|
||||
if tty_size_err != unix.EINTR {
|
||||
break
|
||||
}
|
||||
}
|
||||
if tty_size_err == nil && sz.Col < 80 {
|
||||
screen_width = int(sz.Col)
|
||||
}
|
||||
}
|
||||
var output strings.Builder
|
||||
use := cmd.Use
|
||||
idx := strings.Index(use, " ")
|
||||
if idx > -1 {
|
||||
use = use[idx+1:]
|
||||
} else {
|
||||
use = ""
|
||||
}
|
||||
fmt.Fprintln(&output, formatter.Title("Usage")+":", formatter.Exe(full_command_name(cmd)), use)
|
||||
fmt.Fprintln(&output)
|
||||
if len(cmd.Long) > 0 {
|
||||
format_with_indent(&output, cmd.Long, "", screen_width)
|
||||
} else if len(cmd.Short) > 0 {
|
||||
format_with_indent(&output, cmd.Short, "", screen_width)
|
||||
}
|
||||
if cmd.HasAvailableSubCommands() {
|
||||
fmt.Fprintln(&output)
|
||||
fmt.Fprintln(&output, formatter.Title("Commands")+":")
|
||||
for _, child := range cmd.Commands() {
|
||||
if child.Hidden {
|
||||
continue
|
||||
}
|
||||
fmt.Fprintln(&output, " ", formatter.Opt(child.Name()))
|
||||
format_with_indent(&output, child.Short, " ", screen_width)
|
||||
}
|
||||
fmt.Fprintln(&output)
|
||||
format_with_indent(&output, "Get help for an individual command by running:", "", screen_width)
|
||||
fmt.Fprintln(&output, " ", full_command_name(cmd), formatter.Italic("command"), "-h")
|
||||
}
|
||||
if cmd.HasAvailableFlags() {
|
||||
options_title := cmd.Annotations["options_title"]
|
||||
if len(options_title) == 0 {
|
||||
options_title = "Options"
|
||||
}
|
||||
fmt.Fprintln(&output)
|
||||
fmt.Fprintln(&output, formatter.Title(options_title)+":")
|
||||
flag_set := cmd.LocalFlags()
|
||||
flag_set.VisitAll(func(flag *pflag.Flag) {
|
||||
fmt.Fprint(&output, formatter.Opt(" --"+flag.Name))
|
||||
if flag.Shorthand != "" {
|
||||
fmt.Fprint(&output, ", ", formatter.Opt("-"+flag.Shorthand))
|
||||
}
|
||||
defval := ""
|
||||
switch flag.Value.Type() {
|
||||
default:
|
||||
if flag.DefValue != "" {
|
||||
defval = fmt.Sprintf("[=%s]", formatter.Italic(flag.DefValue))
|
||||
}
|
||||
case "stringArray":
|
||||
if flag.DefValue != "[]" {
|
||||
defval = fmt.Sprintf("[=%s]", formatter.Italic(flag.DefValue))
|
||||
}
|
||||
case "bool":
|
||||
case "count":
|
||||
}
|
||||
if defval != "" {
|
||||
fmt.Fprint(&output, " ", defval)
|
||||
}
|
||||
fmt.Fprintln(&output)
|
||||
msg := flag.Usage
|
||||
switch flag.Name {
|
||||
case "help":
|
||||
msg = "Print this help message"
|
||||
case "version":
|
||||
msg = "Print the version of " + RootCmd.Name() + ": " + formatter.Italic(RootCmd.Version)
|
||||
}
|
||||
format_with_indent(&output, msg, " ", screen_width)
|
||||
fmt.Fprintln(&output)
|
||||
})
|
||||
}
|
||||
if cmd.Annotations["usage-suffix"] != "" {
|
||||
fmt.Fprintln(&output, cmd.Annotations["usage-suffix"])
|
||||
} else {
|
||||
fmt.Fprintln(&output, formatter.Italic(RootCmd.Name()), formatter.Opt(kitty.VersionString), "created by", formatter.Title("Kovid Goyal"))
|
||||
}
|
||||
output_text := output.String()
|
||||
// fmt.Printf("%#v\n", output_text)
|
||||
if use_pager && formatter.EscapeCodesAllowed() && cmd.Annotations["allow-pager"] != "no" {
|
||||
pager := exec.Command(kitty.DefaultPager[0], kitty.DefaultPager[1:]...)
|
||||
pager.Stdin = strings.NewReader(output_text)
|
||||
pager.Stdout = os.Stdout
|
||||
pager.Stderr = os.Stderr
|
||||
pager.Run()
|
||||
} else {
|
||||
cmd.OutOrStdout().Write([]byte(output_text))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func FlagNormalizer(name string) string {
|
||||
return strings.ReplaceAll(name, "_", "-")
|
||||
}
|
||||
|
||||
func DisallowArgs(cmd *cobra.Command, args []string) error {
|
||||
if cmd.HasSubCommands() {
|
||||
if len(args) == 0 {
|
||||
return fmt.Errorf("No sub-command specified. Use %s -h to get a list of available sub-commands", full_command_name(cmd))
|
||||
}
|
||||
cmd.SuggestionsMinimumDistance = 2
|
||||
suggestions := cmd.SuggestionsFor(args[0])
|
||||
es := "Not a valid subcommand: " + args[0]
|
||||
trailer := fmt.Sprintf("Use %s to get a list of available sub-commands", formatter.Bold(full_command_name(cmd)+" -h"))
|
||||
if len(suggestions) > 0 {
|
||||
es += "\nDid you mean?\n"
|
||||
for _, s := range suggestions {
|
||||
es += fmt.Sprintf("\t%s\n", formatter.Italic(s))
|
||||
}
|
||||
es += trailer
|
||||
} else {
|
||||
es += ". " + trailer
|
||||
}
|
||||
return fmt.Errorf("%s", es)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func CreateCommand(cmd *cobra.Command) *cobra.Command {
|
||||
cmd.Annotations = make(map[string]string)
|
||||
cmd.SilenceErrors = true
|
||||
cmd.SilenceUsage = true
|
||||
cmd.PersistentFlags().SortFlags = false
|
||||
cmd.Flags().SortFlags = false
|
||||
cmd.Flags().SetNormalizeFunc(func(fs *pflag.FlagSet, name string) pflag.NormalizedName {
|
||||
return pflag.NormalizedName(FlagNormalizer(name))
|
||||
})
|
||||
cmd.PersistentFlags().SetNormalizeFunc(cmd.Flags().GetNormalizeFunc())
|
||||
if !cmd.Runnable() {
|
||||
cmd.Args = DisallowArgs
|
||||
cmd.RunE = func(cmd *cobra.Command, args []string) error {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
|
||||
func show_help(cmd *cobra.Command, args []string) {
|
||||
show_usage(cmd, true)
|
||||
}
|
||||
|
||||
func PrintError(err error) {
|
||||
fmt.Println(formatter.Err("Error")+":", err)
|
||||
}
|
||||
|
||||
func Init(root *cobra.Command) {
|
||||
vs := kitty.VersionString
|
||||
if kitty.VCSRevision != "" {
|
||||
vs = vs + " (" + kitty.VCSRevision + ")"
|
||||
}
|
||||
formatter = markup.New(tty.IsTerminal(os.Stdout.Fd()))
|
||||
RootCmd = root
|
||||
root.Version = vs
|
||||
root.SetUsageFunc(func(cmd *cobra.Command) error { return show_usage(cmd, false) })
|
||||
root.SetHelpFunc(show_help)
|
||||
root.SetHelpCommand(&cobra.Command{Hidden: true})
|
||||
root.CompletionOptions.DisableDefaultCmd = true
|
||||
}
|
||||
|
||||
func Execute(root *cobra.Command) error {
|
||||
return root.Execute()
|
||||
}
|
||||
|
||||
type FlagValGetter struct {
|
||||
Flags *pflag.FlagSet
|
||||
Err error
|
||||
}
|
||||
|
||||
func (self *FlagValGetter) String(name string) string {
|
||||
if self.Err != nil {
|
||||
return ""
|
||||
}
|
||||
ans, err := self.Flags.GetString(name)
|
||||
self.Err = err
|
||||
return ans
|
||||
}
|
||||
@@ -238,11 +238,11 @@ type OptionGroup struct {
|
||||
}
|
||||
|
||||
func (self *OptionGroup) Clone(parent *Command) *OptionGroup {
|
||||
ans := OptionGroup{Title: self.Title, Options: make([]*Option, 0, len(self.Options))}
|
||||
ans := OptionGroup{Title: self.Title, Options: make([]*Option, len(self.Options))}
|
||||
for i, o := range self.Options {
|
||||
c := *o
|
||||
c.Parent = parent
|
||||
self.Options[i] = &c
|
||||
ans.Options[i] = &c
|
||||
}
|
||||
return &ans
|
||||
}
|
||||
@@ -302,8 +302,8 @@ func (self *Command) Clone(parent *Command) *Command {
|
||||
ans := *self
|
||||
ans.Args = make([]string, 0, 8)
|
||||
ans.Parent = parent
|
||||
ans.SubCommandGroups = make([]*CommandGroup, 0, len(self.SubCommandGroups))
|
||||
ans.OptionGroups = make([]*OptionGroup, 0, len(self.OptionGroups))
|
||||
ans.SubCommandGroups = make([]*CommandGroup, len(self.SubCommandGroups))
|
||||
ans.OptionGroups = make([]*OptionGroup, len(self.OptionGroups))
|
||||
|
||||
for i, o := range self.OptionGroups {
|
||||
ans.OptionGroups[i] = o.Clone(&ans)
|
||||
@@ -314,14 +314,11 @@ func (self *Command) Clone(parent *Command) *Command {
|
||||
return &ans
|
||||
}
|
||||
|
||||
func (self *Command) AddClone(group string, src *Command) (*Command, error) {
|
||||
func (self *Command) AddClone(group string, src *Command) *Command {
|
||||
c := src.Clone(self)
|
||||
g := self.AddSubCommandGroup(group)
|
||||
if g.FindSubCommand(c.Name) != nil {
|
||||
return nil, fmt.Errorf("A sub command with the name: %s already exists in %s", c.Name, self.Name)
|
||||
}
|
||||
g.SubCommands = append(g.SubCommands, c)
|
||||
return c, nil
|
||||
return c
|
||||
}
|
||||
|
||||
func NewRootCommand() *Command {
|
||||
@@ -605,6 +602,19 @@ type Context struct {
|
||||
SeenCommands []*Command
|
||||
}
|
||||
|
||||
func GetOptionValue[T any](self *Command, name string) (ans T, err error) {
|
||||
opt := self.option_map[name]
|
||||
if opt == nil {
|
||||
err = fmt.Errorf("No option with the name: %s", name)
|
||||
return
|
||||
}
|
||||
ans, ok := opt.parsed_value().(T)
|
||||
if !ok {
|
||||
err = fmt.Errorf("The option %s is not of the correct type", name)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (self *Command) GetOptionValues(pointer_to_options_struct any) error {
|
||||
val := reflect.ValueOf(pointer_to_options_struct).Elem()
|
||||
if val.Kind() != reflect.Struct {
|
||||
@@ -689,7 +699,7 @@ func (self *Command) Exec(args ...string) {
|
||||
} else if cmd.Run != nil {
|
||||
exit_code, err = cmd.Run(cmd, cmd.Args)
|
||||
if err != nil {
|
||||
PrintError(err)
|
||||
ShowError(err)
|
||||
if exit_code == 0 {
|
||||
exit_code = 1
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user