mirror of
https://github.com/XTLS/Xray-core.git
synced 2025-04-29 16:58:34 +00:00
v1.1.0
This commit is contained in:
parent
ed8d6d743c
commit
16544c18ab
627 changed files with 3247 additions and 2635 deletions
|
@ -22,13 +22,19 @@ type Command struct {
|
|||
Run func(cmd *Command, args []string)
|
||||
|
||||
// UsageLine is the one-line usage message.
|
||||
// The words between "go" and the first flag or argument in the line are taken to be the command name.
|
||||
// The words between the first word (the "executable name") and the first flag or argument in the line are taken to be the command name.
|
||||
//
|
||||
// UsageLine supports go template syntax. It's recommended to use "{{.Exec}}" instead of hardcoding name
|
||||
UsageLine string
|
||||
|
||||
// Short is the short description shown in the 'go help' output.
|
||||
//
|
||||
// Note: Short does not support go template syntax.
|
||||
Short string
|
||||
|
||||
// Long is the long message shown in the 'go help <this-command>' output.
|
||||
//
|
||||
// Long supports go template syntax. It's recommended to use "{{.Exec}}", "{{.LongName}}" instead of hardcoding strings
|
||||
Long string
|
||||
|
||||
// Flag is a set of flags specific to this command.
|
||||
|
@ -44,16 +50,18 @@ type Command struct {
|
|||
Commands []*Command
|
||||
}
|
||||
|
||||
// LongName returns the command's long name: all the words in the usage line between "go" and a flag or argument,
|
||||
// LongName returns the command's long name: all the words in the usage line between first word (e.g. "xray") and a flag or argument,
|
||||
func (c *Command) LongName() string {
|
||||
name := c.UsageLine
|
||||
if i := strings.Index(name, " ["); i >= 0 {
|
||||
name = name[:i]
|
||||
name = strings.TrimSpace(name[:i])
|
||||
}
|
||||
if name == CommandEnv.Exec {
|
||||
return ""
|
||||
if i := strings.Index(name, " "); i >= 0 {
|
||||
name = name[i+1:]
|
||||
} else {
|
||||
name = ""
|
||||
}
|
||||
return strings.TrimPrefix(name, CommandEnv.Exec+" ")
|
||||
return strings.TrimSpace(name)
|
||||
}
|
||||
|
||||
// Name returns the command's short name: the last word in the usage line before a flag or argument.
|
||||
|
@ -62,11 +70,12 @@ func (c *Command) Name() string {
|
|||
if i := strings.LastIndex(name, " "); i >= 0 {
|
||||
name = name[i+1:]
|
||||
}
|
||||
return name
|
||||
return strings.TrimSpace(name)
|
||||
}
|
||||
|
||||
// Usage prints usage of the Command
|
||||
func (c *Command) Usage() {
|
||||
buildCommandText(c)
|
||||
fmt.Fprintf(os.Stderr, "usage: %s\n", c.UsageLine)
|
||||
fmt.Fprintf(os.Stderr, "Run 'xray help %s' for details.\n", c.LongName())
|
||||
SetExitStatus(2)
|
||||
|
|
|
@ -7,7 +7,10 @@ import (
|
|||
|
||||
// CommandEnvHolder is a struct holds the environment info of commands
|
||||
type CommandEnvHolder struct {
|
||||
// Excutable name of current binary
|
||||
Exec string
|
||||
// commands column width of current command
|
||||
CommandsWidth int
|
||||
}
|
||||
|
||||
// CommandEnv holds the environment info of commands
|
||||
|
|
|
@ -14,7 +14,6 @@ import (
|
|||
|
||||
// Execute excute the commands
|
||||
func Execute() {
|
||||
buildCommandsText(RootCommand)
|
||||
flag.Parse()
|
||||
args := flag.Args()
|
||||
if len(args) < 1 {
|
||||
|
@ -61,6 +60,7 @@ BigCmdLoop:
|
|||
args = cmd.Flag.Args()
|
||||
}
|
||||
|
||||
buildCommandText(cmd)
|
||||
cmd.Run(cmd, args)
|
||||
Exit()
|
||||
return
|
||||
|
|
|
@ -41,6 +41,7 @@ Args:
|
|||
if len(cmd.Commands) > 0 {
|
||||
PrintUsage(os.Stdout, cmd)
|
||||
} else {
|
||||
buildCommandText(cmd)
|
||||
tmpl(os.Stdout, helpTemplate, makeTmplData(cmd))
|
||||
}
|
||||
}
|
||||
|
@ -49,11 +50,11 @@ var usageTemplate = `{{.Long | trim}}
|
|||
|
||||
Usage:
|
||||
|
||||
{{.Exec}} <command> [arguments]
|
||||
{{.UsageLine}} <command> [arguments]
|
||||
|
||||
The commands are:
|
||||
{{range .Commands}}{{if and (ne .Short "") (or (.Runnable) .Commands)}}
|
||||
{{.Name | printf "%-12s"}} {{.Short}}{{end}}{{end}}
|
||||
{{.Name | width $.CommandsWidth}} {{.Short}}{{end}}{{end}}
|
||||
|
||||
Use "{{.Exec}} help{{with .LongName}} {{.}}{{end}} <command>" for more information about a command.
|
||||
`
|
||||
|
@ -91,7 +92,7 @@ func (w *errWriter) Write(b []byte) (int, error) {
|
|||
// tmpl executes the given template text on data, writing the result to w.
|
||||
func tmpl(w io.Writer, text string, data interface{}) {
|
||||
t := template.New("top")
|
||||
t.Funcs(template.FuncMap{"trim": strings.TrimSpace, "capitalize": capitalize})
|
||||
t.Funcs(template.FuncMap{"trim": strings.TrimSpace, "capitalize": capitalize, "width": width})
|
||||
template.Must(t.Parse(text))
|
||||
ew := &errWriter{w: w}
|
||||
err := t.Execute(ew, data)
|
||||
|
@ -116,26 +117,28 @@ func capitalize(s string) string {
|
|||
return string(unicode.ToTitle(r)) + s[n:]
|
||||
}
|
||||
|
||||
func width(width int, value string) string {
|
||||
format := fmt.Sprintf("%%-%ds", width)
|
||||
return fmt.Sprintf(format, value)
|
||||
}
|
||||
|
||||
// PrintUsage prints usage of cmd to w
|
||||
func PrintUsage(w io.Writer, cmd *Command) {
|
||||
buildCommandText(cmd)
|
||||
bw := bufio.NewWriter(w)
|
||||
tmpl(bw, usageTemplate, makeTmplData(cmd))
|
||||
bw.Flush()
|
||||
}
|
||||
|
||||
// buildCommandsText build text of command and its children as template
|
||||
func buildCommandsText(cmd *Command) {
|
||||
buildCommandText(cmd)
|
||||
for _, cmd := range cmd.Commands {
|
||||
buildCommandsText(cmd)
|
||||
}
|
||||
}
|
||||
|
||||
// buildCommandText build command text as template
|
||||
func buildCommandText(cmd *Command) {
|
||||
cmd.UsageLine = buildText(cmd.UsageLine, makeTmplData(cmd))
|
||||
cmd.Short = buildText(cmd.Short, makeTmplData(cmd))
|
||||
cmd.Long = buildText(cmd.Long, makeTmplData(cmd))
|
||||
data := makeTmplData(cmd)
|
||||
cmd.UsageLine = buildText(cmd.UsageLine, data)
|
||||
// DO NOT SUPPORT ".Short":
|
||||
// - It's not necessary
|
||||
// - Or, we have to build text for all sub commands of current command, like "xray help api"
|
||||
// cmd.Short = buildText(cmd.Short, data)
|
||||
cmd.Long = buildText(cmd.Long, data)
|
||||
}
|
||||
|
||||
func buildText(text string, data interface{}) string {
|
||||
|
@ -150,6 +153,15 @@ type tmplData struct {
|
|||
}
|
||||
|
||||
func makeTmplData(cmd *Command) tmplData {
|
||||
// Minimum width of the command column
|
||||
width := 12
|
||||
for _, c := range cmd.Commands {
|
||||
l := len(c.Name())
|
||||
if width < l {
|
||||
width = l
|
||||
}
|
||||
}
|
||||
CommandEnv.CommandsWidth = width
|
||||
return tmplData{
|
||||
Command: cmd,
|
||||
CommandEnvHolder: &CommandEnv,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue