github.com/pyroscope-io/pyroscope@v0.37.3-0.20230725203016-5f6947968bd0/pkg/cli/usage.go (about) 1 package cli 2 3 import ( 4 "fmt" 5 "strings" 6 "text/tabwriter" 7 8 "github.com/fatih/color" 9 "github.com/spf13/cobra" 10 "github.com/spf13/pflag" 11 ) 12 13 var ( 14 headerClr *color.Color 15 itemClr *color.Color 16 descClr *color.Color 17 defClr *color.Color 18 ) 19 20 func init() { 21 headerClr = color.New(color.FgGreen) 22 itemClr = color.New(color.Bold) 23 // itemClr = color.New() 24 descClr = color.New() 25 defClr = color.New(color.FgYellow) 26 } 27 28 // TODO: Do we want to keep this or use cobra default one? Maybe banner + cobra default? Or something else? 29 // This is mostly copied from ffcli package 30 func DefaultUsageFunc(sf *pflag.FlagSet, c *cobra.Command) string { 31 var b strings.Builder 32 33 fmt.Fprintf(&b, "continuous profiling platform\n\n") 34 headerClr.Fprintf(&b, "USAGE\n") 35 if c.Use != "" { 36 fmt.Fprintf(&b, " %s\n", c.Use) 37 } else { 38 fmt.Fprintf(&b, " %s\n", c.Name()) 39 } 40 fmt.Fprintf(&b, "\n") 41 42 if c.Long != "" { 43 fmt.Fprintf(&b, "%s\n\n", c.Long) 44 } 45 46 if hasSubCommands(c) { 47 headerClr.Fprintf(&b, "SUBCOMMANDS\n") 48 tw := tabwriter.NewWriter(&b, 0, 2, 2, ' ', 0) 49 for _, subcommand := range c.Commands() { 50 if !subcommand.Hidden { 51 fmt.Fprintf(tw, " %s\t%s\n", itemClr.Sprintf(subcommand.Name()), subcommand.Short) 52 } 53 } 54 tw.Flush() 55 fmt.Fprintf(&b, "\n") 56 } 57 58 if countFlags(c.Flags()) > 0 { 59 // headerClr.Fprintf(&b, "FLAGS\n") 60 tw := tabwriter.NewWriter(&b, 0, 2, 2, ' ', 0) 61 fmt.Fprintf(tw, "%s\t %s@new-line@\n", headerClr.Sprintf("FLAGS"), defClr.Sprint("DEFAULT VALUES")) 62 63 // TODO: it would be nice to sort by how often people would use these. 64 // But for that we'd have to have a conversion from flag-set back to struct 65 sf.VisitAll(func(f *pflag.Flag) { 66 if f.Hidden { 67 return 68 } 69 def := f.DefValue 70 // if def == "" { 71 // def = "..." 72 // } 73 def = defClr.Sprint(def) 74 // def = fmt.Sprintf("(%s)", def) 75 fmt.Fprintf(tw, " %s\t%s", itemClr.Sprintf("--"+f.Name), def) 76 if f.Usage != "" { 77 fmt.Fprintf(tw, "@new-line@ ") 78 descClr.Fprint(tw, f.Usage) 79 } 80 descClr.Fprint(tw, "@new-line@") 81 fmt.Fprint(tw, "\n") 82 }) 83 tw.Flush() 84 // fmt.Fprintf(&b, "\n") 85 } 86 87 if hasSubCommands(c) { 88 b.WriteString("Run 'pyroscope SUBCOMMAND --help' for more information on a subcommand.\n") 89 } 90 91 return strings.ReplaceAll(b.String(), "@new-line@", "\n") 92 } 93 94 // hasSubCommands works as cobra HasSubCommands but reports false 95 // when the only subcommand is help. 96 func hasSubCommands(cmd *cobra.Command) bool { 97 return cmd.HasSubCommands() && !(len(cmd.Commands()) == 1 && cmd.Commands()[0].Name() == "help") 98 } 99 100 func countFlags(fs *pflag.FlagSet) (n int) { 101 fs.VisitAll(func(*pflag.Flag) { n++ }) 102 return n 103 }