2022-08-14 16:06:03 +03:00
|
|
|
package cli
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2022-08-15 11:15:05 +03:00
|
|
|
"io"
|
2022-08-14 16:06:03 +03:00
|
|
|
"os"
|
2022-08-15 11:15:05 +03:00
|
|
|
"os/exec"
|
2022-08-15 07:14:36 +03:00
|
|
|
"path/filepath"
|
2022-08-14 20:56:56 +03:00
|
|
|
"regexp"
|
2022-08-14 16:06:03 +03:00
|
|
|
"strings"
|
|
|
|
"unicode"
|
|
|
|
|
|
|
|
"github.com/fatih/color"
|
2022-08-15 11:15:05 +03:00
|
|
|
"github.com/mattn/go-isatty"
|
2022-08-14 16:06:03 +03:00
|
|
|
runewidth "github.com/mattn/go-runewidth"
|
|
|
|
"github.com/spf13/cobra"
|
|
|
|
"github.com/spf13/pflag"
|
2022-08-15 11:15:05 +03:00
|
|
|
"golang.org/x/sys/unix"
|
2022-08-14 16:06:03 +03:00
|
|
|
|
|
|
|
"kitty"
|
2022-08-15 07:14:36 +03:00
|
|
|
"kitty/tools/utils"
|
2022-08-14 16:06:03 +03:00
|
|
|
)
|
|
|
|
|
2022-08-14 20:56:56 +03:00
|
|
|
var RootCmd *cobra.Command
|
|
|
|
|
2022-08-15 11:15:05 +03:00
|
|
|
func GetTTYSize() (*unix.Winsize, error) {
|
2022-08-15 12:32:58 +03:00
|
|
|
if stdout_is_terminal {
|
2022-08-15 11:15:05 +03:00
|
|
|
return unix.IoctlGetWinsize(int(os.Stdout.Fd()), unix.TIOCGWINSZ)
|
2022-08-14 16:06:03 +03:00
|
|
|
}
|
2022-08-15 11:15:05 +03:00
|
|
|
return nil, fmt.Errorf("STDOUT is not a TTY")
|
2022-08-14 16:06:03 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func key_in_slice(vals []string, key string) bool {
|
|
|
|
for _, q := range vals {
|
|
|
|
if q == key {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2022-08-17 10:05:14 +03:00
|
|
|
type ChoicesVal struct {
|
|
|
|
name, Choice string
|
|
|
|
allowed []string
|
|
|
|
}
|
|
|
|
type choicesVal ChoicesVal
|
|
|
|
|
|
|
|
func (i *choicesVal) String() string { return ChoicesVal(*i).Choice }
|
2022-08-17 13:08:24 +03:00
|
|
|
func (i *choicesVal) Type() string { return "string" }
|
2022-08-17 10:05:14 +03:00
|
|
|
func (i *choicesVal) Set(s string) error {
|
|
|
|
(*i).Choice = s
|
2022-08-14 16:06:03 +03:00
|
|
|
return nil
|
|
|
|
}
|
2022-08-17 10:05:14 +03:00
|
|
|
func newChoicesVal(val ChoicesVal, p *ChoicesVal) *choicesVal {
|
|
|
|
*p = val
|
|
|
|
return (*choicesVal)(p)
|
|
|
|
}
|
|
|
|
|
2022-08-17 13:08:24 +03:00
|
|
|
func add_choices(flags *pflag.FlagSet, p *ChoicesVal, choices []string, name string, short string, usage string) {
|
2022-08-17 10:05:14 +03:00
|
|
|
value := ChoicesVal{Choice: choices[0], allowed: choices}
|
2022-08-17 13:08:24 +03:00
|
|
|
flags.VarP(newChoicesVal(value, p), name, short, usage)
|
2022-08-17 10:05:14 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func Choices(flags *pflag.FlagSet, name string, usage string, choices ...string) *ChoicesVal {
|
|
|
|
p := new(ChoicesVal)
|
2022-08-17 13:08:24 +03:00
|
|
|
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)
|
2022-08-17 10:05:14 +03:00
|
|
|
return p
|
|
|
|
}
|
2022-08-14 16:06:03 +03:00
|
|
|
|
2022-08-15 11:15:05 +03:00
|
|
|
var stdout_is_terminal = false
|
2022-08-14 16:06:03 +03:00
|
|
|
var title_fmt = color.New(color.FgBlue, color.Bold).SprintFunc()
|
|
|
|
var exe_fmt = color.New(color.FgYellow, color.Bold).SprintFunc()
|
|
|
|
var opt_fmt = color.New(color.FgGreen).SprintFunc()
|
|
|
|
var italic_fmt = color.New(color.Italic).SprintFunc()
|
2022-08-15 11:28:16 +03:00
|
|
|
var err_fmt = color.New(color.FgHiRed).SprintFunc()
|
2022-08-14 20:56:56 +03:00
|
|
|
var bold_fmt = color.New(color.Bold).SprintFunc()
|
|
|
|
var code_fmt = color.New(color.FgCyan).SprintFunc()
|
|
|
|
var cyan_fmt = color.New(color.FgCyan).SprintFunc()
|
|
|
|
var yellow_fmt = color.New(color.FgYellow).SprintFunc()
|
|
|
|
var blue_fmt = color.New(color.FgBlue).SprintFunc()
|
|
|
|
var green_fmt = color.New(color.FgGreen).SprintFunc()
|
2022-08-14 16:06:03 +03:00
|
|
|
|
2022-08-15 11:15:05 +03:00
|
|
|
func format_line_with_indent(output io.Writer, text string, indent string, screen_width int) {
|
2022-08-17 11:28:01 +03:00
|
|
|
if strings.TrimSpace(text) == "" {
|
|
|
|
fmt.Fprintln(output, indent)
|
|
|
|
return
|
|
|
|
}
|
2022-08-14 16:06:03 +03:00
|
|
|
x := len(indent)
|
2022-08-15 11:15:05 +03:00
|
|
|
fmt.Fprint(output, indent)
|
|
|
|
in_escape := 0
|
2022-08-14 20:56:56 +03:00
|
|
|
var current_word strings.Builder
|
2022-08-16 06:52:12 +03:00
|
|
|
var escapes strings.Builder
|
2022-08-14 16:06:03 +03:00
|
|
|
|
|
|
|
print_word := func(r rune) {
|
2022-08-14 20:56:56 +03:00
|
|
|
w := runewidth.StringWidth(current_word.String())
|
2022-08-14 16:06:03 +03:00
|
|
|
if x+w > screen_width {
|
2022-08-15 11:15:05 +03:00
|
|
|
fmt.Fprintln(output)
|
|
|
|
fmt.Fprint(output, indent)
|
2022-08-14 16:06:03 +03:00
|
|
|
x = len(indent)
|
2022-08-14 20:56:56 +03:00
|
|
|
s := strings.TrimSpace(current_word.String())
|
|
|
|
current_word.Reset()
|
|
|
|
current_word.WriteString(s)
|
|
|
|
}
|
2022-08-16 06:52:12 +03:00
|
|
|
if escapes.Len() > 0 {
|
|
|
|
output.Write([]byte(escapes.String()))
|
|
|
|
escapes.Reset()
|
|
|
|
}
|
|
|
|
if current_word.Len() > 0 {
|
|
|
|
output.Write([]byte(current_word.String()))
|
|
|
|
current_word.Reset()
|
|
|
|
}
|
2022-08-14 20:56:56 +03:00
|
|
|
if r > 0 {
|
|
|
|
current_word.WriteRune(r)
|
2022-08-14 16:06:03 +03:00
|
|
|
}
|
|
|
|
x += w
|
|
|
|
}
|
|
|
|
|
2022-08-15 11:15:05 +03:00
|
|
|
for i, r := range text {
|
|
|
|
if in_escape > 0 {
|
2022-08-15 12:32:58 +03:00
|
|
|
if in_escape == 1 && (r == ']' || r == '[') {
|
2022-08-15 11:15:05 +03:00
|
|
|
in_escape = 2
|
2022-08-15 12:32:58 +03:00
|
|
|
if r == ']' {
|
|
|
|
in_escape = 3
|
|
|
|
}
|
2022-08-14 16:06:03 +03:00
|
|
|
}
|
2022-08-15 11:15:05 +03:00
|
|
|
if (in_escape == 2 && r == 'm') || (in_escape == 3 && r == '\\' && text[i-1] == 0x1b) {
|
|
|
|
in_escape = 0
|
|
|
|
}
|
2022-08-16 06:52:12 +03:00
|
|
|
escapes.WriteRune(r)
|
2022-08-14 16:06:03 +03:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
if r == 0x1b {
|
2022-08-15 11:15:05 +03:00
|
|
|
in_escape = 1
|
2022-08-14 20:56:56 +03:00
|
|
|
if current_word.Len() != 0 {
|
|
|
|
print_word(0)
|
|
|
|
}
|
2022-08-16 06:52:12 +03:00
|
|
|
escapes.WriteRune(r)
|
2022-08-14 16:06:03 +03:00
|
|
|
continue
|
|
|
|
}
|
2022-08-14 20:56:56 +03:00
|
|
|
if current_word.Len() != 0 && r != 0xa0 && unicode.IsSpace(r) {
|
2022-08-14 16:06:03 +03:00
|
|
|
print_word(r)
|
|
|
|
} else {
|
2022-08-14 20:56:56 +03:00
|
|
|
current_word.WriteRune(r)
|
2022-08-14 16:06:03 +03:00
|
|
|
}
|
|
|
|
}
|
2022-08-16 06:52:12 +03:00
|
|
|
if current_word.Len() != 0 || escapes.Len() != 0 {
|
2022-08-14 20:56:56 +03:00
|
|
|
print_word(0)
|
2022-08-14 16:06:03 +03:00
|
|
|
}
|
|
|
|
if len(text) > 0 {
|
2022-08-15 11:15:05 +03:00
|
|
|
fmt.Fprintln(output)
|
2022-08-14 16:06:03 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-14 20:56:56 +03:00
|
|
|
func ReplaceAllStringSubmatchFunc(re *regexp.Regexp, str string, repl func([]string) string) string {
|
|
|
|
result := ""
|
|
|
|
lastIndex := 0
|
|
|
|
|
|
|
|
for _, v := range re.FindAllSubmatchIndex([]byte(str), -1) {
|
|
|
|
groups := []string{}
|
|
|
|
for i := 0; i < len(v); i += 2 {
|
|
|
|
if v[i] == -1 || v[i+1] == -1 {
|
|
|
|
groups = append(groups, "")
|
|
|
|
} else {
|
|
|
|
groups = append(groups, str[v[i]:v[i+1]])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
result += str[lastIndex:v[0]] + repl(groups)
|
|
|
|
lastIndex = v[1]
|
|
|
|
}
|
|
|
|
|
|
|
|
return result + str[lastIndex:]
|
|
|
|
}
|
|
|
|
|
|
|
|
func website_url(doc string) string {
|
|
|
|
if doc != "" {
|
|
|
|
doc = strings.TrimSuffix(doc, "/")
|
|
|
|
if doc != "" {
|
|
|
|
doc += "/"
|
|
|
|
}
|
|
|
|
}
|
2022-08-16 18:44:40 +03:00
|
|
|
return kitty.WebsiteBaseURL + doc
|
2022-08-14 20:56:56 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
var prettify_pat = regexp.MustCompile(":([a-z]+):`([^`]+)`")
|
|
|
|
var ref_pat = regexp.MustCompile(`\s*<\S+?>`)
|
|
|
|
|
2022-08-15 07:14:36 +03:00
|
|
|
func hyperlink_for_path(path string, text string) string {
|
2022-08-15 11:15:05 +03:00
|
|
|
if !stdout_is_terminal {
|
2022-08-15 07:14:36 +03:00
|
|
|
return text
|
|
|
|
}
|
|
|
|
path = strings.ReplaceAll(utils.Abspath(path), string(os.PathSeparator), "/")
|
|
|
|
fi, err := os.Stat(path)
|
|
|
|
if err == nil && fi.IsDir() {
|
|
|
|
path = strings.TrimSuffix(path, "/") + "/"
|
|
|
|
}
|
|
|
|
host, err := os.Hostname()
|
|
|
|
if err != nil {
|
|
|
|
host = ""
|
|
|
|
}
|
|
|
|
return "\x1b]8;;file://" + host + path + "\x1b\\" + text + "\x1b]8;;\x1b\\"
|
|
|
|
}
|
|
|
|
|
2022-08-14 20:56:56 +03:00
|
|
|
func prettify(text string) string {
|
|
|
|
return ReplaceAllStringSubmatchFunc(prettify_pat, text, func(groups []string) string {
|
|
|
|
val := groups[2]
|
|
|
|
switch groups[1] {
|
2022-08-15 07:14:36 +03:00
|
|
|
case "file":
|
2022-08-15 11:15:05 +03:00
|
|
|
if val == "kitty.conf" && stdout_is_terminal {
|
2022-08-15 07:14:36 +03:00
|
|
|
path := filepath.Join(utils.ConfigDir(), val)
|
|
|
|
val = hyperlink_for_path(path, val)
|
|
|
|
}
|
|
|
|
return italic_fmt(val)
|
|
|
|
case "env", "envvar":
|
2022-08-14 20:56:56 +03:00
|
|
|
return italic_fmt(val)
|
|
|
|
case "doc":
|
|
|
|
return website_url(val)
|
|
|
|
case "ref":
|
|
|
|
return ref_pat.ReplaceAllString(val, ``)
|
|
|
|
case "code":
|
|
|
|
return code_fmt(val)
|
|
|
|
case "option":
|
|
|
|
idx := strings.LastIndex(val, "--")
|
|
|
|
if idx < 0 {
|
|
|
|
idx = strings.Index(val, "-")
|
|
|
|
}
|
|
|
|
if idx > -1 {
|
|
|
|
val = val[idx:]
|
|
|
|
}
|
|
|
|
return bold_fmt(val)
|
2022-08-16 13:40:36 +03:00
|
|
|
case "opt":
|
|
|
|
return bold_fmt(val)
|
2022-08-14 20:56:56 +03:00
|
|
|
case "yellow":
|
|
|
|
return yellow_fmt(val)
|
|
|
|
case "blue":
|
|
|
|
return blue_fmt(val)
|
|
|
|
case "green":
|
|
|
|
return green_fmt(val)
|
|
|
|
case "cyan":
|
|
|
|
return cyan_fmt(val)
|
|
|
|
case "emph":
|
|
|
|
return italic_fmt(val)
|
|
|
|
default:
|
|
|
|
return val
|
|
|
|
}
|
|
|
|
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2022-08-15 11:15:05 +03:00
|
|
|
func format_with_indent(output io.Writer, text string, indent string, screen_width int) {
|
2022-08-14 20:56:56 +03:00
|
|
|
for _, line := range strings.Split(prettify(text), "\n") {
|
2022-08-15 11:15:05 +03:00
|
|
|
format_line_with_indent(output, line, indent, screen_width)
|
2022-08-14 20:56:56 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-15 11:28:16 +03:00
|
|
|
func full_command_name(cmd *cobra.Command) string {
|
|
|
|
var parent_names []string
|
|
|
|
cmd.VisitParents(func(p *cobra.Command) {
|
2022-08-16 17:49:39 +03:00
|
|
|
parent_names = append([]string{p.Name()}, parent_names...)
|
2022-08-15 11:28:16 +03:00
|
|
|
})
|
|
|
|
parent_names = append(parent_names, cmd.Name())
|
|
|
|
return strings.Join(parent_names, " ")
|
|
|
|
}
|
|
|
|
|
2022-08-17 10:38:58 +03:00
|
|
|
func show_usage(cmd *cobra.Command, use_pager bool) error {
|
2022-08-14 16:06:03 +03:00
|
|
|
ws, tty_size_err := GetTTYSize()
|
2022-08-15 11:15:05 +03:00
|
|
|
var output strings.Builder
|
2022-08-14 16:06:03 +03:00
|
|
|
screen_width := 80
|
2022-08-15 11:15:05 +03:00
|
|
|
if tty_size_err == nil && ws.Col < 80 {
|
|
|
|
screen_width = int(ws.Col)
|
2022-08-14 16:06:03 +03:00
|
|
|
}
|
2022-08-15 05:46:00 +03:00
|
|
|
use := cmd.Use
|
|
|
|
idx := strings.Index(use, " ")
|
|
|
|
if idx > -1 {
|
2022-08-15 07:14:36 +03:00
|
|
|
use = use[idx+1:]
|
2022-08-16 19:10:40 +03:00
|
|
|
} else {
|
|
|
|
use = ""
|
2022-08-15 05:46:00 +03:00
|
|
|
}
|
2022-08-15 11:28:16 +03:00
|
|
|
fmt.Fprintln(&output, title_fmt("Usage")+":", exe_fmt(full_command_name(cmd)), use)
|
2022-08-15 11:15:05 +03:00
|
|
|
fmt.Fprintln(&output)
|
2022-08-14 16:06:03 +03:00
|
|
|
if len(cmd.Long) > 0 {
|
2022-08-15 11:15:05 +03:00
|
|
|
format_with_indent(&output, cmd.Long, "", screen_width)
|
2022-08-14 16:06:03 +03:00
|
|
|
} else if len(cmd.Short) > 0 {
|
2022-08-15 11:15:05 +03:00
|
|
|
format_with_indent(&output, cmd.Short, "", screen_width)
|
2022-08-14 16:06:03 +03:00
|
|
|
}
|
|
|
|
if cmd.HasAvailableSubCommands() {
|
2022-08-15 11:15:05 +03:00
|
|
|
fmt.Fprintln(&output)
|
|
|
|
fmt.Fprintln(&output, title_fmt("Commands")+":")
|
2022-08-14 16:06:03 +03:00
|
|
|
for _, child := range cmd.Commands() {
|
2022-08-16 19:10:40 +03:00
|
|
|
if child.Hidden {
|
|
|
|
continue
|
|
|
|
}
|
2022-08-15 11:15:05 +03:00
|
|
|
fmt.Fprintln(&output, " ", opt_fmt(child.Name()))
|
|
|
|
format_with_indent(&output, child.Short, " ", screen_width)
|
2022-08-14 16:06:03 +03:00
|
|
|
}
|
2022-08-15 11:15:05 +03:00
|
|
|
fmt.Fprintln(&output)
|
|
|
|
format_with_indent(&output, "Get help for an individual command by running:", "", screen_width)
|
2022-08-16 17:49:39 +03:00
|
|
|
fmt.Fprintln(&output, " ", full_command_name(cmd), italic_fmt("command"), "-h")
|
2022-08-14 16:06:03 +03:00
|
|
|
}
|
|
|
|
if cmd.HasAvailableFlags() {
|
|
|
|
options_title := cmd.Annotations["options_title"]
|
|
|
|
if len(options_title) == 0 {
|
|
|
|
options_title = "Options"
|
|
|
|
}
|
2022-08-15 11:15:05 +03:00
|
|
|
fmt.Fprintln(&output)
|
|
|
|
fmt.Fprintln(&output, title_fmt(options_title)+":")
|
2022-08-14 16:06:03 +03:00
|
|
|
flag_set := cmd.LocalFlags()
|
|
|
|
flag_set.VisitAll(func(flag *pflag.Flag) {
|
2022-08-15 11:15:05 +03:00
|
|
|
fmt.Fprint(&output, opt_fmt(" --"+flag.Name))
|
2022-08-14 16:06:03 +03:00
|
|
|
if flag.Shorthand != "" {
|
2022-08-15 11:15:05 +03:00
|
|
|
fmt.Fprint(&output, ", ", opt_fmt("-"+flag.Shorthand))
|
2022-08-14 16:06:03 +03:00
|
|
|
}
|
|
|
|
defval := ""
|
|
|
|
switch flag.Value.Type() {
|
|
|
|
default:
|
2022-08-15 07:14:36 +03:00
|
|
|
if flag.DefValue != "" {
|
2022-08-15 05:46:00 +03:00
|
|
|
defval = fmt.Sprintf("[=%s]", italic_fmt(flag.DefValue))
|
|
|
|
}
|
2022-08-14 16:06:03 +03:00
|
|
|
case "bool":
|
|
|
|
case "count":
|
|
|
|
}
|
|
|
|
if defval != "" {
|
2022-08-15 11:15:05 +03:00
|
|
|
fmt.Fprint(&output, " ", defval)
|
2022-08-14 16:06:03 +03:00
|
|
|
}
|
2022-08-15 11:15:05 +03:00
|
|
|
fmt.Fprintln(&output)
|
2022-08-14 20:56:56 +03:00
|
|
|
msg := flag.Usage
|
|
|
|
switch flag.Name {
|
|
|
|
case "help":
|
|
|
|
msg = "Print this help message"
|
|
|
|
case "version":
|
2022-08-15 05:46:00 +03:00
|
|
|
msg = "Print the version of " + RootCmd.Name() + ": " + italic_fmt(RootCmd.Version)
|
2022-08-14 16:06:03 +03:00
|
|
|
}
|
2022-08-15 11:15:05 +03:00
|
|
|
format_with_indent(&output, msg, " ", screen_width)
|
2022-08-14 16:06:03 +03:00
|
|
|
if cmd.Annotations["choices-"+flag.Name] != "" {
|
2022-08-15 11:15:05 +03:00
|
|
|
fmt.Fprintln(&output, " Choices:", strings.Join(strings.Split(cmd.Annotations["choices-"+flag.Name], "\000"), ", "))
|
2022-08-14 16:06:03 +03:00
|
|
|
}
|
2022-08-15 11:15:05 +03:00
|
|
|
fmt.Fprintln(&output)
|
2022-08-14 16:06:03 +03:00
|
|
|
})
|
|
|
|
}
|
2022-08-15 11:28:16 +03:00
|
|
|
if cmd.Annotations["usage-suffix"] != "" {
|
|
|
|
fmt.Fprintln(&output, cmd.Annotations["usage-suffix"])
|
|
|
|
} else {
|
2022-08-16 18:56:55 +03:00
|
|
|
fmt.Fprintln(&output, italic_fmt(RootCmd.Name()), opt_fmt(kitty.VersionString), "created by", title_fmt("Kovid Goyal"))
|
2022-08-15 11:28:16 +03:00
|
|
|
}
|
2022-08-15 12:32:58 +03:00
|
|
|
output_text := output.String()
|
2022-08-16 06:52:12 +03:00
|
|
|
// fmt.Printf("%#v\n", output_text)
|
2022-08-17 10:38:58 +03:00
|
|
|
if use_pager && stdout_is_terminal && cmd.Annotations["allow-pager"] != "no" {
|
2022-08-15 12:32:58 +03:00
|
|
|
pager := exec.Command(kitty.DefaultPager[0], kitty.DefaultPager[1:]...)
|
2022-08-15 11:15:05 +03:00
|
|
|
pager.Stdin = strings.NewReader(output_text)
|
|
|
|
pager.Stdout = os.Stdout
|
|
|
|
pager.Stderr = os.Stderr
|
|
|
|
pager.Run()
|
2022-08-14 16:06:03 +03:00
|
|
|
} else {
|
2022-08-16 15:32:31 +03:00
|
|
|
cmd.OutOrStdout().Write([]byte(output_text))
|
2022-08-14 16:06:03 +03:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-08-15 05:46:00 +03:00
|
|
|
func CreateCommand(cmd *cobra.Command) *cobra.Command {
|
2022-08-14 16:06:03 +03:00
|
|
|
cmd.Annotations = make(map[string]string)
|
2022-08-16 15:32:31 +03:00
|
|
|
if cmd.Run == nil && cmd.RunE == nil {
|
|
|
|
cmd.RunE = func(cmd *cobra.Command, args []string) error {
|
|
|
|
if len(cmd.Commands()) > 0 {
|
2022-08-16 19:10:40 +03:00
|
|
|
if len(args) == 0 {
|
2022-08-17 10:38:58 +03:00
|
|
|
return fmt.Errorf("No sub-command specified. Use %s -h to get a list of available sub-commands", full_command_name(cmd))
|
2022-08-16 19:10:40 +03:00
|
|
|
}
|
2022-08-17 10:05:14 +03:00
|
|
|
return fmt.Errorf("Not a valid subcommand: %s. Use %s -h to get a list of available sub-commands", args[0], full_command_name(cmd))
|
2022-08-16 15:32:31 +03:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
cmd.SilenceErrors = true
|
|
|
|
cmd.SilenceUsage = true
|
2022-08-16 13:40:36 +03:00
|
|
|
cmd.PersistentFlags().SortFlags = false
|
|
|
|
cmd.Flags().SortFlags = false
|
2022-08-14 16:06:03 +03:00
|
|
|
return cmd
|
|
|
|
}
|
|
|
|
|
2022-08-16 15:32:31 +03:00
|
|
|
func show_help(cmd *cobra.Command, args []string) {
|
2022-08-17 10:38:58 +03:00
|
|
|
show_usage(cmd, true)
|
2022-08-15 05:46:00 +03:00
|
|
|
}
|
|
|
|
|
2022-08-17 10:05:14 +03:00
|
|
|
func PrintError(err error) {
|
|
|
|
fmt.Println(err_fmt("Error")+":", err)
|
|
|
|
}
|
|
|
|
|
2022-08-14 16:06:03 +03:00
|
|
|
func Init(root *cobra.Command) {
|
2022-08-16 18:48:16 +03:00
|
|
|
vs := kitty.VersionString
|
|
|
|
if kitty.VCSRevision != "" {
|
|
|
|
vs = vs + " (" + kitty.VCSRevision + ")"
|
|
|
|
}
|
2022-08-15 11:15:05 +03:00
|
|
|
stdout_is_terminal = isatty.IsTerminal(os.Stdout.Fd())
|
2022-08-14 20:56:56 +03:00
|
|
|
RootCmd = root
|
2022-08-16 18:48:16 +03:00
|
|
|
root.Version = vs
|
2022-08-17 10:38:58 +03:00
|
|
|
root.SetUsageFunc(func(cmd *cobra.Command) error { return show_usage(cmd, false) })
|
2022-08-16 15:32:31 +03:00
|
|
|
root.SetHelpFunc(show_help)
|
2022-08-16 19:10:40 +03:00
|
|
|
root.SetHelpCommand(&cobra.Command{Hidden: true})
|
2022-08-17 08:25:46 +03:00
|
|
|
root.CompletionOptions.DisableDefaultCmd = true
|
2022-08-14 16:06:03 +03:00
|
|
|
}
|
2022-08-17 10:38:58 +03:00
|
|
|
|
|
|
|
func Execute(root *cobra.Command) error {
|
|
|
|
return root.Execute()
|
|
|
|
}
|