1
0
mirror of https://github.com/golang/go synced 2024-09-30 22:58:34 -06:00

godoc: Add URLForSrcQuery option to godoc.Presentation.

This allows the creation of URLs to lines of source code with a query
term highlighted without assuming godoc source code URL parameters.
Needed for interfacing with other source code viewing servers.

R=bradfitz
CC=golang-dev
https://golang.org/cl/34200043
This commit is contained in:
Brad Garcia 2013-12-04 10:37:01 -05:00
parent df34f98521
commit ff7cfafc58
5 changed files with 137 additions and 16 deletions

View File

@ -22,6 +22,7 @@ import (
"os" "os"
pathpkg "path" pathpkg "path"
"regexp" "regexp"
"strconv"
"strings" "strings"
"text/template" "text/template"
"time" "time"
@ -80,6 +81,7 @@ func (p *Presentation) initFuncMap() {
"srcLink": srcLinkFunc, "srcLink": srcLinkFunc,
"posLink_url": newPosLink_urlFunc(srcPosLinkFunc), "posLink_url": newPosLink_urlFunc(srcPosLinkFunc),
"docLink": docLinkFunc, "docLink": docLinkFunc,
"queryLink": queryLinkFunc,
// formatting of Examples // formatting of Examples
"example_html": p.example_htmlFunc, "example_html": p.example_htmlFunc,
@ -96,6 +98,9 @@ func (p *Presentation) initFuncMap() {
if p.URLForSrcPos != nil { if p.URLForSrcPos != nil {
p.funcMap["posLink_url"] = newPosLink_urlFunc(p.URLForSrcPos) p.funcMap["posLink_url"] = newPosLink_urlFunc(p.URLForSrcPos)
} }
if p.URLForSrcQuery != nil {
p.funcMap["queryLink"] = p.URLForSrcQuery
}
} }
func filenameFunc(path string) string { func filenameFunc(path string) string {
@ -298,6 +303,19 @@ func srcLinkFunc(s string) string {
return pathpkg.Clean("/" + s) return pathpkg.Clean("/" + s)
} }
// queryLinkFunc returns a URL for a line in a source file with a highlighted
// query term.
// s is expected to be a path to a source file.
// query is expected to be a string that has already been appropriately escaped
// for use in a URL query.
func queryLinkFunc(s, query string, line int) string {
url := pathpkg.Clean("/"+s) + "?h=" + query
if line > 0 {
url += "#L" + strconv.Itoa(line)
}
return url
}
func docLinkFunc(s string, ident string) string { func docLinkFunc(s string, ident string) string {
s = strings.TrimPrefix(s, "/src") s = strings.TrimPrefix(s, "/src")
return pathpkg.Clean("/"+s) + "/#" + ident return pathpkg.Clean("/"+s) + "/#" + ident

90
godoc/godoc_test.go Normal file
View File

@ -0,0 +1,90 @@
// Copyright 2013 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 godoc
import (
"testing"
)
func TestPkgLinkFunc(t *testing.T) {
for _, tc := range []struct {
path string
want string
}{
{"/src/pkg/fmt", "pkg/fmt"},
{"/fmt", "pkg/fmt"},
} {
if got, want := pkgLinkFunc(tc.path), tc.want; got != want {
t.Errorf("pkgLinkFunc(%v) = %v; want %v", tc.path, got, want)
}
}
}
func TestSrcPosLinkFunc(t *testing.T) {
for _, tc := range []struct {
src string
line int
low int
high int
want string
}{
{"/src/pkg/fmt/print.go", 42, 30, 50, "/src/pkg/fmt/print.go?s=30:50#L32"},
{"/src/pkg/fmt/print.go", 2, 1, 5, "/src/pkg/fmt/print.go?s=1:5#L1"},
{"/src/pkg/fmt/print.go", 2, 0, 0, "/src/pkg/fmt/print.go#L2"},
{"/src/pkg/fmt/print.go", 0, 0, 0, "/src/pkg/fmt/print.go"},
{"/src/pkg/fmt/print.go", 0, 1, 5, "/src/pkg/fmt/print.go?s=1:5#L1"},
} {
if got, want := srcPosLinkFunc(tc.src, tc.line, tc.low, tc.high), tc.want; got != want {
t.Errorf("srcLinkFunc(%v, %v, %v, %v) = %v; want %v", tc.src, tc.line, tc.low, tc.high, got, want)
}
}
}
func TestSrcLinkFunc(t *testing.T) {
for _, tc := range []struct {
src string
want string
}{
{"/src/pkg/fmt/print.go", "/src/pkg/fmt/print.go"},
{"src/pkg/fmt/print.go", "/src/pkg/fmt/print.go"},
} {
if got, want := srcLinkFunc(tc.src), tc.want; got != want {
t.Errorf("srcLinkFunc(%v) = %v; want %v", tc.src, got, want)
}
}
}
func TestQueryLinkFunc(t *testing.T) {
for _, tc := range []struct {
src string
query string
line int
want string
}{
{"/src/pkg/fmt/print.go", "Sprintf", 33, "/src/pkg/fmt/print.go?h=Sprintf#L33"},
{"/src/pkg/fmt/print.go", "Sprintf", 0, "/src/pkg/fmt/print.go?h=Sprintf"},
{"src/pkg/fmt/print.go", "EOF", 33, "/src/pkg/fmt/print.go?h=EOF#L33"},
{"src/pkg/fmt/print.go", "a%3f+%26b", 1, "/src/pkg/fmt/print.go?h=a%3f+%26b#L1"},
} {
if got, want := queryLinkFunc(tc.src, tc.query, tc.line), tc.want; got != want {
t.Errorf("queryLinkFunc(%v, %v, %v) = %v; want %v", tc.src, tc.query, tc.line, got, want)
}
}
}
func TestDocLinkFunc(t *testing.T) {
for _, tc := range []struct {
src string
ident string
want string
}{
{"/src/pkg/fmt", "Sprintf", "/pkg/fmt/#Sprintf"},
{"/src/pkg/fmt", "EOF", "/pkg/fmt/#EOF"},
} {
if got, want := docLinkFunc(tc.src, tc.ident), tc.want; got != want {
t.Errorf("docLinkFunc(%v, %v) = %v; want %v", tc.src, tc.ident, got, want)
}
}
}

View File

@ -67,6 +67,15 @@ type Presentation struct {
// The source file argument has the form /src/pkg/<path>/<filename>. // The source file argument has the form /src/pkg/<path>/<filename>.
URLForSrcPos func(src string, line, low, high int) string URLForSrcPos func(src string, line, low, high int) string
// URLForSrcQuery optionally specifies a function to create a URL given a
// source file, a query string, and a line from the source file (1-based).
// The source file argument has the form /src/pkg/<path>/<filename>.
// The query argument will be escaped for the purposes of embedding in a URL
// query parameter.
// Ideally, the returned URL will be for the specified line of the file with
// the query string highlighted.
URLForSrcQuery func(src, query string, line int) string
initFuncMapOnce sync.Once initFuncMapOnce sync.Once
funcMap template.FuncMap funcMap template.FuncMap
templateFuncs template.FuncMap templateFuncs template.FuncMap

View File

@ -50,10 +50,11 @@
{{$pkg_html := pkgLink .Pak.Path | html}} {{$pkg_html := pkgLink .Pak.Path | html}}
<h3 id="Global_{{$pkg_html}}">package <a href="/{{$pkg_html}}">{{html .Pak.Name}}</a></h3> <h3 id="Global_{{$pkg_html}}">package <a href="/{{$pkg_html}}">{{html .Pak.Name}}</a></h3>
{{range .Files}} {{range .Files}}
{{$src_html := srcLink .File.Path | html}} {{$file := .File.Path}}
{{range .Groups}} {{range .Groups}}
{{range .}} {{range .}}
<a href="{{$src_html}}?h={{$query_url}}#L{{infoLine .}}">{{$src_html}}:{{infoLine .}}</a> {{$line := infoLine .}}
<a href="{{queryLink $file $query_url $line | html}}">{{$file}}:{{$line}}</a>
{{infoSnippet_html .}} {{infoSnippet_html .}}
{{end}} {{end}}
{{end}} {{end}}
@ -66,8 +67,8 @@
{{$pkg_html := pkgLink .Pak.Path | html}} {{$pkg_html := pkgLink .Pak.Path | html}}
<h3 id="Local_{{$pkg_html}}">package <a href="/{{$pkg_html}}">{{html .Pak.Name}}</a></h3> <h3 id="Local_{{$pkg_html}}">package <a href="/{{$pkg_html}}">{{html .Pak.Name}}</a></h3>
{{range .Files}} {{range .Files}}
{{$src_html := srcLink .File.Path | html}} {{$file := .File.Path}}
<a href="{{$src_html}}?h={{$query_url}}">{{$src_html}}</a> <a href="{{queryLink $file $query_url 0 | html}}">{{$file}}</a>
<table class="layout"> <table class="layout">
{{range .Groups}} {{range .Groups}}
<tr> <tr>
@ -76,7 +77,8 @@
<td align="left" width="4"></td> <td align="left" width="4"></td>
<td> <td>
{{range .}} {{range .}}
<a href="{{$src_html}}?h={{$query_url}}#L{{infoLine .}}">{{infoLine .}}</a> {{$line := infoLine .}}
<a href="{{queryLink $file $query_url $line | html}}">{{$line}}</a>
{{end}} {{end}}
</td> </td>
</tr> </tr>
@ -98,17 +100,17 @@
<p> <p>
<table class="layout"> <table class="layout">
{{range .}} {{range .}}
{{$src_html := srcLink .Filename | html}} {{$file := .Filename}}
<tr> <tr>
<td align="left" valign="top"> <td align="left" valign="top">
<a href="{{$src_html}}?h={{$query_url}}">{{$src_html}}</a>: <a href="{{queryLink $file $query_url 0}}">{{$file}}</a>:
</td> </td>
<td align="left" width="4"></td> <td align="left" width="4"></td>
<th align="left" valign="top">{{len .Lines}}</th> <th align="left" valign="top">{{len .Lines}}</th>
<td align="left" width="4"></td> <td align="left" width="4"></td>
<td align="left"> <td align="left">
{{range .Lines}} {{range .Lines}}
<a href="{{$src_html}}?h={{$query_url}}#L{{html .}}">{{html .}}</a> <a href="{{queryLink $file $query_url .}}">{{html .}}</a>
{{end}} {{end}}
{{if not $.Complete}} {{if not $.Complete}}
... ...

View File

@ -1413,10 +1413,11 @@ function PlaygroundOutput(el) {
{{$pkg_html := pkgLink .Pak.Path | html}} {{$pkg_html := pkgLink .Pak.Path | html}}
<h3 id="Global_{{$pkg_html}}">package <a href="/{{$pkg_html}}">{{html .Pak.Name}}</a></h3> <h3 id="Global_{{$pkg_html}}">package <a href="/{{$pkg_html}}">{{html .Pak.Name}}</a></h3>
{{range .Files}} {{range .Files}}
{{$src_html := srcLink .File.Path | html}} {{$file := .File.Path}}
{{range .Groups}} {{range .Groups}}
{{range .}} {{range .}}
<a href="{{$src_html}}?h={{$query_url}}#L{{infoLine .}}">{{$src_html}}:{{infoLine .}}</a> {{$line := infoLine .}}
<a href="{{queryLink $file $query_url $line | html}}">{{$file}}:{{$line}}</a>
{{infoSnippet_html .}} {{infoSnippet_html .}}
{{end}} {{end}}
{{end}} {{end}}
@ -1429,8 +1430,8 @@ function PlaygroundOutput(el) {
{{$pkg_html := pkgLink .Pak.Path | html}} {{$pkg_html := pkgLink .Pak.Path | html}}
<h3 id="Local_{{$pkg_html}}">package <a href="/{{$pkg_html}}">{{html .Pak.Name}}</a></h3> <h3 id="Local_{{$pkg_html}}">package <a href="/{{$pkg_html}}">{{html .Pak.Name}}</a></h3>
{{range .Files}} {{range .Files}}
{{$src_html := srcLink .File.Path | html}} {{$file := .File.Path}}
<a href="{{$src_html}}?h={{$query_url}}">{{$src_html}}</a> <a href="{{queryLink $file $query_url 0 | html}}">{{$file}}</a>
<table class="layout"> <table class="layout">
{{range .Groups}} {{range .Groups}}
<tr> <tr>
@ -1439,7 +1440,8 @@ function PlaygroundOutput(el) {
<td align="left" width="4"></td> <td align="left" width="4"></td>
<td> <td>
{{range .}} {{range .}}
<a href="{{$src_html}}?h={{$query_url}}#L{{infoLine .}}">{{infoLine .}}</a> {{$line := infoLine .}}
<a href="{{queryLink $file $query_url $line | html}}">{{$line}}</a>
{{end}} {{end}}
</td> </td>
</tr> </tr>
@ -1461,17 +1463,17 @@ function PlaygroundOutput(el) {
<p> <p>
<table class="layout"> <table class="layout">
{{range .}} {{range .}}
{{$src_html := srcLink .Filename | html}} {{$file := .Filename}}
<tr> <tr>
<td align="left" valign="top"> <td align="left" valign="top">
<a href="{{$src_html}}?h={{$query_url}}">{{$src_html}}</a>: <a href="{{queryLink $file $query_url 0}}">{{$file}}</a>:
</td> </td>
<td align="left" width="4"></td> <td align="left" width="4"></td>
<th align="left" valign="top">{{len .Lines}}</th> <th align="left" valign="top">{{len .Lines}}</th>
<td align="left" width="4"></td> <td align="left" width="4"></td>
<td align="left"> <td align="left">
{{range .Lines}} {{range .Lines}}
<a href="{{$src_html}}?h={{$query_url}}#L{{html .}}">{{html .}}</a> <a href="{{queryLink $file $query_url .}}">{{html .}}</a>
{{end}} {{end}}
{{if not $.Complete}} {{if not $.Complete}}
... ...