// Copyright 2022 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.package commentimport ()// A Printer is a doc comment printer.// The fields in the struct can be filled in before calling// any of the printing methods// in order to customize the details of the printing process.typePrinterstruct {// HeadingLevel is the nesting level used for // HTML and Markdown headings. // If HeadingLevel is zero, it defaults to level 3, // meaning to use <h3> and ###. HeadingLevel int// HeadingID is a function that computes the heading ID // (anchor tag) to use for the heading h when generating // HTML and Markdown. If HeadingID returns an empty string, // then the heading ID is omitted. // If HeadingID is nil, h.DefaultID is used. HeadingID func(h *Heading) string// DocLinkURL is a function that computes the URL for the given DocLink. // If DocLinkURL is nil, then link.DefaultURL(p.DocLinkBaseURL) is used. DocLinkURL func(link *DocLink) string// DocLinkBaseURL is used when DocLinkURL is nil, // passed to [DocLink.DefaultURL] to construct a DocLink's URL. // See that method's documentation for details. DocLinkBaseURL string// TextPrefix is a prefix to print at the start of every line // when generating text output using the Text method. TextPrefix string// TextCodePrefix is the prefix to print at the start of each // preformatted (code block) line when generating text output, // instead of (not in addition to) TextPrefix. // If TextCodePrefix is the empty string, it defaults to TextPrefix+"\t". TextCodePrefix string// TextWidth is the maximum width text line to generate, // measured in Unicode code points, // excluding TextPrefix and the newline character. // If TextWidth is zero, it defaults to 80 minus the number of code points in TextPrefix. // If TextWidth is negative, there is no limit. TextWidth int}func ( *Printer) () int {if .HeadingLevel <= 0 {return3 }return .HeadingLevel}func ( *Printer) ( *Heading) string {if .HeadingID == nil {return .DefaultID() }return .HeadingID()}func ( *Printer) ( *DocLink) string {if .DocLinkURL != nil {return .DocLinkURL() }return .DefaultURL(.DocLinkBaseURL)}// DefaultURL constructs and returns the documentation URL for l,// using baseURL as a prefix for links to other packages.//// The possible forms returned by DefaultURL are:// - baseURL/ImportPath, for a link to another package// - baseURL/ImportPath#Name, for a link to a const, func, type, or var in another package// - baseURL/ImportPath#Recv.Name, for a link to a method in another package// - #Name, for a link to a const, func, type, or var in this package// - #Recv.Name, for a link to a method in this package//// If baseURL ends in a trailing slash, then DefaultURL inserts// a slash between ImportPath and # in the anchored forms.// For example, here are some baseURL values and URLs they can generate://// "/pkg/" → "/pkg/math/#Sqrt"// "/pkg" → "/pkg/math#Sqrt"// "/" → "/math/#Sqrt"// "" → "/math#Sqrt"func ( *DocLink) ( string) string {if .ImportPath != "" { := ""ifstrings.HasSuffix(, "/") { = "/" } else { += "/" }switch {case .Name == "":return + .ImportPath + case .Recv != "":return + .ImportPath + + "#" + .Recv + "." + .Namedefault:return + .ImportPath + + "#" + .Name } }if .Recv != "" {return"#" + .Recv + "." + .Name }return"#" + .Name}// DefaultID returns the default anchor ID for the heading h.//// The default anchor ID is constructed by converting every// rune that is not alphanumeric ASCII to an underscore// and then adding the prefix “hdr-”.// For example, if the heading text is “Go Doc Comments”,// the default ID is “hdr-Go_Doc_Comments”.func ( *Heading) () string {// Note: The “hdr-” prefix is important to avoid DOM clobbering attacks. // See https://pkg.go.dev/github.com/google/safehtml#Identifier.varstrings.BuildervartextPrinter .oneLongLine(&, .Text) := strings.TrimSpace(.String())if == "" {return"" } .Reset() .WriteString("hdr-")for , := range {if < 0x80 && isIdentASCII(byte()) { .WriteByte(byte()) } else { .WriteByte('_') } }return .String()}type commentPrinter struct { *Printer}// Comment returns the standard Go formatting of the [Doc],// without any comment markers.func ( *Printer) ( *Doc) []byte { := &commentPrinter{Printer: }varbytes.Bufferfor , := range .Content {if > 0 && blankBefore() { .WriteString("\n") } .block(&, ) }// Print one block containing all the link definitions that were used, // and then a second block containing all the unused ones. // This makes it easy to clean up the unused ones: gofmt and // delete the final block. And it's a nice visual signal without // affecting the way the comment formats for users.for := 0; < 2; ++ { := == 0 := truefor , := range .Links {if .Used == {if { .WriteString("\n") = false } .WriteString("[") .WriteString(.Text) .WriteString("]: ") .WriteString(.URL) .WriteString("\n") } } }return .Bytes()}// blankBefore reports whether the block x requires a blank line before it.// All blocks do, except for Lists that return false from x.BlankBefore().func blankBefore( Block) bool {if , := .(*List); {return .BlankBefore() }returntrue}// block prints the block x to out.func ( *commentPrinter) ( *bytes.Buffer, Block) {switch x := .(type) {default:fmt.Fprintf(, "?%T", )case *Paragraph: .text(, "", .Text) .WriteString("\n")case *Heading: .WriteString("# ") .text(, "", .Text) .WriteString("\n")case *Code: := .Textfor != "" {varstring , , _ = strings.Cut(, "\n")if != "" { .WriteString("\t") .WriteString() } .WriteString("\n") }case *List: := .BlankBetween()for , := range .Items {if > 0 && { .WriteString("\n") } .WriteString(" ")if .Number == "" { .WriteString(" - ") } else { .WriteString(.Number) .WriteString(". ") }for , := range .Content {const = " "if > 0 { .WriteString("\n" + ) } .text(, , .(*Paragraph).Text) .WriteString("\n") } } }}// text prints the text sequence x to out.func ( *commentPrinter) ( *bytes.Buffer, string, []Text) {for , := range {switch t := .(type) {casePlain: .indent(, , string())caseItalic: .indent(, , string())case *Link:if .Auto { .(, , .Text) } else { .WriteString("[") .(, , .Text) .WriteString("]") }case *DocLink: .WriteString("[") .(, , .Text) .WriteString("]") } }}// indent prints s to out, indenting with the indent string// after each newline in s.func ( *commentPrinter) ( *bytes.Buffer, , string) {for != "" { , , := strings.Cut(, "\n") .WriteString()if { .WriteString("\n") .WriteString() } = }}
The pages are generated with Goldsv0.7.0-preview. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.