@cryptotaxi247 / kubo / commits / c169fca5a

commands/cli: Added a helptext generator

Matt Bell committed Nov 8, 2014 at 01:52 UTC c169fca5a2826af8bb360bb12e8d7e9886de6fdb
1 file changed +193
commands/cli/helptext.go new
+193
@@ -0,0 +1,193 @@
1 +package cli
2 +
3 +import (
4 + "fmt"
5 + "strings"
6 +
7 + cmds "github.com/jbenet/go-ipfs/commands"
8 +)
9 +
10 +const (
11 + requiredArg = "<%v>"
12 + optionalArg = "[<%v>]"
13 + variadicArg = "%v..."
14 + optionFlag = "-%v"
15 + optionType = "(%v)"
16 +
17 + whitespace = "\r\n\t "
18 +)
19 +
20 +// HelpText returns a formatted CLI helptext string, generated for the given command
21 +func HelpText(rootName string, root *cmds.Command, path []string) (string, error) {
22 + cmd, err := root.Get(path)
23 + if err != nil {
24 + return "", err
25 + }
26 +
27 + s := ""
28 + usage := usageText(cmd)
29 + if len(usage) > 0 {
30 + usage += " "
31 + }
32 + s += fmt.Sprintf("%v %v %v- %v\n\n", rootName, strings.Join(path, " "), usage, cmd.Description)
33 +
34 + if len(cmd.Help) > 0 {
35 + s += fmt.Sprintf("%v\n\n", strings.Trim(cmd.Help, whitespace))
36 + }
37 +
38 + if cmd.Arguments != nil {
39 + lines := indent(argumentText(cmd), " ")
40 + s += fmt.Sprintf("Arguments:\n%v\n\n", strings.Join(lines, "\n"))
41 + }
42 +
43 + if cmd.Subcommands != nil {
44 + lines := indent(subcommandText(cmd, rootName, path), " ")
45 + s += fmt.Sprintf("Subcommands:\n%v\n\n", strings.Join(lines, "\n"))
46 + }
47 +
48 + if cmd.Options != nil {
49 + lines := indent(optionText(cmd), " ")
50 + s += fmt.Sprintf("Options:\n%v\n\n", strings.Join(lines, "\n"))
51 + }
52 +
53 + return s, nil
54 +}
55 +
56 +func argumentText(cmd *cmds.Command) []string {
57 + lines := make([]string, len(cmd.Arguments))
58 +
59 + for i, arg := range cmd.Arguments {
60 + lines[i] = argUsageText(arg)
61 + lines[i] += "\n" + arg.Description
62 + lines[i] = indentString(lines[i], " ") + "\n"
63 + }
64 +
65 + return lines
66 +}
67 +
68 +func optionText(cmd ...*cmds.Command) []string {
69 + // get a slice of the options we want to list out
70 + options := make([]cmds.Option, 0)
71 + for _, c := range cmd {
72 + for _, opt := range c.Options {
73 + options = append(options, opt)
74 + }
75 + }
76 +
77 + // add option names to output (with each name aligned)
78 + lines := make([]string, 0)
79 + j := 0
80 + for {
81 + done := true
82 + i := 0
83 + for _, opt := range options {
84 + if len(lines) < i+1 {
85 + lines = append(lines, "")
86 + }
87 + if len(opt.Names) >= j+1 {
88 + lines[i] += fmt.Sprintf(optionFlag, opt.Names[j])
89 + }
90 + if len(opt.Names) > j+1 {
91 + lines[i] += ", "
92 + done = false
93 + }
94 +
95 + i++
96 + }
97 +
98 + if done {
99 + break
100 + }
101 +
102 + lines = align(lines)
103 + j++
104 + }
105 +
106 + // add option types to output
107 + for i, opt := range options {
108 + lines[i] += " " + fmt.Sprintf(optionType, opt.Type)
109 + }
110 + lines = align(lines)
111 +
112 + // add option descriptions to output
113 + for i, opt := range options {
114 + lines[i] += "\n" + opt.Description
115 + lines[i] = indentString(lines[i], " ") + "\n"
116 + }
117 +
118 + return lines
119 +}
120 +
121 +func subcommandText(cmd *cmds.Command, rootName string, path []string) []string {
122 + prefix := fmt.Sprintf("%v %v", rootName, strings.Join(path, " "))
123 + lines := make([]string, len(cmd.Subcommands))
124 +
125 + i := 0
126 + for name, sub := range cmd.Subcommands {
127 + usage := usageText(sub)
128 + lines[i] = fmt.Sprintf("%v %v %v", prefix, name, usage)
129 + lines[i] += fmt.Sprintf("\n%v", sub.Description)
130 + lines[i] = indentString(lines[i], " ") + "\n"
131 + i++
132 + }
133 +
134 + return lines
135 +}
136 +
137 +func usageText(cmd *cmds.Command) string {
138 + s := ""
139 + for i, arg := range cmd.Arguments {
140 + if i != 0 {
141 + s += " "
142 + }
143 + s += argUsageText(arg)
144 + }
145 +
146 + return s
147 +}
148 +
149 +func argUsageText(arg cmds.Argument) string {
150 + s := arg.Name
151 +
152 + if arg.Required {
153 + s = fmt.Sprintf(requiredArg, s)
154 + } else {
155 + s = fmt.Sprintf(optionalArg, s)
156 + }
157 +
158 + if arg.Variadic {
159 + s = fmt.Sprintf(variadicArg, s)
160 + }
161 +
162 + return s
163 +}
164 +
165 +func align(lines []string) []string {
166 + longest := 0
167 + for _, line := range lines {
168 + length := len(line)
169 + if length > longest {
170 + longest = length
171 + }
172 + }
173 +
174 + for i, line := range lines {
175 + length := len(line)
176 + if length > 0 {
177 + lines[i] += strings.Repeat(" ", longest-length)
178 + }
179 + }
180 +
181 + return lines
182 +}
183 +
184 +func indent(lines []string, prefix string) []string {
185 + for i, line := range lines {
186 + lines[i] = prefix + indentString(line, prefix)
187 + }
188 + return lines
189 +}
190 +
191 +func indentString(line string, prefix string) string {
192 + return strings.Replace(line, "\n", "\n"+prefix, -1)
193 +}