func NamedCommand(name string, cmd Function) Function {
	return &namedCommand{name: name, cmd: cmd}
}
NamedCommand constructs a command which carries the named passed as argument
and delegate execution to cmd.
package cli
import (
	"bytes"
	"context"
	"fmt"
	"io"
	"reflect"
	"sort"
	"strings"
	"text/tabwriter"
	"unicode/utf8"
)
func Command(fn interface{}) Function { return &CommandFunc{Func: fn} }
type CommandFunc struct {
	Help string
	Desc string
	Func interface{}
	function reflect.Value
	parser   parser
	options  structDecoder
	values   []decodeFunc
	variadic bool
	context  bool
	help     string
}
func (cmd *CommandFunc) configure() {
	if cmd.function.IsValid() {
		return  
	}
	t := reflect.TypeOf(cmd.Func)
	v := reflect.ValueOf(cmd.Func)
	if t.Kind() != reflect.Func {
		panic("cli.Command: expected a function as argument but got " + t.String())
	}
	ctxType := reflect.TypeOf((*context.Context)(nil)).Elem()
	cmd.function = v
	cmd.variadic = t.IsVariadic()
	if n := t.NumIn(); n == 0 {
		cmd.parser, cmd.options, cmd.help = makeStructDecoder(emptyType)
	} else {
		x := 0
		if f := t.In(x); f.Kind() == reflect.Interface && f.Implements(ctxType) {
			cmd.context = true
			x++
		}
		if x < n {
			if f := t.In(x); f.Kind() == reflect.Struct {
				cmd.parser, cmd.options, cmd.help = makeStructDecoder(f)
				x++
			} else {
				panic("cli.Command: expected a struct as first argument but got " + f.String())
			}
		}
		if cmd.variadic {
			n--
		}
		for i := x; i < n; i++ {
			p := t.In(i)
			if p.Kind() == reflect.Slice {
				cmd.values = append(cmd.values, makeSliceDecoder(p))
				break
			}
			cmd.values = append(cmd.values, makeValueDecoder(p))
		}
	}
	switch t.NumOut() {
	case 0:
	case 1:
		if r0 := t.Out(0); r0 != errorType {
			panic("cli.Command: expected a function returning (error) but got (" + r0.String() + ")")
		}
	case 2:
		if r0, r1 := t.Out(0), t.Out(1); r0 != intType || r1 != errorType {
			panic("cli.Command: expected a function returing (int, error) but got (" + r0.String() + ", " + r1.String() + ")")
		}
	default:
		panic("cli.Command: the function returns too many values")
	}
	if cmd.help == "" {
		cmd.help = cmd.Help
	}
}
func (cmd *CommandFunc) Call(ctx context.Context, args, env []string) (int, error) {
	cmd.configure()
	options, values, command, err := cmd.parser.parseCommandLine(args)
	if err != nil {
		return 1, err
	}
	if wantHelp(options) {
		return 0, &Help{Cmd: cmd}
	}
	for name, field := range cmd.options {
		if _, ok := options[name]; !ok && len(field.envvars) != 0 {
			for _, e := range field.envvars {
				if v, ok := lookupEnv(e, env); ok {
					options[name] = []string{v}
					break
				}
			}
		}
	}
	for name, field := range cmd.options {
		if _, ok := options[name]; !ok && field.defval != "" && field.defval != "-" {
			options[name] = []string{field.defval}
		}
	}
	for name, field := range cmd.options {
		if _, ok := options[name]; !ok && field.defval == "" && !field.boolean && !field.slice {
			return 1, &Usage{Cmd: cmd, Err: fmt.Errorf("missing required flag: %q", name)}
		}
	}
	var params []reflect.Value
	x := 0
	if cmd.context {
		params = append(params, reflect.ValueOf(ctx))
		x++
	} else if ctx != nil && ctx != context.TODO() {
		panic("to use context, all commands must accept a context.Context as their first argument")
	}
	if t := cmd.function.Type(); t.NumIn() > 0 {
		n := t.NumIn()
		if x < n {
			v := reflect.New(t.In(x)).Elem()
			if err := cmd.options.decode(v, options); err != nil {
				return 1, err
			}
			params = append(params, v)
			x++
		}
		if cmd.variadic {
			n--
		}
		for i := x; i < n; i++ {
			p := t.In(i)
			v := reflect.New(p).Elem()
			if p.Kind() == reflect.Slice {
				if err := cmd.values[i-x](v, values); err != nil {
					return 1, err
				}
				params = append(params, v)
				values = nil
				break
			}
			var value []string
			if len(values) == 0 {
				value = []string{""}
			} else {
				value, values = values[:1], values[1:]
			}
			if err := cmd.values[i-x](v, value); err != nil {
				return 1, err
			}
			params = append(params, v)
		}
	}
	if len(values) != 0 {
		return 1, &Usage{
			Cmd: cmd,
			Err: fmt.Errorf("too many positional arguments: %q", values),
		}
	}
	if cmd.variadic && len(command) == 0 {
		return 1, &Usage{
			Cmd: cmd,
			Err: fmt.Errorf("missing command after \"--\" separator"),
		}
	}
	if !cmd.variadic && len(command) != 0 {
		return 1, &Usage{
			Cmd: cmd,
			Err: fmt.Errorf("unsupported command after \"--\" separator"),
		}
	}
	var r []reflect.Value
	if cmd.variadic {
		r = cmd.function.CallSlice(append(params, reflect.ValueOf(command)))
	} else {
		r = cmd.function.Call(params)
	}
	var ret int
	switch len(r) {
	case 0:
	case 1:
		if err, _ = r[0].Interface().(error); err != nil {
			ret = 1
		}
	default:
		ret, _ = r[0].Interface().(int)
		err, _ = r[1].Interface().(error)
	}
	switch e := err.(type) {
	case *Help:
		e.Cmd = cmd
	case *Usage:
		e.Cmd = cmd
	}
	return ret, err
}
func (cmd *CommandFunc) Format(w fmt.State, v rune) {
	switch v {
	case 's':  
		io.WriteString(w, "[options]")
		t := cmd.function.Type()
		n := t.NumIn()
		if cmd.variadic {
			n--
		}
		i := 1
		if cmd.context {
			i = 2
		}
		for i < n {
			p := t.In(i)
			fmt.Fprintf(w, " [%s]", typeNameOf(p))
			if p.Kind() == reflect.Slice {
				break
			}
			i++
		}
		if cmd.variadic {
			io.WriteString(w, " -- [command]")
		}
	case 'v':  
		if w.Flag('#') {
			io.WriteString(w, strings.Replace(cmd.function.Type().String(), "func", "cli.Command", 1))
			return
		}
		if cmd.Desc != "" {
			for _, line := range strings.Split(cmd.Desc, "\n") {
				fmt.Fprintf(w, "  %s\n", line)
			}
			io.WriteString(w, "\n")
		}
		io.WriteString(w, "Options:\n")
		tw := newTabWriter(w)
		defer tw.Flush()
		shortLen := 0
		for _, field := range cmd.options {
			n := 0
			for _, f := range field.flags {
				if isShortFlag(f) {
					n += utf8.RuneCountInString(f) + 2
				}
			}
			if n > shortLen {
				shortLen = n
			}
		}
		b := &bytes.Buffer{}
		b.Grow(128)
		for _, fieldName := range sortedMapKeys(reflect.ValueOf(cmd.options)) {
			b.Reset()
			b.WriteString("  ")  
			field := cmd.options[fieldName.String()]
			n := 0
			for i, f := range field.flags {
				if isShortFlag(f) {
					n += writeFlag(b, f, i, len(field.flags))
				}
			}
			for n < shortLen {
				b.WriteByte(' ')
				n++
			}
			for i, f := range field.flags {
				if isLongFlag(f) {
					writeFlag(b, f, i, len(field.flags))
				}
			}
			if field.argtyp != "" {
				b.WriteString(" ")
				b.WriteString(field.argtyp)
			}
			b.WriteString("\t")
			if field.help != "" {
				b.WriteString("  ")
				b.WriteString(field.help)
			}
			if field.defval != "" && field.defval != "-" {
				fmt.Fprintf(b, " (default: %s)", field.defval)
			}
			b.WriteString("\n")
			tw.Write(b.Bytes())
		}
	case 'x':  
		io.WriteString(w, cmd.help)
	}
}
func writeFlag(b *bytes.Buffer, f string, i, n int) int {
	b.WriteString(f)
	if (i + 1) < n {
		b.WriteString(", ")
	}
	return utf8.RuneCountInString(f) + 2
}
func isShortFlag(s string) bool { return !isLongFlag(s) }
func isLongFlag(s string) bool  { return strings.HasPrefix(s, "--") }
type CommandSet map[string]Function
func (cmds CommandSet) Call(ctx context.Context, args, env []string) (int, error) {
	for _, cmd := range cmds {
		if c, ok := cmd.(interface{ configure() }); ok {
			c.configure()
		}
	}
	var wantHelp bool
	if wantHelp, args = parseHelp(args); wantHelp {
		return 0, &Help{Cmd: cmds}
	}
	var a string
	var c Function
	for i, arg := range args {
		if isCommandSeparator(arg) {
			break
		}
		if isOption(arg) {
			continue
		}
		a = arg
		tmp := make([]string, 0, len(args)-1)
		tmp = append(tmp, args[:i]...)
		tmp = append(tmp, args[i+1:]...)
		args = tmp
		break
	}
	if a == "" {
		return 1, &Usage{Cmd: cmds, Err: fmt.Errorf("missing command")}
	}
	if c = cmds[a]; c == nil {
		return 1, &Usage{Cmd: cmds, Err: fmt.Errorf("unknown command: %q", a)}
	}
	return NamedCommand(a, c).Call(ctx, args, env)
}
func (cmds CommandSet) Format(w fmt.State, v rune) {
	switch v {
	case 's':
		io.WriteString(w, "[command] [-h] [--help] ...")
	case 'v':
		if w.Flag('#') {
			io.WriteString(w, "cli.CommandSet{")
			names := make([]string, 0, len(cmds))
			for name := range cmds {
				names = append(names, name)
			}
			sort.Strings(names)
			for i, name := range names {
				if i != 0 {
					io.WriteString(w, ", ")
				}
				fmt.Fprintf(w, "%q:%#v", name, cmds[name])
			}
			io.WriteString(w, "}")
			return
		}
		io.WriteString(w, "Commands:\n")
		tw := newTabWriter(w)
		for _, cmd := range sortedMapKeys(reflect.ValueOf(cmds)) {
			cmdKey := cmd.String()
			fmt.Fprintf(tw, "  %s\t  %x\n", cmdKey, cmds[cmdKey])
		}
		tw.Flush()
		io.WriteString(w, `
Options:
  -h, --help  Show this help message
`)
	}
}