github.com/gogf/gf/v2@v2.7.4/os/gcmd/gcmd_command_help.go (about) 1 // Copyright GoFrame Author(https://goframe.org). All Rights Reserved. 2 // 3 // This Source Code Form is subject to the terms of the MIT License. 4 // If a copy of the MIT was not distributed with this file, 5 // You can obtain one at https://github.com/gogf/gf. 6 // 7 8 package gcmd 9 10 import ( 11 "bytes" 12 "context" 13 "fmt" 14 "io" 15 "os" 16 17 "github.com/gogf/gf/v2/text/gstr" 18 ) 19 20 // Print prints help info to stdout for current command. 21 func (c *Command) Print() { 22 c.PrintTo(os.Stdout) 23 } 24 25 // PrintTo prints help info to custom io.Writer. 26 func (c *Command) PrintTo(writer io.Writer) { 27 var ( 28 prefix = gstr.Repeat(" ", 4) 29 buffer = bytes.NewBuffer(nil) 30 arguments = make([]Argument, len(c.Arguments)) 31 ) 32 // Copy options for printing. 33 copy(arguments, c.Arguments) 34 // Add built-in help option, just for info only. 35 arguments = append(arguments, defaultHelpOption) 36 37 // Usage. 38 if c.Usage != "" || c.Name != "" { 39 buffer.WriteString("USAGE\n") 40 buffer.WriteString(prefix) 41 if c.Usage != "" { 42 buffer.WriteString(c.Usage) 43 } else { 44 var ( 45 p = c 46 name = c.Name 47 ) 48 for p.parent != nil { 49 name = p.parent.Name + " " + name 50 p = p.parent 51 } 52 buffer.WriteString(name) 53 if len(c.commands) > 0 { 54 buffer.WriteString(` COMMAND`) 55 } 56 if c.hasArgumentFromIndex() { 57 buffer.WriteString(` ARGUMENT`) 58 } 59 buffer.WriteString(` [OPTION]`) 60 } 61 buffer.WriteString("\n\n") 62 } 63 // Command. 64 if len(c.commands) > 0 { 65 buffer.WriteString("COMMAND\n") 66 var ( 67 maxSpaceLength = 0 68 ) 69 for _, cmd := range c.commands { 70 if len(cmd.Name) > maxSpaceLength { 71 maxSpaceLength = len(cmd.Name) 72 } 73 } 74 for _, cmd := range c.commands { 75 var ( 76 spaceLength = maxSpaceLength - len(cmd.Name) 77 wordwrapPrefix = gstr.Repeat(" ", len(prefix+cmd.Name)+spaceLength+4) 78 ) 79 c.printLineBrief(printLineBriefInput{ 80 Buffer: buffer, 81 Name: cmd.Name, 82 Prefix: prefix, 83 Brief: gstr.Trim(cmd.Brief), 84 WordwrapPrefix: wordwrapPrefix, 85 SpaceLength: spaceLength, 86 }) 87 } 88 buffer.WriteString("\n") 89 } 90 91 // Argument. 92 if c.hasArgumentFromIndex() { 93 buffer.WriteString("ARGUMENT\n") 94 var ( 95 maxSpaceLength = 0 96 ) 97 for _, arg := range arguments { 98 if !arg.IsArg { 99 continue 100 } 101 if len(arg.Name) > maxSpaceLength { 102 maxSpaceLength = len(arg.Name) 103 } 104 } 105 for _, arg := range arguments { 106 if !arg.IsArg { 107 continue 108 } 109 var ( 110 spaceLength = maxSpaceLength - len(arg.Name) 111 wordwrapPrefix = gstr.Repeat(" ", len(prefix+arg.Name)+spaceLength+4) 112 ) 113 c.printLineBrief(printLineBriefInput{ 114 Buffer: buffer, 115 Name: arg.Name, 116 Prefix: prefix, 117 Brief: gstr.Trim(arg.Brief), 118 WordwrapPrefix: wordwrapPrefix, 119 SpaceLength: spaceLength, 120 }) 121 } 122 buffer.WriteString("\n") 123 } 124 125 // Option. 126 if c.hasArgumentFromOption() { 127 buffer.WriteString("OPTION\n") 128 var ( 129 nameStr string 130 maxSpaceLength = 0 131 ) 132 for _, arg := range arguments { 133 if arg.IsArg { 134 continue 135 } 136 if arg.Short != "" { 137 nameStr = fmt.Sprintf("-%s,--%s", arg.Short, arg.Name) 138 } else { 139 nameStr = fmt.Sprintf("-/--%s", arg.Name) 140 } 141 if len(nameStr) > maxSpaceLength { 142 maxSpaceLength = len(nameStr) 143 } 144 } 145 for _, arg := range arguments { 146 if arg.IsArg { 147 continue 148 } 149 if arg.Short != "" { 150 nameStr = fmt.Sprintf("-%s, --%s", arg.Short, arg.Name) 151 } else { 152 nameStr = fmt.Sprintf("-/--%s", arg.Name) 153 } 154 var ( 155 brief = gstr.Trim(arg.Brief) 156 spaceLength = maxSpaceLength - len(nameStr) 157 wordwrapPrefix = gstr.Repeat(" ", len(prefix+nameStr)+spaceLength+4) 158 ) 159 c.printLineBrief(printLineBriefInput{ 160 Buffer: buffer, 161 Name: nameStr, 162 Prefix: prefix, 163 Brief: brief, 164 WordwrapPrefix: wordwrapPrefix, 165 SpaceLength: spaceLength, 166 }) 167 } 168 buffer.WriteString("\n") 169 } 170 171 // Example. 172 if c.Examples != "" { 173 buffer.WriteString("EXAMPLE\n") 174 for _, line := range gstr.SplitAndTrim(gstr.Trim(c.Examples), "\n") { 175 buffer.WriteString(prefix) 176 buffer.WriteString(gstr.WordWrap(gstr.Trim(line), maxLineChars, "\n"+prefix)) 177 buffer.WriteString("\n") 178 } 179 buffer.WriteString("\n") 180 } 181 182 // Description. 183 if c.Description != "" { 184 buffer.WriteString("DESCRIPTION\n") 185 for _, line := range gstr.SplitAndTrim(gstr.Trim(c.Description), "\n") { 186 buffer.WriteString(prefix) 187 buffer.WriteString(gstr.WordWrap(gstr.Trim(line), maxLineChars, "\n"+prefix)) 188 buffer.WriteString("\n") 189 } 190 buffer.WriteString("\n") 191 } 192 193 // Additional. 194 if c.Additional != "" { 195 lineStr := gstr.WordWrap(gstr.Trim(c.Additional), maxLineChars, "\n") 196 buffer.WriteString(lineStr) 197 buffer.WriteString("\n") 198 } 199 content := buffer.String() 200 content = gstr.Replace(content, "\t", " ") 201 _, _ = writer.Write([]byte(content)) 202 } 203 204 type printLineBriefInput struct { 205 Buffer *bytes.Buffer 206 Name string 207 Prefix string 208 Brief string 209 WordwrapPrefix string 210 SpaceLength int 211 } 212 213 func (c *Command) printLineBrief(in printLineBriefInput) { 214 briefArray := gstr.SplitAndTrim(in.Brief, "\n") 215 if len(briefArray) == 0 { 216 // If command brief is empty, it just prints its command name. 217 briefArray = []string{""} 218 } 219 for i, line := range briefArray { 220 var lineStr string 221 if i == 0 { 222 lineStr = fmt.Sprintf( 223 "%s%s%s%s\n", 224 in.Prefix, in.Name, gstr.Repeat(" ", in.SpaceLength+4), line, 225 ) 226 } else { 227 lineStr = fmt.Sprintf( 228 "%s%s%s%s\n", 229 in.Prefix, gstr.Repeat(" ", len(in.Name)), gstr.Repeat(" ", in.SpaceLength+4), line, 230 ) 231 } 232 lineStr = gstr.WordWrap(lineStr, maxLineChars, "\n"+in.WordwrapPrefix) 233 in.Buffer.WriteString(lineStr) 234 } 235 } 236 237 func (c *Command) defaultHelpFunc(ctx context.Context, parser *Parser) error { 238 // Print command help info to stdout. 239 c.Print() 240 return nil 241 }