github.com/goplus/igop@v0.25.0/cmd/internal/help/help.go (about) 1 // Copyright 2017 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Package help implements the ``igop help'' command. 6 package help 7 8 import ( 9 "bufio" 10 "fmt" 11 "io" 12 "log" 13 "os" 14 "strings" 15 "text/template" 16 "unicode" 17 "unicode/utf8" 18 19 "github.com/goplus/igop/cmd/internal/base" 20 ) 21 22 // Help implements the 'help' command. 23 func Help(w io.Writer, args []string) { 24 cmd := base.Igop 25 Args: 26 for i, arg := range args { 27 for _, sub := range cmd.Commands { 28 if sub.Name() == arg { 29 cmd = sub 30 continue Args 31 } 32 } 33 34 // helpSuccess is the help command using as many args as possible that would succeed. 35 helpSuccess := "igop help" 36 if i > 0 { 37 helpSuccess += " " + strings.Join(args[:i], " ") 38 } 39 fmt.Fprintf(os.Stderr, "igop help %s: unknown help topic. Run '%s'.\n", strings.Join(args, " "), helpSuccess) 40 os.Exit(2) 41 } 42 43 if len(cmd.Commands) > 0 { 44 PrintUsage(w, cmd) 45 } else { 46 cmd.Usage(w) 47 } 48 // not exit 2: succeeded at 'igop help cmd'. 49 return 50 } 51 52 var usageTemplate = `{{.Short | trim}} 53 54 Usage: 55 56 {{.UsageLine}} <command> [arguments] 57 58 The commands are: 59 {{range .Commands}}{{if or (.Runnable) .Commands}} 60 {{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}} 61 62 Use "igop help{{with .LongName}} {{.}}{{end}} <command>" for more information about a command. 63 64 ` 65 66 // commentWriter writes a Go comment to the underlying io.Writer, 67 // using line comment form (//). 68 type commentWriter struct { 69 W io.Writer 70 wroteSlashes bool // Wrote "//" at the beginning of the current line. 71 } 72 73 func (c *commentWriter) Write(p []byte) (int, error) { 74 var n int 75 for i, b := range p { 76 if !c.wroteSlashes { 77 s := "//" 78 if b != '\n' { 79 s = "// " 80 } 81 if _, err := io.WriteString(c.W, s); err != nil { 82 return n, err 83 } 84 c.wroteSlashes = true 85 } 86 n0, err := c.W.Write(p[i : i+1]) 87 n += n0 88 if err != nil { 89 return n, err 90 } 91 if b == '\n' { 92 c.wroteSlashes = false 93 } 94 } 95 return len(p), nil 96 } 97 98 // An errWriter wraps a writer, recording whether a write error occurred. 99 type errWriter struct { 100 w io.Writer 101 err error 102 } 103 104 func (w *errWriter) Write(b []byte) (int, error) { 105 n, err := w.w.Write(b) 106 if err != nil { 107 w.err = err 108 } 109 return n, err 110 } 111 112 // tmpl executes the given template text on data, writing the result to w. 113 func tmpl(w io.Writer, text string, data interface{}) { 114 t := template.New("top") 115 t.Funcs(template.FuncMap{"trim": strings.TrimSpace, "capitalize": capitalize}) 116 template.Must(t.Parse(text)) 117 ew := &errWriter{w: w} 118 err := t.Execute(ew, data) 119 if ew.err != nil { 120 // I/O error writing. Ignore write on closed pipe. 121 if strings.Contains(ew.err.Error(), "pipe") { 122 os.Exit(1) 123 } 124 log.Fatalf("writing output: %v", ew.err) 125 } 126 if err != nil { 127 panic(err) 128 } 129 } 130 131 func capitalize(s string) string { 132 if s == "" { 133 return s 134 } 135 r, n := utf8.DecodeRuneInString(s) 136 return string(unicode.ToTitle(r)) + s[n:] 137 } 138 139 // PrintUsage prints usage information. 140 func PrintUsage(w io.Writer, cmd *base.Command) { 141 bw := bufio.NewWriter(w) 142 tmpl(bw, usageTemplate, cmd) 143 bw.Flush() 144 }