1
2
3
4
5
6 package help
7
8 import (
9 "bufio"
10 "fmt"
11 "io"
12 "os"
13 "strings"
14 "text/template"
15 "unicode"
16 "unicode/utf8"
17
18 "cmd/go/internal/base"
19 "cmd/internal/telemetry/counter"
20 )
21
22 var counterErrorsHelpUnknownTopic = counter.New("go/errors:help-unknown-topic")
23
24
25 func Help(w io.Writer, args []string) {
26
27 if len(args) == 1 && args[0] == "documentation" {
28 fmt.Fprintln(w, "// Copyright 2011 The Go Authors. All rights reserved.")
29 fmt.Fprintln(w, "// Use of this source code is governed by a BSD-style")
30 fmt.Fprintln(w, "// license that can be found in the LICENSE file.")
31 fmt.Fprintln(w)
32 fmt.Fprintln(w, "// Code generated by 'go test cmd/go -v -run=^TestDocsUpToDate$ -fixdocs'; DO NOT EDIT.")
33 fmt.Fprintln(w, "// Edit the documentation in other files and then execute 'go generate cmd/go' to generate this one.")
34 fmt.Fprintln(w)
35 buf := new(strings.Builder)
36 PrintUsage(buf, base.Go)
37 usage := &base.Command{Long: buf.String()}
38 cmds := []*base.Command{usage}
39 for _, cmd := range base.Go.Commands {
40 cmds = append(cmds, cmd)
41 cmds = append(cmds, cmd.Commands...)
42 }
43 tmpl(&commentWriter{W: w}, documentationTemplate, cmds)
44 fmt.Fprintln(w, "package main")
45 return
46 }
47
48 cmd := base.Go
49 Args:
50 for i, arg := range args {
51 for _, sub := range cmd.Commands {
52 if sub.Name() == arg {
53 cmd = sub
54 continue Args
55 }
56 }
57
58
59 helpSuccess := "go help"
60 if i > 0 {
61 helpSuccess += " " + strings.Join(args[:i], " ")
62 }
63 counterErrorsHelpUnknownTopic.Inc()
64 fmt.Fprintf(os.Stderr, "go help %s: unknown help topic. Run '%s'.\n", strings.Join(args, " "), helpSuccess)
65 base.SetExitStatus(2)
66 base.Exit()
67 }
68
69 if len(cmd.Commands) > 0 {
70 PrintUsage(os.Stdout, cmd)
71 } else {
72 tmpl(os.Stdout, helpTemplate, cmd)
73 }
74
75 return
76 }
77
78 var usageTemplate = `{{.Long | trim}}
79
80 Usage:
81
82 {{.UsageLine}} <command> [arguments]
83
84 The commands are:
85 {{range .Commands}}{{if or (.Runnable) .Commands}}
86 {{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}
87
88 Use "go help{{with .LongName}} {{.}}{{end}} <command>" for more information about a command.
89 {{if eq (.UsageLine) "go"}}
90 Additional help topics:
91 {{range .Commands}}{{if and (not .Runnable) (not .Commands)}}
92 {{.Name | printf "%-15s"}} {{.Short}}{{end}}{{end}}
93
94 Use "go help{{with .LongName}} {{.}}{{end}} <topic>" for more information about that topic.
95 {{end}}
96 `
97
98 var helpTemplate = `{{if .Runnable}}usage: {{.UsageLine}}
99
100 {{end}}{{.Long | trim}}
101 `
102
103 var documentationTemplate = `{{range .}}{{if .Short}}{{.Short | capitalize}}
104
105 {{end}}{{if .Commands}}` + usageTemplate + `{{else}}{{if .Runnable}}Usage:
106
107 {{.UsageLine}}
108
109 {{end}}{{.Long | trim}}
110
111
112 {{end}}{{end}}`
113
114
115
116 type commentWriter struct {
117 W io.Writer
118 wroteSlashes bool
119 }
120
121 func (c *commentWriter) Write(p []byte) (int, error) {
122 var n int
123 for i, b := range p {
124 if !c.wroteSlashes {
125 s := "//"
126 if b != '\n' {
127 s = "// "
128 }
129 if _, err := io.WriteString(c.W, s); err != nil {
130 return n, err
131 }
132 c.wroteSlashes = true
133 }
134 n0, err := c.W.Write(p[i : i+1])
135 n += n0
136 if err != nil {
137 return n, err
138 }
139 if b == '\n' {
140 c.wroteSlashes = false
141 }
142 }
143 return len(p), nil
144 }
145
146
147 type errWriter struct {
148 w io.Writer
149 err error
150 }
151
152 func (w *errWriter) Write(b []byte) (int, error) {
153 n, err := w.w.Write(b)
154 if err != nil {
155 w.err = err
156 }
157 return n, err
158 }
159
160
161 func tmpl(w io.Writer, text string, data any) {
162 t := template.New("top")
163 t.Funcs(template.FuncMap{"trim": strings.TrimSpace, "capitalize": capitalize})
164 template.Must(t.Parse(text))
165 ew := &errWriter{w: w}
166 err := t.Execute(ew, data)
167 if ew.err != nil {
168
169 if strings.Contains(ew.err.Error(), "pipe") {
170 base.SetExitStatus(1)
171 base.Exit()
172 }
173 base.Fatalf("writing output: %v", ew.err)
174 }
175 if err != nil {
176 panic(err)
177 }
178 }
179
180 func capitalize(s string) string {
181 if s == "" {
182 return s
183 }
184 r, n := utf8.DecodeRuneInString(s)
185 return string(unicode.ToTitle(r)) + s[n:]
186 }
187
188 func PrintUsage(w io.Writer, cmd *base.Command) {
189 bw := bufio.NewWriter(w)
190 tmpl(bw, usageTemplate, cmd)
191 bw.Flush()
192 }
193
View as plain text