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