diff --git a/cmd/golangorg/testdata/godev.txt b/cmd/golangorg/testdata/godev.txt
index 9d0ce4d5..8e7cffa2 100644
--- a/cmd/golangorg/testdata/godev.txt
+++ b/cmd/golangorg/testdata/godev.txt
@@ -123,3 +123,14 @@ body contains This content is part of the Go Wiki.
GET https://go.dev/wiki/Comments
body contains Go Wiki: Comments
body contains This content is part of the Go Wiki.
+
+GET https://go.dev/pkg/cmd/go/?m=old
+redirect == /cmd/go/?m=old
+
+GET https://go.dev/pkg/slices/?m=old
+body !contains href="/cmp
+body contains href="/pkg/cmp/?m=old#Compare
+
+GET https://go.dev/cmd/link/internal/ld/?m=old
+body !contains href="/pkg/cmd
+body contains href="/cmd/link/internal/loader/?m=old#Loader
diff --git a/internal/pkgdoc/doc.go b/internal/pkgdoc/doc.go
index ef1712a3..e95cde77 100644
--- a/internal/pkgdoc/doc.go
+++ b/internal/pkgdoc/doc.go
@@ -520,10 +520,15 @@ func (p *Page) ModeQuery() string {
}
func maybeRedirect(w http.ResponseWriter, r *http.Request) (redirected bool) {
+ r.URL.Host = ""
+ r.URL.Scheme = ""
canonical := path.Clean(r.URL.Path)
if !strings.HasSuffix(canonical, "/") {
canonical += "/"
}
+ if strings.HasPrefix(canonical, "/pkg/cmd/") {
+ canonical = canonical[len("/pkg"):]
+ }
if r.URL.Path != canonical {
url := *r.URL
url.Path = canonical
diff --git a/internal/pkgdoc/funcs.go b/internal/pkgdoc/funcs.go
index 66972281..f9b8dfee 100644
--- a/internal/pkgdoc/funcs.go
+++ b/internal/pkgdoc/funcs.go
@@ -10,6 +10,7 @@ import (
"fmt"
"go/ast"
"go/doc"
+ "go/doc/comment"
"go/format"
"go/printer"
"go/token"
@@ -154,8 +155,23 @@ func firstIdent(x []byte) string {
}
// Comment formats the given documentation comment as HTML.
-func (p *Page) Comment(comment string) template.HTML {
- return template.HTML(p.PDoc.HTML(comment))
+func (p *Page) Comment(text string) template.HTML {
+ pr := p.PDoc.Printer()
+ pr.DocLinkURL = func(link *comment.DocLink) string {
+ url := link.DefaultURL("/pkg/")
+ if strings.HasPrefix(url, "/pkg/cmd/") {
+ url = url[len("/pkg"):]
+ }
+ if p.OldDocs {
+ if base, frag, ok := strings.Cut(url, "#"); ok {
+ url = base + "?m=old#" + frag
+ } else {
+ url += "?m=old"
+ }
+ }
+ return url
+ }
+ return template.HTML(pr.HTML(p.PDoc.Parser().Parse(text)))
}
// sanitize sanitizes the argument src by replacing newlines with
diff --git a/internal/texthtml/ast.go b/internal/texthtml/ast.go
index c7e05606..1c755415 100644
--- a/internal/texthtml/ast.go
+++ b/internal/texthtml/ast.go
@@ -11,6 +11,7 @@ import (
"go/doc"
"go/token"
"strconv"
+ "strings"
"unicode"
"unicode/utf8"
)
@@ -24,13 +25,17 @@ type goLink struct {
}
func (l *goLink) tags() (start, end string) {
+ prefix := "/pkg/"
+ if strings.HasPrefix(l.path, "cmd/") {
+ prefix = "/"
+ }
switch {
case l.path != "" && l.name == "":
// package path
- return ``, ``
+ return ``, ``
case l.path != "" && l.name != "":
// qualified identifier
- return ``, ``
+ return ``, ``
case l.path == "" && l.name != "":
// local identifier
if l.isVal {