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.
5 // Package help implements the ``go help'' command.
19 "cmd/go/internal/base"
20 "cmd/go/internal/modload"
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.")
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.")
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() {
42 } else if cmd
.UsageLine
== "gopath-get" && !modload
.Enabled() {
45 cmds
= append(cmds
, cmd
)
46 cmds
= append(cmds
, cmd
.Commands
...)
48 tmpl(&commentWriter
{W
: w
}, documentationTemplate
, cmds
)
49 fmt
.Fprintln(w
, "package main")
55 for i
, arg
:= range args
{
56 for _
, sub
:= range cmd
.Commands
{
57 if sub
.Name() == arg
{
63 // helpSuccess is the help command using as many args as possible that would succeed.
64 helpSuccess
:= "go help"
66 helpSuccess
+= " " + strings
.Join(args
[:i
], " ")
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'
73 if len(cmd
.Commands
) > 0 {
74 PrintUsage(os
.Stdout
, cmd
)
76 tmpl(os
.Stdout
, helpTemplate
, cmd
)
78 // not exit 2: succeeded at 'go help cmd'.
82 var usageTemplate
= `{{.Long | trim}}
86 {{.UsageLine}} <command> [arguments]
89 {{range .Commands}}{{if or (.Runnable) .Commands}}
90 {{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}
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}}
98 Use "go help{{with .LongName}} {{.}}{{end}} <topic>" for more information about that topic.
102 var helpTemplate
= `{{if .Runnable}}usage: {{.UsageLine}}
104 {{end}}{{.Long | trim}}
107 var documentationTemplate
= `{{range .}}{{if .Short}}{{.Short | capitalize}}
109 {{end}}{{if .Commands}}` + usageTemplate
+ `{{else}}{{if .Runnable}}Usage:
113 {{end}}{{.Long | trim}}
118 // commentWriter writes a Go comment to the underlying io.Writer,
119 // using line comment form (//).
120 type commentWriter
struct {
122 wroteSlashes
bool // Wrote "//" at the beginning of the current line.
125 func (c
*commentWriter
) Write(p
[]byte) (int, error
) {
127 for i
, b
:= range p
{
133 if _
, err
:= io
.WriteString(c
.W
, s
); err
!= nil {
136 c
.wroteSlashes
= true
138 n0
, err
:= c
.W
.Write(p
[i
: i
+1])
144 c
.wroteSlashes
= false
150 // An errWriter wraps a writer, recording whether a write error occurred.
151 type errWriter
struct {
156 func (w
*errWriter
) Write(b
[]byte) (int, error
) {
157 n
, err
:= w
.w
.Write(b
)
164 // tmpl executes the given template text on data, writing the result to w.
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
)
172 // I/O error writing. Ignore write on closed pipe.
173 if strings
.Contains(ew
.err
.Error(), "pipe") {
174 base
.SetExitStatus(1)
177 base
.Fatalf("writing output: %v", ew
.err
)
184 func capitalize(s
string) string {
188 r
, n
:= utf8
.DecodeRuneInString(s
)
189 return string(unicode
.ToTitle(r
)) + s
[n
:]
192 func PrintUsage(w io
.Writer
, cmd
*base
.Command
) {
193 bw
:= bufio
.NewWriter(w
)
194 tmpl(bw
, usageTemplate
, cmd
)