...
1
2
3
4
5 package comment
6
7 import (
8 "bytes"
9 "fmt"
10 "strings"
11 )
12
13
14
15
16
17 type Printer struct {
18
19
20
21
22 HeadingLevel int
23
24
25
26
27
28
29 HeadingID func(h *Heading) string
30
31
32
33 DocLinkURL func(link *DocLink) string
34
35
36
37
38 DocLinkBaseURL string
39
40
41
42 TextPrefix string
43
44
45
46
47
48 TextCodePrefix string
49
50
51
52
53
54
55 TextWidth int
56 }
57
58 func (p *Printer) headingLevel() int {
59 if p.HeadingLevel <= 0 {
60 return 3
61 }
62 return p.HeadingLevel
63 }
64
65 func (p *Printer) headingID(h *Heading) string {
66 if p.HeadingID == nil {
67 return h.DefaultID()
68 }
69 return p.HeadingID(h)
70 }
71
72 func (p *Printer) docLinkURL(link *DocLink) string {
73 if p.DocLinkURL != nil {
74 return p.DocLinkURL(link)
75 }
76 return link.DefaultURL(p.DocLinkBaseURL)
77 }
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97 func (l *DocLink) DefaultURL(baseURL string) string {
98 if l.ImportPath != "" {
99 slash := ""
100 if strings.HasSuffix(baseURL, "/") {
101 slash = "/"
102 } else {
103 baseURL += "/"
104 }
105 switch {
106 case l.Name == "":
107 return baseURL + l.ImportPath + slash
108 case l.Recv != "":
109 return baseURL + l.ImportPath + slash + "#" + l.Recv + "." + l.Name
110 default:
111 return baseURL + l.ImportPath + slash + "#" + l.Name
112 }
113 }
114 if l.Recv != "" {
115 return "#" + l.Recv + "." + l.Name
116 }
117 return "#" + l.Name
118 }
119
120
121
122
123
124
125
126
127 func (h *Heading) DefaultID() string {
128
129
130 var out strings.Builder
131 var p textPrinter
132 p.oneLongLine(&out, h.Text)
133 s := strings.TrimSpace(out.String())
134 if s == "" {
135 return ""
136 }
137 out.Reset()
138 out.WriteString("hdr-")
139 for _, r := range s {
140 if r < 0x80 && isIdentASCII(byte(r)) {
141 out.WriteByte(byte(r))
142 } else {
143 out.WriteByte('_')
144 }
145 }
146 return out.String()
147 }
148
149 type commentPrinter struct {
150 *Printer
151 headingPrefix string
152 needDoc map[string]bool
153 }
154
155
156
157 func (p *Printer) Comment(d *Doc) []byte {
158 cp := &commentPrinter{Printer: p}
159 var out bytes.Buffer
160 for i, x := range d.Content {
161 if i > 0 && blankBefore(x) {
162 out.WriteString("\n")
163 }
164 cp.block(&out, x)
165 }
166
167
168
169
170
171
172 for i := 0; i < 2; i++ {
173 used := i == 0
174 first := true
175 for _, def := range d.Links {
176 if def.Used == used {
177 if first {
178 out.WriteString("\n")
179 first = false
180 }
181 out.WriteString("[")
182 out.WriteString(def.Text)
183 out.WriteString("]: ")
184 out.WriteString(def.URL)
185 out.WriteString("\n")
186 }
187 }
188 }
189
190 return out.Bytes()
191 }
192
193
194
195 func blankBefore(x Block) bool {
196 if x, ok := x.(*List); ok {
197 return x.BlankBefore()
198 }
199 return true
200 }
201
202
203 func (p *commentPrinter) block(out *bytes.Buffer, x Block) {
204 switch x := x.(type) {
205 default:
206 fmt.Fprintf(out, "?%T", x)
207
208 case *Paragraph:
209 p.text(out, "", x.Text)
210 out.WriteString("\n")
211
212 case *Heading:
213 out.WriteString("# ")
214 p.text(out, "", x.Text)
215 out.WriteString("\n")
216
217 case *Code:
218 md := x.Text
219 for md != "" {
220 var line string
221 line, md, _ = strings.Cut(md, "\n")
222 if line != "" {
223 out.WriteString("\t")
224 out.WriteString(line)
225 }
226 out.WriteString("\n")
227 }
228
229 case *List:
230 loose := x.BlankBetween()
231 for i, item := range x.Items {
232 if i > 0 && loose {
233 out.WriteString("\n")
234 }
235 out.WriteString(" ")
236 if item.Number == "" {
237 out.WriteString(" - ")
238 } else {
239 out.WriteString(item.Number)
240 out.WriteString(". ")
241 }
242 for i, blk := range item.Content {
243 const fourSpace = " "
244 if i > 0 {
245 out.WriteString("\n" + fourSpace)
246 }
247 p.text(out, fourSpace, blk.(*Paragraph).Text)
248 out.WriteString("\n")
249 }
250 }
251 }
252 }
253
254
255 func (p *commentPrinter) text(out *bytes.Buffer, indent string, x []Text) {
256 for _, t := range x {
257 switch t := t.(type) {
258 case Plain:
259 p.indent(out, indent, string(t))
260 case Italic:
261 p.indent(out, indent, string(t))
262 case *Link:
263 if t.Auto {
264 p.text(out, indent, t.Text)
265 } else {
266 out.WriteString("[")
267 p.text(out, indent, t.Text)
268 out.WriteString("]")
269 }
270 case *DocLink:
271 out.WriteString("[")
272 p.text(out, indent, t.Text)
273 out.WriteString("]")
274 }
275 }
276 }
277
278
279
280 func (p *commentPrinter) indent(out *bytes.Buffer, indent, s string) {
281 for s != "" {
282 line, rest, ok := strings.Cut(s, "\n")
283 out.WriteString(line)
284 if ok {
285 out.WriteString("\n")
286 out.WriteString(indent)
287 }
288 s = rest
289 }
290 }
291
View as plain text