This repository was archived by the owner on Apr 14, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 22
/
Copy pathman.go
174 lines (147 loc) · 4.48 KB
/
man.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
package man
import (
"bytes"
"fmt"
"io"
"strings"
"time"
"github.com/cpuguy83/go-md2man/v2/md2man"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)
// Options specify the common properties of the man page.
type Options struct {
Header Header // General data.
Origin Origin // Data representing the origin of this man page.
SeeAlso []string // Links to other man pages, e.g. "ps(1)"
}
// Origin conveys data of the man page origin.
type Origin struct {
Source string // Origin of the man page.
Date time.Time // The Date when the man page was written.
}
// Header conveys general data of the man page.
type Header struct {
// Man page title.
Title string
// Man page section.
// Use "1" for General commands.
// Use "2" for System calls.
// Use "3" for Library functions, covering in particular the C standard library.
// Use "4" for Special files (usually devices, those found in /dev) and drivers.
// Use "5" for File formats and conventions.
// Use "6" for Games and screensavers.
// Use "7" for Miscellanea.
// Use "8" for System administration commands and daemons.
Section string
// Manual title.
Manual string
}
type mdBuffer struct {
*bytes.Buffer
}
func (buf *mdBuffer) printfln(format string, a ...interface{}) (int, error) {
return buf.WriteString(fmt.Sprintf(format+"\n", a...))
}
func (buf *mdBuffer) printline(s string) (int, error) {
return buf.WriteString(s + "\n")
}
func (buf *mdBuffer) boldln(s string) (int, error) {
return buf.printfln("**%s**", s)
}
func (buf *mdBuffer) header(title string) (int, error) {
return buf.printfln("# %s", title)
}
func (buf *mdBuffer) code(s string) (int, error) {
return buf.printfln("```\n%s\n```", s)
}
func newMdBuffer() *mdBuffer {
buf := new(mdBuffer)
buf.Buffer = new(bytes.Buffer)
return buf
}
// Generate writes the man page, taking the given command as root, to a writer.
func Generate(cmd *cobra.Command, options *Options, w io.Writer) error {
buf := newMdBuffer()
writeToBuf(buf, options, cmd)
return writeAsMan(buf, w)
}
func writeToBuf(buf *mdBuffer, options *Options, cmd *cobra.Command) {
writeMetadata(options, buf)
writeName(cmd.Name(), cmd.Short, buf)
writeSynopsis(cmd.UseLine(), buf)
writeDescription(cmd.Long, buf)
writeOptions(cmd.Flags(), buf)
writeCommands(cmd, buf)
writeExamples(cmd, buf)
writeExitStatus(buf)
writeSeeAlso(options.SeeAlso, buf)
}
func writeMetadata(options *Options, buf *mdBuffer) {
buf.printfln("%% %s(%s)%s", options.Header.Title, options.Header.Section, options.Origin.Date.Format("Jan 2006"))
buf.printfln("%% %s", options.Origin.Source)
buf.printfln("%% %s", options.Header.Manual)
}
func writeName(name, short string, buf *mdBuffer) {
buf.header("NAME")
buf.printfln("%s \\- %s", name, short)
}
func writeSynopsis(use string, buf *mdBuffer) {
buf.header("SYNOPSIS")
buf.boldln(use)
}
func writeDescription(description string, buf *mdBuffer) {
buf.header("DESCRIPTION")
buf.printline(description)
}
func writeOptions(flags *pflag.FlagSet, buf *mdBuffer) {
buf.header("OPTIONS")
flags.VisitAll(func(flag *pflag.Flag) {
writeOption(flag, buf)
})
}
func writeOption(flag *pflag.Flag, buf *mdBuffer) {
buf.printfln("**--%s**=%q\n\t%s\n", flag.Name, flag.DefValue, flag.Usage)
}
func writeCommands(cmd *cobra.Command, buf *mdBuffer) {
buf.header("COMMANDS")
buf.printline("The following commands are understood:\n")
writeCommandRecursive(cmd, buf)
}
func writeCommandRecursive(cmd *cobra.Command, buf *mdBuffer) {
if cmd.RunE != nil || cmd.Run != nil {
buf.printfln("**%s** - %s\n", cmd.CommandPath(), cmd.Short)
buf.printfln("\t\t%s\n", cmd.Long)
}
for _, sub := range cmd.Commands() {
writeCommandRecursive(sub, buf)
}
}
func writeExamples(cmd *cobra.Command, buf *mdBuffer) {
buf.header("EXAMPLES")
writeExampleRecursive(cmd, buf)
}
func writeExampleRecursive(cmd *cobra.Command, buf *mdBuffer) {
if cmd.Example != "" {
buf.boldln(cmd.Short)
buf.code(cmd.Example)
}
for _, sub := range cmd.Commands() {
writeExampleRecursive(sub, buf)
}
}
func writeExitStatus(buf *mdBuffer) {
buf.header("EXIT STATUS")
buf.printline("On success, 0 is returned, a non-zero failure code otherwise. " +
"If the return code is non-zero, look at the output to get a hint on what went wrong.")
}
func writeSeeAlso(sa []string, buf *mdBuffer) {
buf.header("SEE ALSO")
buf.boldln(strings.Join(sa, ", "))
}
func writeAsMan(buf *mdBuffer, w io.Writer) error {
bytesMarkdown := buf.Bytes()
bytesMan := md2man.Render(bytesMarkdown)
_, err := w.Write(bytesMan)
return err
}