diff --git a/godoc/godoc.go b/godoc/godoc.go index 0e0bf713..d71498db 100644 --- a/godoc/godoc.go +++ b/godoc/godoc.go @@ -78,7 +78,7 @@ func (p *Presentation) initFuncMap() { // support for URL attributes "pkgLink": pkgLinkFunc, "srcLink": srcLinkFunc, - "posLink_url": posLink_urlFunc, + "posLink_url": newPosLink_urlFunc(srcPosLinkFunc), // formatting of Examples "example_html": p.example_htmlFunc, @@ -89,6 +89,12 @@ func (p *Presentation) initFuncMap() { // formatting of Notes "noteTitle": noteTitle, } + if p.URLForSrc != nil { + p.funcMap["srcLink"] = p.URLForSrc + } + if p.URLForSrcPos != nil { + p.funcMap["posLink_url"] = newPosLink_urlFunc(p.URLForSrcPos) + } } func filenameFunc(path string) string { @@ -232,37 +238,43 @@ func pkgLinkFunc(path string) string { return "pkg/" + relpath // remove trailing '/' for relative URL } -// n must be an ast.Node or a *doc.Note -func posLink_urlFunc(info *PageInfo, n interface{}) string { - var pos, end token.Pos +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 + return func(info *PageInfo, n interface{}) string { + var pos, end token.Pos - switch n := n.(type) { - case ast.Node: - pos = n.Pos() - end = n.End() - case *doc.Note: - pos = n.Pos - end = n.End - default: - panic(fmt.Sprintf("wrong type for posLink_url template formatter: %T", n)) - } - - var relpath string - var line int - var low, high int // selection offset range - - if pos.IsValid() { - p := info.FSet.Position(pos) - relpath = p.Filename - line = p.Line - low = p.Offset - } - if end.IsValid() { - high = info.FSet.Position(end).Offset + switch n := n.(type) { + case ast.Node: + pos = n.Pos() + end = n.End() + case *doc.Note: + pos = n.Pos + end = n.End + default: + panic(fmt.Sprintf("wrong type for posLink_url template formatter: %T", n)) + } + + var relpath string + var line int + var low, high int // selection offset range + + if pos.IsValid() { + p := info.FSet.Position(pos) + relpath = p.Filename + line = p.Line + low = p.Offset + } + if end.IsValid() { + high = info.FSet.Position(end).Offset + } + + return srcPosLinkFunc(relpath, line, low, high) } +} +func srcPosLinkFunc(s string, line, low, high int) string { var buf bytes.Buffer - template.HTMLEscape(&buf, []byte(relpath)) + template.HTMLEscape(&buf, []byte(s)) // selection ranges are of form "s=low:high" if low < high { fmt.Fprintf(&buf, "?s=%d:%d", low, high) // no need for URL escaping @@ -278,7 +290,6 @@ func posLink_urlFunc(info *PageInfo, n interface{}) string { if line > 0 { fmt.Fprintf(&buf, "#L%d", line) // no need for URL escaping } - return buf.String() } diff --git a/godoc/pres.go b/godoc/pres.go index 29b4432b..631b62c5 100644 --- a/godoc/pres.go +++ b/godoc/pres.go @@ -49,6 +49,19 @@ type Presentation struct { // value is provided. AdjustPageInfoMode func(req *http.Request, mode PageInfoMode) PageInfoMode + // URLForSrc optionally specifies a function that takes a source file and + // returns a URL for it. + // The source file argument has the form /src/pkg//. + URLForSrc func(src string) string + + // URLForSrcPos optionally specifies a function to create a URL given a + // source file, a line from the source file (1-based), and low & high offset + // positions (0-based, bytes from beginning of file). Ideally, the returned + // URL will be for the specified line of the file, while the high & low + // positions will be used to highlight a section of the file. + // The source file argument has the form /src/pkg//. + URLForSrcPos func(src string, line, low, high int) string + initFuncMapOnce sync.Once funcMap template.FuncMap templateFuncs template.FuncMap