func (i *Info) Render() {
	usageMessage := "\n{*}Usage:{!} " + i.Name
	if len(i.Options) != 0 {
		usageMessage += " " + i.OptionsColorTag + "{options}{!}"
	}
	if len(i.Commands) != 0 {
		usageMessage += " " + i.CommandsColorTag + "{command}{!}"
	}
	if len(i.Args) != 0 {
		usageMessage += " " + strings.Join(i.Args, " ")
	}
	fmtc.Println(usageMessage)
	if i.Spoiler != "" {
		fmtc.NewLine()
		fmtc.Println(i.Spoiler)
	}
	if len(i.Commands) != 0 {
		renderCommands(i)
	}
	if len(i.Options) != 0 {
		renderOptions(i)
	}
	if len(i.Examples) != 0 {
		renderExamples(i)
	}
	fmtc.NewLine()
}
Render prints usage info to console
package usage
import (
	"os"
	"path/filepath"
	"strings"
	"time"
	"pkg.re/essentialkaos/ek.v12/fmtc"
	"pkg.re/essentialkaos/ek.v12/mathutil"
	"pkg.re/essentialkaos/ek.v12/strutil"
	"pkg.re/essentialkaos/ek.v12/version"
)
const (
	_SPACES = "                                                                "
	_DOTS   = "................................................................"
)
const _BREADCRUMBS_MIN_SIZE = 8
type About struct {
	App        string  
	Version    string  
	Release    string  
	Build      string  
	Desc       string  
	Year       int     
	License    string  
	Owner      string  
	BugTracker string  
	UpdateChecker UpdateChecker
}
type Info struct {
	CommandsColorTag string  
	OptionsColorTag  string  
	Breadcrumbs      bool    
	Name    string
	Args    []string
	Spoiler string
	Commands []*Command
	Options  []*Option
	Examples []*Example
	curGroup string
}
type UpdateChecker struct {
	Data      string
	CheckFunc func(app, version, data string) (string, time.Time, bool)
}
type Command struct {
	Name         string
	Desc         string
	Group        string
	Args         []string
	BoundOptions []string
}
type Option struct {
	Short string
	Long  string
	Desc  string
	Arg   string
}
type Example struct {
	Cmd  string
	Desc string
	Raw  bool
}
func NewInfo(args ...string) *Info {
	var name string
	if len(args) != 0 {
		name = args[0]
		args = args[1:]
	}
	if name == "" {
		name = filepath.Base(os.Args[0])
	}
	info := &Info{
		Name: name,
		Args: args,
		CommandsColorTag: "{y}",
		OptionsColorTag:  "{g}",
		Breadcrumbs:      true,
	}
	return info
}
func (i *Info) AddGroup(group string) {
	i.curGroup = group
}
func (i *Info) AddCommand(a ...string) {
	group := "Commands"
	if i.curGroup != "" {
		group = i.curGroup
	}
	if len(a) < 2 {
		return
	}
	i.Commands = append(
		i.Commands,
		&Command{
			Name:  a[0],
			Desc:  a[1],
			Args:  a[2:],
			Group: group,
		},
	)
}
func (i *Info) AddOption(a ...string) {
	if len(a) < 2 {
		return
	}
	long, short := parseOptionName(a[0])
	i.Options = append(
		i.Options,
		&Option{
			Long:  long,
			Short: short,
			Desc:  a[1],
			Arg:   strings.Join(a[2:], " "),
		},
	)
}
func (i *Info) AddExample(a ...string) {
	if len(a) == 0 {
		return
	}
	a = append(a, "")
	i.Examples = append(i.Examples, &Example{a[0], a[1], false})
}
func (i *Info) AddRawExample(a ...string) {
	if len(a) == 0 {
		return
	}
	a = append(a, "")
	i.Examples = append(i.Examples, &Example{a[0], a[1], true})
}
func (i *Info) AddSpoiler(spoiler string) {
	i.Spoiler = spoiler
}
func (i *Info) BoundOptions(cmd string, options ...string) {
	for _, command := range i.Commands {
		if command.Name == cmd {
			for _, opt := range options {
				longOption, _ := parseOptionName(opt)
				command.BoundOptions = append(command.BoundOptions, longOption)
			}
			return
		}
	}
}
func (i *Info) GetCommand(name string) *Command {
	for _, command := range i.Commands {
		if command.Name == name {
			return command
		}
	}
	return nil
}
func (i *Info) GetOption(name string) *Option {
	name, _ = parseOptionName(name)
	for _, option := range i.Options {
		if option.Long == name {
			return option
		}
	}
	return nil
}