summaryrefslogtreecommitdiffhomepage
path: root/tempfork/pkgdoc/pkgdoc.go
diff options
context:
space:
mode:
Diffstat (limited to 'tempfork/pkgdoc/pkgdoc.go')
-rw-r--r--tempfork/pkgdoc/pkgdoc.go46
1 files changed, 41 insertions, 5 deletions
diff --git a/tempfork/pkgdoc/pkgdoc.go b/tempfork/pkgdoc/pkgdoc.go
index 1868b028e..cab38dd48 100644
--- a/tempfork/pkgdoc/pkgdoc.go
+++ b/tempfork/pkgdoc/pkgdoc.go
@@ -13,6 +13,7 @@ import (
"go/ast"
"go/build"
"go/doc"
+ "go/doc/comment"
"go/parser"
"go/token"
"io"
@@ -46,6 +47,31 @@ func (pkg *Package) ToText(w io.Writer, text, prefix, codePrefix string) {
w.Write(pr.Text(d))
}
+// ToMarkdown parses the godoc comment text and writes a Markdown rendering to w
+// suitable for a repository README.md: top-level sections become ## headings
+// without per-heading anchor IDs, and [Symbol] doc links resolve to pkg.go.dev,
+// including for symbols in the current package (which the default printer would
+// otherwise emit as bare #Name fragments with no backing anchor).
+func (pkg *Package) ToMarkdown(w io.Writer, text string) {
+ d := pkg.doc.Parser().Parse(text)
+ pr := pkg.doc.Printer()
+ pr.HeadingLevel = 2
+ pr.HeadingID = func(*comment.Heading) string { return "" }
+ pr.DocLinkBaseURL = "https://pkg.go.dev"
+ pr.DocLinkURL = func(link *comment.DocLink) string {
+ importPath := link.ImportPath
+ if importPath == "" {
+ importPath = pkg.doc.ImportPath
+ }
+ name := link.Name
+ if link.Recv != "" {
+ name = link.Recv + "." + name
+ }
+ return "https://pkg.go.dev/" + importPath + "#" + name
+ }
+ w.Write(pr.Markdown(d))
+}
+
// pkgBuffer is a wrapper for bytes.Buffer that prints a package clause the
// first time Write is called.
type pkgBuffer struct {
@@ -85,7 +111,10 @@ func parsePackage(writer io.Writer, pkg *build.Package, userPath string) *Packag
return slices.Contains(pkg.GoFiles, info.Name()) || slices.Contains(pkg.CgoFiles, info.Name())
}
fset := token.NewFileSet()
- pkgs, err := parser.ParseDir(fset, pkg.Dir, include, parser.ParseComments|parser.ImportsOnly)
+ // Parse declarations (not just imports) so that doc.Package knows the
+ // package's symbols; the Markdown printer needs this to resolve
+ // [Symbol] doc links in package comments.
+ pkgs, err := parser.ParseDir(fset, pkg.Dir, include, parser.ParseComments)
if err != nil {
log.Fatal(err)
}
@@ -144,10 +173,10 @@ func (pkg *Package) newlines(n int) {
}
}
-// packageDoc prints the docs for the package.
+// packageDoc prints the docs for the package as Markdown.
func (pkg *Package) packageDoc() {
pkg.Printf("") // Trigger the package clause; we know the package exists.
- pkg.ToText(&pkg.buf, pkg.doc.Doc, "", indent)
+ pkg.ToMarkdown(&pkg.buf, pkg.doc.Doc)
pkg.newlines(1)
pkg.bugs()
@@ -175,8 +204,12 @@ func (pkg *Package) bugs() {
}
}
-// PackageDoc generates documentation for a package in the given directory.
-func PackageDoc(dir string) ([]byte, error) {
+// PackageDoc generates Markdown documentation for the package in the given
+// directory. importPath is the full Go import path of that package (e.g.
+// "tailscale.com/tsnet"); it's used to render [Symbol] doc links to the
+// right pkg.go.dev URL. If importPath is empty, build.ImportDir's guess
+// is used (typically "." for module-based repos).
+func PackageDoc(dir, importPath string) ([]byte, error) {
var buf bytes.Buffer
var writer io.Writer = &buf
@@ -188,6 +221,9 @@ func PackageDoc(dir string) ([]byte, error) {
}
return nil, err
}
+ if importPath != "" {
+ buildPackage.ImportPath = importPath
+ }
userPath := dir
pkg := parsePackage(writer, buildPackage, userPath)