godoc: add links to docs in text and dir pages
Fixes golang/go#17125 Change-Id: I22dd0561cd1c8eb30524797b6c0488d08a65285b Reviewed-on: https://go-review.googlesource.com/29279 Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
parent
34f7837286
commit
5128de7288
|
@ -79,11 +79,13 @@ func (p *Presentation) initFuncMap() {
|
||||||
"sanitize": sanitizeFunc,
|
"sanitize": sanitizeFunc,
|
||||||
|
|
||||||
// support for URL attributes
|
// support for URL attributes
|
||||||
"pkgLink": pkgLinkFunc,
|
"pkgLink": pkgLinkFunc,
|
||||||
"srcLink": srcLinkFunc,
|
"srcLink": srcLinkFunc,
|
||||||
"posLink_url": newPosLink_urlFunc(srcPosLinkFunc),
|
"posLink_url": newPosLink_urlFunc(srcPosLinkFunc),
|
||||||
"docLink": docLinkFunc,
|
"docLink": docLinkFunc,
|
||||||
"queryLink": queryLinkFunc,
|
"queryLink": queryLinkFunc,
|
||||||
|
"srcBreadcrumb": srcBreadcrumbFunc,
|
||||||
|
"srcToPkgLink": srcToPkgLinkFunc,
|
||||||
|
|
||||||
// formatting of Examples
|
// formatting of Examples
|
||||||
"example_html": p.example_htmlFunc,
|
"example_html": p.example_htmlFunc,
|
||||||
|
@ -459,6 +461,51 @@ func pkgLinkFunc(path string) string {
|
||||||
return "pkg/" + path
|
return "pkg/" + path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// srcToPkgLinkFunc builds an <a> tag linking to
|
||||||
|
// the package documentation of relpath.
|
||||||
|
func srcToPkgLinkFunc(relpath string) string {
|
||||||
|
relpath = pkgLinkFunc(relpath)
|
||||||
|
if relpath == "pkg/" {
|
||||||
|
return `<a href="/pkg">Index</a>`
|
||||||
|
}
|
||||||
|
if i := strings.LastIndex(relpath, "/"); i != -1 {
|
||||||
|
// Remove filename after last slash.
|
||||||
|
relpath = relpath[:i]
|
||||||
|
}
|
||||||
|
return fmt.Sprintf(`<a href="/%s">%s</a>`, relpath, relpath[len("pkg/"):])
|
||||||
|
}
|
||||||
|
|
||||||
|
// srcBreadcrumbFun converts each segment of relpath to a HTML <a>.
|
||||||
|
// Each segment links to its corresponding src directories.
|
||||||
|
func srcBreadcrumbFunc(relpath string) string {
|
||||||
|
segments := strings.Split(relpath, "/")
|
||||||
|
var buf bytes.Buffer
|
||||||
|
var selectedSegment string
|
||||||
|
var selectedIndex int
|
||||||
|
|
||||||
|
if strings.HasSuffix(relpath, "/") {
|
||||||
|
// relpath is a directory ending with a "/".
|
||||||
|
// Selected segment is the segment before the last slash.
|
||||||
|
selectedIndex = len(segments) - 2
|
||||||
|
selectedSegment = segments[selectedIndex] + "/"
|
||||||
|
} else {
|
||||||
|
selectedIndex = len(segments) - 1
|
||||||
|
selectedSegment = segments[selectedIndex]
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range segments[:selectedIndex] {
|
||||||
|
buf.WriteString(fmt.Sprintf(`<a href="/%s">%s</a>/`,
|
||||||
|
strings.Join(segments[:i+1], "/"),
|
||||||
|
segments[i],
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.WriteString(`<span class="text-muted">`)
|
||||||
|
buf.WriteString(selectedSegment)
|
||||||
|
buf.WriteString(`</span>`)
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
func newPosLink_urlFunc(srcPosLinkFunc func(s string, line, low, high int) string) func(info *PageInfo, n interface{}) string {
|
func newPosLink_urlFunc(srcPosLinkFunc func(s string, line, low, high int) string) func(info *PageInfo, n interface{}) string {
|
||||||
// n must be an ast.Node or a *doc.Note
|
// n must be an ast.Node or a *doc.Note
|
||||||
return func(info *PageInfo, n interface{}) string {
|
return func(info *PageInfo, n interface{}) string {
|
||||||
|
|
|
@ -290,3 +290,32 @@ func TestReplaceLeadingIndentation(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSrcBreadcrumbFunc(t *testing.T) {
|
||||||
|
for _, tc := range []struct {
|
||||||
|
path string
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{"src/", `<span class="text-muted">src/</span>`},
|
||||||
|
{"src/fmt/", `<a href="/src">src</a>/<span class="text-muted">fmt/</span>`},
|
||||||
|
{"src/fmt/print.go", `<a href="/src">src</a>/<a href="/src/fmt">fmt</a>/<span class="text-muted">print.go</span>`},
|
||||||
|
} {
|
||||||
|
if got := srcBreadcrumbFunc(tc.path); got != tc.want {
|
||||||
|
t.Errorf("srcBreadcrumbFunc(%v) = %v; want %v", tc.path, got, tc.want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSrcToPkgLinkFunc(t *testing.T) {
|
||||||
|
for _, tc := range []struct {
|
||||||
|
path string
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{"src/", `<a href="/pkg">Index</a>`},
|
||||||
|
{"src/fmt/", `<a href="/pkg/fmt">fmt</a>`},
|
||||||
|
} {
|
||||||
|
if got := srcToPkgLinkFunc(tc.path); got != tc.want {
|
||||||
|
t.Errorf("srcToPkgLinkFunc(%v) = %v; want %v", tc.path, got, tc.want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ type Page struct {
|
||||||
Title string
|
Title string
|
||||||
Tabtitle string
|
Tabtitle string
|
||||||
Subtitle string
|
Subtitle string
|
||||||
|
SrcPath string
|
||||||
Query string
|
Query string
|
||||||
Body []byte
|
Body []byte
|
||||||
Share bool
|
Share bool
|
||||||
|
|
|
@ -579,7 +579,8 @@ func (p *Presentation) serveTextFile(w http.ResponseWriter, r *http.Request, abs
|
||||||
fmt.Fprintf(&buf, `<p><a href="/%s?m=text">View as plain text</a></p>`, htmlpkg.EscapeString(relpath))
|
fmt.Fprintf(&buf, `<p><a href="/%s?m=text">View as plain text</a></p>`, htmlpkg.EscapeString(relpath))
|
||||||
|
|
||||||
p.ServePage(w, Page{
|
p.ServePage(w, Page{
|
||||||
Title: title + " " + relpath,
|
Title: title,
|
||||||
|
SrcPath: relpath,
|
||||||
Tabtitle: relpath,
|
Tabtitle: relpath,
|
||||||
Body: buf.Bytes(),
|
Body: buf.Bytes(),
|
||||||
Share: allowShare(r),
|
Share: allowShare(r),
|
||||||
|
@ -649,7 +650,8 @@ func (p *Presentation) serveDirectory(w http.ResponseWriter, r *http.Request, ab
|
||||||
}
|
}
|
||||||
|
|
||||||
p.ServePage(w, Page{
|
p.ServePage(w, Page{
|
||||||
Title: "Directory " + relpath,
|
Title: "Directory",
|
||||||
|
SrcPath: relpath,
|
||||||
Tabtitle: relpath,
|
Tabtitle: relpath,
|
||||||
Body: applyTemplate(p.DirlistHTML, "dirlistHTML", list),
|
Body: applyTemplate(p.DirlistHTML, "dirlistHTML", list),
|
||||||
Share: allowShare(r),
|
Share: allowShare(r),
|
||||||
|
|
|
@ -65,13 +65,23 @@ func main() {
|
||||||
<div id="page"{{if .Title}} class="wide"{{end}}>
|
<div id="page"{{if .Title}} class="wide"{{end}}>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
|
||||||
{{with .Title}}
|
{{if or .Title .SrcPath}}
|
||||||
<h1>{{html .}}</h1>
|
<h1>
|
||||||
|
{{html .Title}}
|
||||||
|
{{html .SrcPath | srcBreadcrumb}}
|
||||||
|
</h1>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{with .Subtitle}}
|
{{with .Subtitle}}
|
||||||
<h2>{{html .}}</h2>
|
<h2>{{html .}}</h2>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
|
{{with .SrcPath}}
|
||||||
|
<h2>
|
||||||
|
Documentation: {{html . | srcToPkgLink}}
|
||||||
|
</h2>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
{{/* The Table of Contents is automatically inserted in this <div>.
|
{{/* The Table of Contents is automatically inserted in this <div>.
|
||||||
Do not delete this <div>. */}}
|
Do not delete this <div>. */}}
|
||||||
<div id="nav"></div>
|
<div id="nav"></div>
|
||||||
|
|
|
@ -529,13 +529,23 @@ func main() {
|
||||||
<div id="page"{{if .Title}} class="wide"{{end}}>
|
<div id="page"{{if .Title}} class="wide"{{end}}>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
|
||||||
{{with .Title}}
|
{{if or .Title .SrcPath}}
|
||||||
<h1>{{html .}}</h1>
|
<h1>
|
||||||
|
{{html .Title}}
|
||||||
|
{{html .SrcPath | srcBreadcrumb}}
|
||||||
|
</h1>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{with .Subtitle}}
|
{{with .Subtitle}}
|
||||||
<h2>{{html .}}</h2>
|
<h2>{{html .}}</h2>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
|
{{with .SrcPath}}
|
||||||
|
<h2>
|
||||||
|
Documentation: {{html . | srcToPkgLink}}
|
||||||
|
</h2>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
{{/* The Table of Contents is automatically inserted in this <div>.
|
{{/* The Table of Contents is automatically inserted in this <div>.
|
||||||
Do not delete this <div>. */}}
|
Do not delete this <div>. */}}
|
||||||
<div id="nav"></div>
|
<div id="nav"></div>
|
||||||
|
@ -2996,6 +3006,9 @@ h1 {
|
||||||
font-size: 28px;
|
font-size: 28px;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
}
|
}
|
||||||
|
h1 .text-muted {
|
||||||
|
color:#777;
|
||||||
|
}
|
||||||
h2 {
|
h2 {
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
background: #E0EBF5;
|
background: #E0EBF5;
|
||||||
|
|
|
@ -101,6 +101,9 @@ h1 {
|
||||||
font-size: 28px;
|
font-size: 28px;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
}
|
}
|
||||||
|
h1 .text-muted {
|
||||||
|
color:#777;
|
||||||
|
}
|
||||||
h2 {
|
h2 {
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
background: #E0EBF5;
|
background: #E0EBF5;
|
||||||
|
|
Loading…
Reference in New Issue