func (fs *Flags) InitFlagSet(name string) {
	if fs.fSet != nil {
		return
	}
	fs.fSet = flag.NewFlagSet(name, flag.ContinueOnError)
	fs.fSet.SetOutput(ioutil.Discard)
	fs.fSet.Usage = func() {}
}
InitFlagSet create and init flag.FlagSet
package gcli
import (
	"bytes"
	"errors"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"reflect"
	"strings"
	"unsafe"
	"github.com/gookit/color"
	"github.com/gookit/goutil"
	"github.com/gookit/goutil/arrutil"
	"github.com/gookit/goutil/strutil"
)
const (
	AlignLeft  = strutil.PosRight
	AlignRight = strutil.PosLeft
	defaultDesc = "No description"
	TagRuleNamed = 0
	TagRuleSimple = 1
)
var (
	FlagTagName = "flag"
	flagTagKeys = arrutil.Strings{"name", "shorts", "desc", "default", "required"}
)
type FlagsOption struct {
	WithoutType bool
	NameDescOL bool
	Alignment uint8
	TagName string
	TagRuleType uint8
}
type Flags struct {
	Desc string
	ExitFunc func(code int)
	opt *FlagsOption
	fSet *flag.FlagSet
	buf *bytes.Buffer
	out io.Writer
	names map[string]int
	metas map[string]*FlagMeta  
	shorts map[string]string
	name2shorts map[string][]string
	flagMaxLen int
	existShort bool
}
func newDefaultFlagOption() *FlagsOption {
	return &FlagsOption{
		Alignment: AlignRight,
		TagName:   FlagTagName,
	}
}
func NewFlags(nameWithDesc ...string) *Flags {
	fs := &Flags{
		out: os.Stdout,
		opt: newDefaultFlagOption(),
	}
	fs.ExitFunc = os.Exit
	fName := "gflag"
	if num := len(nameWithDesc); num > 0 {
		fName = nameWithDesc[0]
		if num > 1 {
			fs.Desc = nameWithDesc[1]
		}
	}
	fs.InitFlagSet(fName)
	return fs
}
var flagValueType = reflect.TypeOf(new(flag.Value)).Elem()
var errNotPtrValue = errors.New("must provide an ptr value")
var errNotAnStruct = errors.New("must provide an struct ptr")
var errTagRuleType = errors.New("invalid tag rule type on struct")
func (fs *Flags) FromStruct(ptr interface{}) error {
	v := reflect.ValueOf(ptr)
	if v.Kind() != reflect.Ptr {
		return errNotPtrValue
	}
	if !v.IsNil() {
		v = v.Elem()
	}
	t := v.Type()
	if t.Kind() != reflect.Struct {
		return errNotAnStruct
	}
	tagName := fs.opt.TagName
	if tagName == "" {
		tagName = FlagTagName
	}
	var mp map[string]string
	for i := 0; i < t.NumField(); i++ {
		sf := t.Field(i)
		name := sf.Name
		if name[0] >= 'a' && name[0] <= 'z' {
			continue
		}
		str := sf.Tag.Get(tagName)
		if str == "" {
			continue
		}
		fv := v.Field(i)
		ft := t.Field(i).Type
		if !fv.CanInterface() {
			continue
		}
		if ft.Kind() == reflect.Ptr {
			if fv.IsNil() {
				return fmt.Errorf("field: %s - nil pointer dereference", name)
			}
			ft = ft.Elem()
			fv = fv.Elem()
		}
		if fs.opt.TagRuleType == TagRuleNamed {
			mp = parseNamedRule(name, str)
		} else if fs.opt.TagRuleType == TagRuleSimple {
			mp = parseSimpleRule(name, str)
		} else {
			return errTagRuleType
		}
		defVal := mp["default"]
		shorts := splitShortcut(mp["shorts"])
		optName, has := mp["name"]
		if !has {  
			optName = strutil.SnakeCase(name, "-")
		}
		meta := newFlagMeta(optName, mp["desc"], defVal, shorts)
		if must, has := mp["required"]; has {
			meta.Required = strutil.MustBool(must)
		}
		if ft.Implements(flagValueType) {
			fs.Var(fv.Interface().(flag.Value), meta)
			continue
		}
		ptr := unsafe.Pointer(fv.UnsafeAddr())
		switch ft.Kind() {
		case reflect.Bool:
			fs.BoolVar((*bool)(ptr), meta)
		case reflect.Int:
			fs.IntVar((*int)(ptr), meta)
		case reflect.Int64:
			fs.Int64Var((*int64)(ptr), meta)
		case reflect.Uint:
			fs.UintVar((*uint)(ptr), meta)
		case reflect.Uint64:
			fs.Uint64Var((*uint64)(ptr), meta)
		case reflect.Float64:
			fs.Float64Var((*float64)(ptr), meta)
		case reflect.String:
			fs.StrVar((*string)(ptr), meta)
		default:
			return fmt.Errorf("field: %s - invalid type for binding flag", name)
		}
	}
	return nil
}
func (fs *Flags) SetOptions(opt *FlagsOption) {
	fs.opt = opt
}
func (fs *Flags) UseSimpleRule() *Flags {
	fs.opt.TagRuleType = TagRuleSimple
	return fs
}
func (fs *Flags) WithOptions(fns func(opt *FlagsOption)) *Flags {
	fns(fs.opt)
	return fs
}