github.com/corona10/go@v0.0.0-20180224231303-7a218942be57/src/cmd/go/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 ``go help'' command. 6 package help 7 8 import ( 9 "bufio" 10 "bytes" 11 "fmt" 12 "io" 13 "os" 14 "strings" 15 "text/template" 16 "unicode" 17 "unicode/utf8" 18 19 "cmd/go/internal/base" 20 ) 21 22 // Help implements the 'help' command. 23 func Help(args []string) { 24 if len(args) == 0 { 25 PrintUsage(os.Stdout) 26 // not exit 2: succeeded at 'go help'. 27 return 28 } 29 if len(args) != 1 { 30 fmt.Fprintf(os.Stderr, "usage: go help command\n\nToo many arguments given.\n") 31 os.Exit(2) // failed at 'go help' 32 } 33 34 arg := args[0] 35 36 // 'go help documentation' generates doc.go. 37 if arg == "documentation" { 38 fmt.Println("// Copyright 2011 The Go Authors. All rights reserved.") 39 fmt.Println("// Use of this source code is governed by a BSD-style") 40 fmt.Println("// license that can be found in the LICENSE file.") 41 fmt.Println() 42 fmt.Println("// DO NOT EDIT THIS FILE. GENERATED BY mkalldocs.sh.") 43 fmt.Println("// Edit the documentation in other files and rerun mkalldocs.sh to generate this one.") 44 fmt.Println() 45 buf := new(bytes.Buffer) 46 PrintUsage(buf) 47 usage := &base.Command{Long: buf.String()} 48 tmpl(&commentWriter{W: os.Stdout}, documentationTemplate, append([]*base.Command{usage}, base.Commands...)) 49 fmt.Println("package main") 50 return 51 } 52 53 for _, cmd := range base.Commands { 54 if cmd.Name() == arg { 55 tmpl(os.Stdout, helpTemplate, cmd) 56 // not exit 2: succeeded at 'go help cmd'. 57 return 58 } 59 } 60 61 fmt.Fprintf(os.Stderr, "Unknown help topic %#q. Run 'go help'.\n", arg) 62 os.Exit(2) // failed at 'go help cmd' 63 } 64 65 var usageTemplate = `Go is a tool for managing Go source code. 66 67 Usage: 68 69 go command [arguments] 70 71 The commands are: 72 {{range .}}{{if .Runnable}} 73 {{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}} 74 75 Use "go help [command]" for more information about a command. 76 77 Additional help topics: 78 {{range .}}{{if not .Runnable}} 79 {{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}} 80 81 Use "go help [topic]" for more information about that topic. 82 83 ` 84 85 var helpTemplate = `{{if .Runnable}}usage: go {{.UsageLine}} 86 87 {{end}}{{.Long | trim}} 88 ` 89 90 var documentationTemplate = `{{range .}}{{if .Short}}{{.Short | capitalize}} 91 92 {{end}}{{if .Runnable}}Usage: 93 94 go {{.UsageLine}} 95 96 {{end}}{{.Long | trim}} 97 98 99 {{end}}` 100 101 // commentWriter writes a Go comment to the underlying io.Writer, 102 // using line comment form (//). 103 type commentWriter struct { 104 W io.Writer 105 wroteSlashes bool // Wrote "//" at the beginning of the current line. 106 } 107 108 func (c *commentWriter) Write(p []byte) (int, error) { 109 var n int 110 for i, b := range p { 111 if !c.wroteSlashes { 112 s := "//" 113 if b != '\n' { 114 s = "// " 115 } 116 if _, err := io.WriteString(c.W, s); err != nil { 117 return n, err 118 } 119 c.wroteSlashes = true 120 } 121 n0, err := c.W.Write(p[i : i+1]) 122 n += n0 123 if err != nil { 124 return n, err 125 } 126 if b == '\n' { 127 c.wroteSlashes = false 128 } 129 } 130 return len(p), nil 131 } 132 133 // An errWriter wraps a writer, recording whether a write error occurred. 134 type errWriter struct { 135 w io.Writer 136 err error 137 } 138 139 func (w *errWriter) Write(b []byte) (int, error) { 140 n, err := w.w.Write(b) 141 if err != nil { 142 w.err = err 143 } 144 return n, err 145 } 146 147 // tmpl executes the given template text on data, writing the result to w. 148 func tmpl(w io.Writer, text string, data interface{}) { 149 t := template.New("top") 150 t.Funcs(template.FuncMap{"trim": strings.TrimSpace, "capitalize": capitalize}) 151 template.Must(t.Parse(text)) 152 ew := &errWriter{w: w} 153 err := t.Execute(ew, data) 154 if ew.err != nil { 155 // I/O error writing. Ignore write on closed pipe. 156 if strings.Contains(ew.err.Error(), "pipe") { 157 os.Exit(1) 158 } 159 base.Fatalf("writing output: %v", ew.err) 160 } 161 if err != nil { 162 panic(err) 163 } 164 } 165 166 func capitalize(s string) string { 167 if s == "" { 168 return s 169 } 170 r, n := utf8.DecodeRuneInString(s) 171 return string(unicode.ToTitle(r)) + s[n:] 172 } 173 174 func PrintUsage(w io.Writer) { 175 bw := bufio.NewWriter(w) 176 tmpl(bw, usageTemplate, base.Commands) 177 bw.Flush() 178 }