Rework flag categories a bit
with internal maps instead of slices and slightly less public API surface area
This commit is contained in:
parent
ddac788d85
commit
156eaafb22
19
app.go
19
app.go
@ -184,15 +184,14 @@ func (a *App) Setup() {
|
|||||||
c.HelpName = fmt.Sprintf("%s %s", a.HelpName, c.Name)
|
c.HelpName = fmt.Sprintf("%s %s", a.HelpName, c.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
fc := FlagCategories{}
|
fc := newFlagCategories()
|
||||||
for _, fl := range c.Flags {
|
for _, fl := range c.Flags {
|
||||||
if cf, ok := fl.(CategorizableFlag); ok {
|
if cf, ok := fl.(CategorizableFlag); ok {
|
||||||
fc = fc.AddFlag(cf.GetCategory(), cf)
|
fc.AddFlag(cf.GetCategory(), cf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Sort(fc)
|
c.flagCategories = fc
|
||||||
c.FlagCategories = fc
|
|
||||||
newCommands = append(newCommands, c)
|
newCommands = append(newCommands, c)
|
||||||
}
|
}
|
||||||
a.Commands = newCommands
|
a.Commands = newCommands
|
||||||
@ -217,13 +216,12 @@ func (a *App) Setup() {
|
|||||||
}
|
}
|
||||||
sort.Sort(a.categories.(*commandCategories))
|
sort.Sort(a.categories.(*commandCategories))
|
||||||
|
|
||||||
a.flagCategories = FlagCategories{}
|
a.flagCategories = newFlagCategories()
|
||||||
for _, fl := range a.Flags {
|
for _, fl := range a.Flags {
|
||||||
if cf, ok := fl.(CategorizableFlag); ok {
|
if cf, ok := fl.(CategorizableFlag); ok {
|
||||||
a.flagCategories.AddFlag(cf.GetCategory(), cf)
|
a.flagCategories.AddFlag(cf.GetCategory(), cf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sort.Sort(a.flagCategories)
|
|
||||||
|
|
||||||
if a.Metadata == nil {
|
if a.Metadata == nil {
|
||||||
a.Metadata = make(map[string]interface{})
|
a.Metadata = make(map[string]interface{})
|
||||||
@ -501,9 +499,12 @@ func (a *App) VisibleCommands() []*Command {
|
|||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
// Categories returns a slice containing all the categories with the commands they contain
|
// VisibleFlagCategories returns a slice containing all the categories with the flags they contain
|
||||||
func (a *App) VisibleFlagCategories() FlagCategories {
|
func (a *App) VisibleFlagCategories() []VisibleFlagCategory {
|
||||||
return a.flagCategories
|
if a.flagCategories == nil {
|
||||||
|
a.flagCategories = newFlagCategories()
|
||||||
|
}
|
||||||
|
return a.flagCategories.VisibleCategories()
|
||||||
}
|
}
|
||||||
|
|
||||||
// VisibleFlags returns a slice of the Flags with Hidden=false
|
// VisibleFlags returns a slice of the Flags with Hidden=false
|
||||||
|
77
app_test.go
77
app_test.go
@ -142,8 +142,8 @@ func ExampleApp_Run_appHelp() {
|
|||||||
// help, h Shows a list of commands or help for one command
|
// help, h Shows a list of commands or help for one command
|
||||||
//
|
//
|
||||||
// GLOBAL OPTIONS:
|
// GLOBAL OPTIONS:
|
||||||
// --name value a name to say (default: "bob")
|
|
||||||
// --help, -h show help (default: false)
|
// --help, -h show help (default: false)
|
||||||
|
// --name value a name to say (default: "bob")
|
||||||
// --version, -v print the version (default: false)
|
// --version, -v print the version (default: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1823,23 +1823,20 @@ func TestApp_VisibleCategories(t *testing.T) {
|
|||||||
HideHelp: true,
|
HideHelp: true,
|
||||||
Commands: []*Command{
|
Commands: []*Command{
|
||||||
{
|
{
|
||||||
Name: "command1",
|
Name: "command1",
|
||||||
Category: "1",
|
Category: "1",
|
||||||
HelpName: "foo command1",
|
HelpName: "foo command1",
|
||||||
Hidden: true,
|
Hidden: true,
|
||||||
FlagCategories: FlagCategories{},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "command2",
|
Name: "command2",
|
||||||
Category: "2",
|
Category: "2",
|
||||||
HelpName: "foo command2",
|
HelpName: "foo command2",
|
||||||
FlagCategories: FlagCategories{},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "command3",
|
Name: "command3",
|
||||||
Category: "3",
|
Category: "3",
|
||||||
HelpName: "foo command3",
|
HelpName: "foo command3",
|
||||||
FlagCategories: FlagCategories{},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -1867,24 +1864,21 @@ func TestApp_VisibleCategories(t *testing.T) {
|
|||||||
HideHelp: true,
|
HideHelp: true,
|
||||||
Commands: []*Command{
|
Commands: []*Command{
|
||||||
{
|
{
|
||||||
Name: "command1",
|
Name: "command1",
|
||||||
Category: "1",
|
Category: "1",
|
||||||
HelpName: "foo command1",
|
HelpName: "foo command1",
|
||||||
Hidden: true,
|
Hidden: true,
|
||||||
FlagCategories: FlagCategories{},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "command2",
|
Name: "command2",
|
||||||
Category: "2",
|
Category: "2",
|
||||||
HelpName: "foo command2",
|
HelpName: "foo command2",
|
||||||
Hidden: true,
|
Hidden: true,
|
||||||
FlagCategories: FlagCategories{},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "command3",
|
Name: "command3",
|
||||||
Category: "3",
|
Category: "3",
|
||||||
HelpName: "foo command3",
|
HelpName: "foo command3",
|
||||||
FlagCategories: FlagCategories{},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -1906,25 +1900,22 @@ func TestApp_VisibleCategories(t *testing.T) {
|
|||||||
HideHelp: true,
|
HideHelp: true,
|
||||||
Commands: []*Command{
|
Commands: []*Command{
|
||||||
{
|
{
|
||||||
Name: "command1",
|
Name: "command1",
|
||||||
Category: "1",
|
Category: "1",
|
||||||
HelpName: "foo command1",
|
HelpName: "foo command1",
|
||||||
Hidden: true,
|
Hidden: true,
|
||||||
FlagCategories: FlagCategories{},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "command2",
|
Name: "command2",
|
||||||
Category: "2",
|
Category: "2",
|
||||||
HelpName: "foo command2",
|
HelpName: "foo command2",
|
||||||
Hidden: true,
|
Hidden: true,
|
||||||
FlagCategories: FlagCategories{},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "command3",
|
Name: "command3",
|
||||||
Category: "3",
|
Category: "3",
|
||||||
HelpName: "foo command3",
|
HelpName: "foo command3",
|
||||||
Hidden: true,
|
Hidden: true,
|
||||||
FlagCategories: FlagCategories{},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
98
category.go
98
category.go
@ -1,10 +1,12 @@
|
|||||||
package cli
|
package cli
|
||||||
|
|
||||||
|
import "sort"
|
||||||
|
|
||||||
// CommandCategories interface allows for category manipulation
|
// CommandCategories interface allows for category manipulation
|
||||||
type CommandCategories interface {
|
type CommandCategories interface {
|
||||||
// AddCommand adds a command to a category, creating a new category if necessary.
|
// AddCommand adds a command to a category, creating a new category if necessary.
|
||||||
AddCommand(category string, command *Command)
|
AddCommand(category string, command *Command)
|
||||||
// categories returns a copy of the category slice
|
// Categories returns a slice of categories sorted by name
|
||||||
Categories() []CommandCategory
|
Categories() []CommandCategory
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,47 +80,81 @@ func (c *commandCategory) VisibleCommands() []*Command {
|
|||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
// FlagCategories is a slice of *FlagCategory.
|
// FlagCategories interface allows for category manipulation
|
||||||
type FlagCategories []*FlagCategory
|
type FlagCategories interface {
|
||||||
|
// AddFlags adds a flag to a category, creating a new category if necessary.
|
||||||
// FlagCategory is a category containing flags.
|
AddFlag(category string, fl Flag)
|
||||||
type FlagCategory struct {
|
// VisibleCategories returns a slice of visible flag categories sorted by name
|
||||||
Name string
|
VisibleCategories() []VisibleFlagCategory
|
||||||
Flags []Flag
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f FlagCategories) Less(i, j int) bool {
|
type defaultFlagCategories struct {
|
||||||
return lexicographicLess(f[i].Name, f[j].Name)
|
m map[string]*defaultVisibleFlagCategory
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f FlagCategories) Len() int {
|
func newFlagCategories() FlagCategories {
|
||||||
return len(f)
|
return &defaultFlagCategories{
|
||||||
}
|
m: map[string]*defaultVisibleFlagCategory{},
|
||||||
|
|
||||||
func (f FlagCategories) Swap(i, j int) {
|
|
||||||
f[i], f[j] = f[j], f[i]
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddFlags adds a command to a category.
|
|
||||||
func (f FlagCategories) AddFlag(category string, flag Flag) FlagCategories {
|
|
||||||
for _, flagCategory := range f {
|
|
||||||
if flagCategory.Name == category {
|
|
||||||
flagCategory.Flags = append(flagCategory.Flags, flag)
|
|
||||||
return f
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return append(f, &FlagCategory{Name: category, Flags: []Flag{flag}})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// VisibleFlags returns a slice of the Flags with Hidden=false
|
func (f *defaultFlagCategories) AddFlag(category string, fl Flag) {
|
||||||
func (c *FlagCategory) VisibleFlags() []VisibleFlag {
|
if _, ok := f.m[category]; !ok {
|
||||||
ret := []VisibleFlag{}
|
f.m[category] = &defaultVisibleFlagCategory{name: category, m: map[string]Flag{}}
|
||||||
for _, fl := range c.Flags {
|
}
|
||||||
|
|
||||||
|
f.m[category].m[fl.String()] = fl
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *defaultFlagCategories) VisibleCategories() []VisibleFlagCategory {
|
||||||
|
catNames := []string{}
|
||||||
|
for name := range f.m {
|
||||||
|
catNames = append(catNames, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Strings(catNames)
|
||||||
|
|
||||||
|
ret := make([]VisibleFlagCategory, len(catNames))
|
||||||
|
for i, name := range catNames {
|
||||||
|
ret[i] = f.m[name]
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// VisibleFlagCategory is a category containing flags.
|
||||||
|
type VisibleFlagCategory interface {
|
||||||
|
// Name returns the category name string
|
||||||
|
Name() string
|
||||||
|
// Flags returns a slice of VisibleFlag sorted by name
|
||||||
|
Flags() []VisibleFlag
|
||||||
|
}
|
||||||
|
|
||||||
|
type defaultVisibleFlagCategory struct {
|
||||||
|
name string
|
||||||
|
m map[string]Flag
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fc *defaultVisibleFlagCategory) Name() string {
|
||||||
|
return fc.name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fc *defaultVisibleFlagCategory) Flags() []VisibleFlag {
|
||||||
|
vfNames := []string{}
|
||||||
|
for flName, fl := range fc.m {
|
||||||
if vf, ok := fl.(VisibleFlag); ok {
|
if vf, ok := fl.(VisibleFlag); ok {
|
||||||
if vf.IsVisible() {
|
if vf.IsVisible() {
|
||||||
ret = append(ret, vf)
|
vfNames = append(vfNames, flName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sort.Strings(vfNames)
|
||||||
|
|
||||||
|
ret := make([]VisibleFlag, len(vfNames))
|
||||||
|
for i, flName := range vfNames {
|
||||||
|
ret[i] = fc.m[flName].(VisibleFlag)
|
||||||
|
}
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
14
command.go
14
command.go
@ -38,9 +38,8 @@ type Command struct {
|
|||||||
// List of child commands
|
// List of child commands
|
||||||
Subcommands []*Command
|
Subcommands []*Command
|
||||||
// List of flags to parse
|
// List of flags to parse
|
||||||
Flags []Flag
|
Flags []Flag
|
||||||
// List of all flag categories
|
flagCategories FlagCategories
|
||||||
FlagCategories FlagCategories
|
|
||||||
// Treat all flags as normal arguments if true
|
// Treat all flags as normal arguments if true
|
||||||
SkipFlagParsing bool
|
SkipFlagParsing bool
|
||||||
// Boolean to hide built-in help command and help flag
|
// Boolean to hide built-in help command and help flag
|
||||||
@ -282,9 +281,12 @@ func (c *Command) startApp(ctx *Context) error {
|
|||||||
return app.RunAsSubcommand(ctx)
|
return app.RunAsSubcommand(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Categories returns a slice containing all the categories with the commands they contain
|
// VisibleFlagCategories returns a slice containing all the visible flag categories with the flags they contain
|
||||||
func (c Command) VisibleFlagCategories() FlagCategories {
|
func (c *Command) VisibleFlagCategories() []VisibleFlagCategory {
|
||||||
return c.FlagCategories
|
if c.flagCategories == nil {
|
||||||
|
c.flagCategories = newFlagCategories()
|
||||||
|
}
|
||||||
|
return c.flagCategories.VisibleCategories()
|
||||||
}
|
}
|
||||||
|
|
||||||
// VisibleFlags returns a slice of the Flags with Hidden=false
|
// VisibleFlags returns a slice of the Flags with Hidden=false
|
||||||
|
@ -25,8 +25,8 @@ COMMANDS:{{range .VisibleCategories}}{{if .Name}}
|
|||||||
{{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}{{end}}{{end}}{{end}}{{if .VisibleFlagCategories}}
|
{{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}{{end}}{{end}}{{end}}{{if .VisibleFlagCategories}}
|
||||||
|
|
||||||
GLOBAL OPTIONS:{{range .VisibleFlagCategories}}
|
GLOBAL OPTIONS:{{range .VisibleFlagCategories}}
|
||||||
{{.Name}}
|
{{if .Name}}{{.Name}}
|
||||||
{{range .VisibleFlags}}{{.}}
|
{{end}}{{range .Flags}}{{.}}
|
||||||
{{end}}{{end}}{{else}}{{if .VisibleFlags}}
|
{{end}}{{end}}{{else}}{{if .VisibleFlags}}
|
||||||
|
|
||||||
GLOBAL OPTIONS:
|
GLOBAL OPTIONS:
|
||||||
@ -53,8 +53,8 @@ DESCRIPTION:
|
|||||||
{{.Description | nindent 3 | trim}}{{end}}{{if .VisibleFlagCategories}}
|
{{.Description | nindent 3 | trim}}{{end}}{{if .VisibleFlagCategories}}
|
||||||
|
|
||||||
OPTIONS:{{range .VisibleFlagCategories}}
|
OPTIONS:{{range .VisibleFlagCategories}}
|
||||||
{{.Name}}
|
{{if .Name}}{{.Name}}
|
||||||
{{range .VisibleFlags}}{{.}}
|
{{end}}{{range .Flags}}{{.}}
|
||||||
{{end}}{{end}}{{else}}{{if .VisibleFlags}}
|
{{end}}{{end}}{{else}}{{if .VisibleFlags}}
|
||||||
|
|
||||||
OPTIONS:
|
OPTIONS:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user