1
2
3
4
5
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 "cmd/go/internal/modload"
21 )
22
23
24 func Help(w io.Writer, args []string) {
25
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
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
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)
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
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 "%-15s"}} {{.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
119
120 type commentWriter struct {
121 W io.Writer
122 wroteSlashes bool
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
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
165 func tmpl(w io.Writer, text string, data any) {
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
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 }
197
View as plain text