1
0
mirror of https://github.com/golang/go synced 2024-11-25 07:07:57 -07:00

godoc: remove last vestiges of old template system

- rename template funcs for better consistency and
  sort them into groups of related functionality
- try to be more consistent with html vs url escaping

R=r
CC=golang-dev
https://golang.org/cl/4887041
This commit is contained in:
Robert Griesemer 2011-08-12 15:43:10 -07:00
parent 5233c50321
commit 5c45e56898
7 changed files with 200 additions and 252 deletions

View File

@ -25,7 +25,7 @@
<form method="GET" action="/search"> <form method="GET" action="/search">
{{with .PkgRoots}} {{with .PkgRoots}}
{{range .PkgRoots}} {{range .PkgRoots}}
<a href="/pkg/{{html .}}">{{html .}}</a> <span class="sep">|</span> <a href="/pkg/{{url .}}">{{html .}}</a> <span class="sep">|</span>
{{end}} {{end}}
{{else}} {{else}}
References: References:

View File

@ -4,21 +4,21 @@
license that can be found in the LICENSE file. license that can be found in the LICENSE file.
--> -->
{{with .PAst}} {{with .PAst}}
<pre>{{html_node . $.FSet}}</pre> <pre>{{node_html . $.FSet}}</pre>
{{end}} {{end}}
{{with .PDoc}} {{with .PDoc}}
<!-- PackageName is printed as title by the top-level template --> <!-- PackageName is printed as title by the top-level template -->
{{if $.IsPkg}} {{if $.IsPkg}}
<p><code>import "{{html .ImportPath}}"</code></p> <p><code>import "{{html .ImportPath}}"</code></p>
{{end}} {{end}}
{{html_comment .Doc}} {{comment_html .Doc}}
{{if $.IsPkg}} {{if $.IsPkg}}
{{with .Filenames}} {{with .Filenames}}
<p> <p>
<h4>Package files</h4> <h4>Package files</h4>
<span style="font-size:90%"> <span style="font-size:90%">
{{range .}} {{range .}}
<a href="/{{url_src .}}">{{.|localname|html}}</a> <a href="/{{.|srcLink}}">{{.|filename|html}}</a>
{{end}} {{end}}
</span> </span>
</p> </p>
@ -27,58 +27,58 @@
{{with .Consts}} {{with .Consts}}
<h2 id="Constants">Constants</h2> <h2 id="Constants">Constants</h2>
{{range .}} {{range .}}
{{html_comment .Doc}} {{comment_html .Doc}}
<pre>{{html_node .Decl $.FSet}}</pre> <pre>{{node_html .Decl $.FSet}}</pre>
{{end}} {{end}}
{{end}} {{end}}
{{with .Vars}} {{with .Vars}}
<h2 id="Variables">Variables</h2> <h2 id="Variables">Variables</h2>
{{range .}} {{range .}}
{{html_comment .Doc}} {{comment_html .Doc}}
<pre>{{html_node .Decl $.FSet}}</pre> <pre>{{node_html .Decl $.FSet}}</pre>
{{end}} {{end}}
{{end}} {{end}}
{{with .Funcs}} {{with .Funcs}}
{{range .}} {{range .}}
{{/* Name is a string - no need for FSet */}} {{/* Name is a string - no need for FSet */}}
{{$name := html .Name}} {{$name := html .Name}}
<h2 id="{{$name}}">func <a href="/{{url_pos .Decl $.FSet}}">{{$name}}</a></h2> <h2 id="{{$name}}">func <a href="/{{posLink .Decl $.FSet}}">{{$name}}</a></h2>
<p><code>{{html_node .Decl $.FSet}}</code></p> <p><code>{{node_html .Decl $.FSet}}</code></p>
{{html_comment .Doc}} {{comment_html .Doc}}
{{end}} {{end}}
{{end}} {{end}}
{{with .Types}} {{with .Types}}
{{range .}} {{range .}}
{{$tname := html_node .Type.Name $.FSet}} {{$tname := node_html .Type.Name $.FSet}}
<h2 id="{{$tname}}">type <a href="/{{url_pos .Decl $.FSet}}">{{$tname}}</a></h2> <h2 id="{{$tname}}">type <a href="/{{posLink .Decl $.FSet}}">{{$tname}}</a></h2>
{{html_comment .Doc}} {{comment_html .Doc}}
<p><pre>{{html_node .Decl $.FSet}}</pre></p> <p><pre>{{node_html .Decl $.FSet}}</pre></p>
{{range .Consts}} {{range .Consts}}
{{html_comment .Doc}} {{comment_html .Doc}}
<pre>{{html_node .Decl $.FSet}}</pre> <pre>{{node_html .Decl $.FSet}}</pre>
{{end}} {{end}}
{{range .Vars}} {{range .Vars}}
{{html_comment .Doc}} {{comment_html .Doc}}
<pre>{{html_node .Decl $.FSet}}</pre> <pre>{{node_html .Decl $.FSet}}</pre>
{{end}} {{end}}
{{range .Factories}} {{range .Factories}}
{{$name := html .Name}} {{$name := html .Name}}
<h3 id="{{$tname}}.{{$name}}">func <a href="/{{url_pos .Decl $.FSet}}">{{$name}}</a></h3> <h3 id="{{$tname}}.{{$name}}">func <a href="/{{posLink .Decl $.FSet}}">{{$name}}</a></h3>
<p><code>{{html_node .Decl $.FSet}}</code></p> <p><code>{{node_html .Decl $.FSet}}</code></p>
{{html_comment .Doc}} {{comment_html .Doc}}
{{end}} {{end}}
{{range .Methods}} {{range .Methods}}
{{$name := html .Name}} {{$name := html .Name}}
<h3 id="{{$tname}}.{{$name}}">func ({{html_node .Recv $.FSet}}) <a href="/{{url_pos .Decl $.FSet}}">{{$name}}</a></h3> <h3 id="{{$tname}}.{{$name}}">func ({{node_html .Recv $.FSet}}) <a href="/{{posLink .Decl $.FSet}}">{{$name}}</a></h3>
<p><code>{{html_node .Decl $.FSet}}</code></p> <p><code>{{node_html .Decl $.FSet}}</code></p>
{{html_comment .Doc}} {{comment_html .Doc}}
{{end}} {{end}}
{{end}} {{end}}
{{end}} {{end}}
{{with .Bugs}} {{with .Bugs}}
<h2 id="Bugs">Bugs</h2> <h2 id="Bugs">Bugs</h2>
{{range .}} {{range .}}
{{html_comment .}} {{comment_html .}}
{{end}} {{end}}
{{end}} {{end}}
{{end}} {{end}}

View File

@ -2,7 +2,7 @@
--------------------------------------- ---------------------------------------
*/}}{{with .PAst}}{{text_node . $FSet}}{{end}}{{/* */}}{{with .PAst}}{{node . $FSet}}{{end}}{{/*
--------------------------------------- ---------------------------------------
@ -16,7 +16,7 @@ import "{{.ImportPath}}"
--------------------------------------- ---------------------------------------
*/}}{{with .Doc}}{{text_node . $FSet}} */}}{{with .Doc}}{{node . $FSet}}
{{end}}{{/* {{end}}{{/*
--------------------------------------- ---------------------------------------
@ -24,7 +24,7 @@ import "{{.ImportPath}}"
*/}}{{with .Consts}} */}}{{with .Consts}}
CONSTANTS CONSTANTS
{{range .}}{{text_node .Decl $FSet}} {{range .}}{{node .Decl $FSet}}
{{.Doc}}{{end}} {{.Doc}}{{end}}
{{end}}{{/* {{end}}{{/*
@ -33,7 +33,7 @@ CONSTANTS
*/}}{{with .Vars}} */}}{{with .Vars}}
VARIABLES VARIABLES
{{range .}}{{text_node .Decl $FSet}} {{range .}}{{node .Decl $FSet}}
{{.Doc}}{{end}} {{.Doc}}{{end}}
{{end}}{{/* {{end}}{{/*
@ -42,7 +42,7 @@ VARIABLES
*/}}{{with .Funcs}} */}}{{with .Funcs}}
FUNCTIONS FUNCTIONS
{{range .}}{{text_node .Decl $FSet}} {{range .}}{{node .Decl $FSet}}
{{.Doc}} {{.Doc}}
{{end}}{{end}}{{/* {{end}}{{end}}{{/*
@ -51,15 +51,15 @@ FUNCTIONS
*/}}{{with .Types}} */}}{{with .Types}}
TYPES TYPES
{{range .}}{{text_node .Decl $FSet}} {{range .}}{{node .Decl $FSet}}
{{.Doc}} {{.Doc}}
{{range .Consts}}{{text_node .Decl $FSet}} {{range .Consts}}{{node .Decl $FSet}}
{{.Doc}} {{.Doc}}
{{end}}{{range .Vars}}{{text_node .Decl $FSet}} {{end}}{{range .Vars}}{{node .Decl $FSet}}
{{.Doc}} {{.Doc}}
{{end}}{{range .Factories}}{{text_node .Decl $FSet}} {{end}}{{range .Factories}}{{node .Decl $FSet}}
{{.Doc}} {{.Doc}}
{{end}}{{range .Methods}}{{text_node .Decl $FSet}} {{end}}{{range .Methods}}{{node .Decl $FSet}}
{{.Doc}} {{.Doc}}
{{end}}{{end}}{{end}}{{/* {{end}}{{end}}{{end}}{{/*

View File

@ -3,10 +3,9 @@
Use of this source code is governed by a BSD-style Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file. license that can be found in the LICENSE file.
--> -->
{{$SearchResult := .}}
{{with .Alert}} {{with .Alert}}
<p> <p>
<span class="alert" style="font-size:120%">{{.}}</span> <span class="alert" style="font-size:120%">{{html .}}</span>
</p> </p>
{{end}} {{end}}
{{with .Alt}} {{with .Alt}}
@ -21,13 +20,14 @@
{{with .Decls}} {{with .Decls}}
<h2 id="Global">Package-level declarations</h2> <h2 id="Global">Package-level declarations</h2>
{{range .}} {{range .}}
<h3 id="Global_{{url_pkg .Pak.Path}}">package <a href="/{{url_pkg .Pak.Path}}">{{html .Pak.Name}}</a></h3> {{$pkg := pkgLink .Pak.Path}}
<h3 id="Global_{{html $pkg}}">package <a href="/{{url $pkg}}">{{html .Pak.Name}}</a></h3>
{{range .Files}} {{range .Files}}
{{$path := url_src .File.Path}} {{$src := srcLink .File.Path}}
{{range .Groups}} {{range .Groups}}
{{range .Infos}} {{range .Infos}}
<a href="/{{$path}}?h={{url $SearchResult.Query}}#L{{infoLine .}}">{{$path}}:{{infoLine .}}</a> <a href="/{{url $src}}?h={{url $.Query}}#L{{infoLine .}}">{{html $src}}:{{infoLine .}}</a>
{{infoSnippet .}} {{infoSnippet_html .}}
{{end}} {{end}}
{{end}} {{end}}
{{end}} {{end}}
@ -36,19 +36,20 @@
{{with .Others}} {{with .Others}}
<h2 id="Local">Local declarations and uses</h2> <h2 id="Local">Local declarations and uses</h2>
{{range .}} {{range .}}
<h3 id="Local_{{url_pkg .Pak.Path}}">package <a href="/{{url_pkg .Pak.Path}}">{{html .Pak.Name}}</a></h3> {{$pkg := pkgLink .Pak.Path}}
<h3 id="Local_{{html $pkg}}">package <a href="/{{url $pkg}}">{{html .Pak.Name}}</a></h3>
{{range .Files}} {{range .Files}}
{{$path := url_src .File.Path}} {{$src := srcLink .File.Path}}
<a href="/{{$path}}?h={{url $SearchResult.Query}}">{{$path}}</a> <a href="/{{url $src}}?h={{url $.Query}}">{{html $src}}</a>
<table class="layout"> <table class="layout">
{{range .Groups}} {{range .Groups}}
<tr> <tr>
<td width="25"></td> <td width="25"></td>
<th align="left" valign="top">{{infoKind .Kind}}</th> <th align="left" valign="top">{{infoKind_html .Kind}}</th>
<td align="left" width="4"></td> <td align="left" width="4"></td>
<td> <td>
{{range .Infos}} {{range .Infos}}
<a href="/{{$path}}?h={{url $SearchResult.Query}}#L{{infoLine .}}">{{infoLine .}}</a> <a href="/{{url $src}}?h={{url $.Query}}#L{{infoLine .}}">{{infoLine .}}</a>
{{end}} {{end}}
</td> </td>
</tr> </tr>
@ -59,36 +60,36 @@
{{end}} {{end}}
{{end}} {{end}}
{{with .Textual}} {{with .Textual}}
{{if $SearchResult.Complete}} {{if $.Complete}}
<h2 id="Textual">{{html $SearchResult.Found}} textual occurrences</h2> <h2 id="Textual">{{html $.Found}} textual occurrences</h2>
{{else}} {{else}}
<h2 id="Textual">More than {{html $SearchResult.Found}} textual occurrences</h2> <h2 id="Textual">More than {{html $.Found}} textual occurrences</h2>
<p> <p>
<span class="alert" style="font-size:120%">Not all files or lines containing "{{html $SearchResult.Query}}" are shown.</span> <span class="alert" style="font-size:120%">Not all files or lines containing "{{html $.Query}}" are shown.</span>
</p> </p>
{{end}} {{end}}
<p> <p>
<table class="layout"> <table class="layout">
{{range .}} {{range .}}
{{$path := url_src .Filename}} {{$src := srcLink .Filename}}
<tr> <tr>
<td align="left" valign="top"> <td align="left" valign="top">
<a href="/{{$path}}?h={{url $SearchResult.Query}}">{{$path}}</a>: <a href="/{{url $src}}?h={{url $.Query}}">{{html $src}}</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="/{{$path}}?h={{url $SearchResult.Query}}#L{{url .}}">{{html .}}</a> <a href="/{{url $src}}?h={{url $.Query}}#L{{url .}}">{{html .}}</a>
{{end}} {{end}}
{{if not $SearchResult.Complete}} {{if not $.Complete}}
... ...
{{end}} {{end}}
</td> </td>
</tr> </tr>
{{end}} {{end}}
{{if not $SearchResult.Complete}} {{if not $.Complete}}
<tr><td align="left">...</td></tr> <tr><td align="left">...</td></tr>
{{end}} {{end}}
</table> </table>

View File

@ -17,7 +17,7 @@ DID YOU MEAN
PACKAGE-LEVEL DECLARATIONS PACKAGE-LEVEL DECLARATIONS
{{range .}}package {{.Pak.Name}} {{range .}}package {{.Pak.Name}}
{{range $File := .Files}}{{range .Groups}}{{range .Infos}} {{url_src $File.File.Path}}:{{infoLine .}}{{end}} {{range $File := .Files}}{{range .Groups}}{{range .Infos}} {{srcLink $File.File.Path}}:{{infoLine .}}{{end}}
{{end}}{{end}}{{/* .Files */}} {{end}}{{end}}{{/* .Files */}}
{{end}}{{end}}{{/* .Decls */}}{{/* {{end}}{{end}}{{/* .Decls */}}{{/*
@ -27,7 +27,7 @@ PACKAGE-LEVEL DECLARATIONS
LOCAL DECLARATIONS AND USES LOCAL DECLARATIONS AND USES
{{range .}}package {{.Pak.Name}} {{range .}}package {{.Pak.Name}}
{{range $File := .Files}}{{range .Groups}}{{range .Infos}} {{url_src $File.File.Path}}:{{infoLine .}} {{range $File := .Files}}{{range .Groups}}{{range .Infos}} {{srcLink $File.File.Path}}:{{infoLine .}}
{{end}}{{end}}{{end}}{{/* .Files */}} {{end}}{{end}}{{end}}{{/* .Files */}}
{{end}}{{end}}{{/* .Others */}}{{end}}{{/* .Hit */}}{{/* {{end}}{{end}}{{/* .Others */}}{{end}}{{/* .Hit */}}{{/*
@ -35,6 +35,6 @@ LOCAL DECLARATIONS AND USES
*/}}{{if .Textual}}{{if .Complete}}{{.Found}} TEXTUAL OCCURRENCES{{else}}MORE THAN {{.Found}} TEXTUAL OCCURRENCES{{end}} */}}{{if .Textual}}{{if .Complete}}{{.Found}} TEXTUAL OCCURRENCES{{else}}MORE THAN {{.Found}} TEXTUAL OCCURRENCES{{end}}
{{range .Textual}}{{len .Lines}} {{url_src .Filename}} {{range .Textual}}{{len .Lines}} {{srcLink .Filename}}
{{end}}{{if not .Complete}}... ... {{end}}{{if not .Complete}}... ...
{{end}}{{end}} {{end}}{{end}}

View File

@ -371,176 +371,9 @@ func writeNode(w io.Writer, fset *token.FileSet, x interface{}) {
(&printer.Config{mode, *tabwidth}).Fprint(&tconv{output: w}, fset, x) (&printer.Config{mode, *tabwidth}).Fprint(&tconv{output: w}, fset, x)
} }
func fileset(x []interface{}) *token.FileSet { func filenameFunc(path string) string {
if len(x) > 1 { _, localname := filepath.Split(path)
if fset, ok := x[1].(*token.FileSet); ok { return localname
return fset
}
}
return nil
}
// Template formatter for the various "url-xxx" formats excluding url-esc.
func urlFmt(w io.Writer, format string, x ...interface{}) {
var path string
var line int
var low, high int // selection
// determine path and position info, if any
type positioner interface {
Pos() token.Pos
End() token.Pos
}
switch t := x[0].(type) {
case string:
path = t
case positioner:
fset := fileset(x)
if p := t.Pos(); p.IsValid() {
pos := fset.Position(p)
path = pos.Filename
line = pos.Line
low = pos.Offset
}
if p := t.End(); p.IsValid() {
high = fset.Position(p).Offset
}
default:
// we should never reach here, but be resilient
// and assume the position is invalid (empty path,
// and line 0)
log.Printf("INTERNAL ERROR: urlFmt(%s) without a string or positioner", format)
}
// map path
relpath := relativeURL(path)
// convert to relative URLs so that they can also
// be used as relative file names in .txt templates
switch format {
default:
// we should never reach here, but be resilient
// and assume the url-pkg format instead
log.Printf("INTERNAL ERROR: urlFmt(%s)", format)
fallthrough
case "url_pkg":
// because of the irregular mapping under goroot
// we need to correct certain relative paths
if strings.HasPrefix(relpath, "src/pkg/") {
relpath = relpath[len("src/pkg/"):]
}
template.HTMLEscape(w, []byte(pkgHandler.pattern[1:]+relpath)) // remove trailing '/' for relative URL
case "url_src":
template.HTMLEscape(w, []byte(relpath))
case "url_pos":
template.HTMLEscape(w, []byte(relpath))
// selection ranges are of form "s=low:high"
if low < high {
fmt.Fprintf(w, "?s=%d:%d", low, high)
// if we have a selection, position the page
// such that the selection is a bit below the top
line -= 10
if line < 1 {
line = 1
}
}
// line id's in html-printed source are of the
// form "L%d" where %d stands for the line number
if line > 0 {
fmt.Fprintf(w, "#L%d", line)
}
}
}
// The strings in infoKinds must be properly html-escaped.
var infoKinds = [nKinds]string{
PackageClause: "package&nbsp;clause",
ImportDecl: "import&nbsp;decl",
ConstDecl: "const&nbsp;decl",
TypeDecl: "type&nbsp;decl",
VarDecl: "var&nbsp;decl",
FuncDecl: "func&nbsp;decl",
MethodDecl: "method&nbsp;decl",
Use: "use",
}
// Template formatter for "infoKind" format.
func infoKindFmt(w io.Writer, format string, x ...interface{}) {
fmt.Fprintf(w, infoKinds[x[0].(SpotKind)]) // infoKind entries are html-escaped
}
// Template formatter for "infoLine" format.
func infoLineFmt(w io.Writer, format string, x ...interface{}) {
info := x[0].(SpotInfo)
line := info.Lori()
if info.IsIndex() {
index, _ := searchIndex.get()
if index != nil {
line = index.(*Index).Snippet(line).Line
} else {
// no line information available because
// we don't have an index - this should
// never happen; be conservative and don't
// crash
line = 0
}
}
fmt.Fprintf(w, "%d", line)
}
// Template formatter for "infoSnippet" format.
func infoSnippetFmt(w io.Writer, format string, x ...interface{}) {
info := x[0].(SpotInfo)
text := []byte(`<span class="alert">no snippet text available</span>`)
if info.IsIndex() {
index, _ := searchIndex.get()
// no escaping of snippet text needed;
// snippet text is escaped when generated
text = index.(*Index).Snippet(info.Lori()).Text
}
w.Write(text)
}
// TODO(gri): Remove this type once fmtMap2funcMap is gone.
type FormatterMap map[string]func(io.Writer, string, ...interface{})
// TODO(gri): Remove the need for this conversion function by rewriting
// the old template formatters into new template functions.
func append2funcMap(funcMap template.FuncMap, fmtMap FormatterMap) template.FuncMap {
for n, f := range fmtMap {
name, fmt := n, f // separate instance of name, fmt for each closure!
if _, ok := funcMap[name]; ok {
panic("function already in map: " + name)
}
funcMap[name] = func(args ...interface{}) string {
var buf bytes.Buffer
fmt(&buf, name, args...)
return buf.String()
}
}
return funcMap
}
func textNodeFunc(node interface{}, fset *token.FileSet) string {
var buf bytes.Buffer
writeNode(&buf, fset, node)
return buf.String()
}
func htmlNodeFunc(node interface{}, fset *token.FileSet) string {
var buf1 bytes.Buffer
writeNode(&buf1, fset, node)
var buf2 bytes.Buffer
FormatText(&buf2, buf1.Bytes(), -1, true, "", nil)
return buf2.String()
}
func htmlCommentFunc(comment string) string {
var buf bytes.Buffer
// TODO(gri) Provide list of words (e.g. function parameters)
// to be emphasized by ToHTML.
doc.ToHTML(&buf, []byte(comment), nil) // does html-escaping
return buf.String()
} }
func fileInfoNameFunc(fi FileInfo) string { func fileInfoNameFunc(fi FileInfo) string {
@ -558,27 +391,144 @@ func fileInfoTimeFunc(fi FileInfo) string {
return "" // don't return epoch if time is obviously not set return "" // don't return epoch if time is obviously not set
} }
func localnameFunc(path string) string { // The strings in infoKinds must be properly html-escaped.
_, localname := filepath.Split(path) var infoKinds = [nKinds]string{
return localname PackageClause: "package&nbsp;clause",
ImportDecl: "import&nbsp;decl",
ConstDecl: "const&nbsp;decl",
TypeDecl: "type&nbsp;decl",
VarDecl: "var&nbsp;decl",
FuncDecl: "func&nbsp;decl",
MethodDecl: "method&nbsp;decl",
Use: "use",
} }
var fmap = append2funcMap(template.FuncMap{ func infoKind_htmlFunc(kind SpotKind) string {
"text_node": textNodeFunc, return infoKinds[kind] // infoKind entries are html-escaped
"html_node": htmlNodeFunc, }
"html_comment": htmlCommentFunc,
func infoLineFunc(info SpotInfo) int {
line := info.Lori()
if info.IsIndex() {
index, _ := searchIndex.get()
if index != nil {
line = index.(*Index).Snippet(line).Line
} else {
// no line information available because
// we don't have an index - this should
// never happen; be conservative and don't
// crash
line = 0
}
}
return line
}
func infoSnippet_htmlFunc(info SpotInfo) string {
if info.IsIndex() {
index, _ := searchIndex.get()
// Snippet.Text was HTML-escaped when it was generated
return index.(*Index).Snippet(info.Lori()).Text
}
return `<span class="alert">no snippet text available</span>`
}
func nodeFunc(node interface{}, fset *token.FileSet) string {
var buf bytes.Buffer
writeNode(&buf, fset, node)
return buf.String()
}
func node_htmlFunc(node interface{}, fset *token.FileSet) string {
var buf1 bytes.Buffer
writeNode(&buf1, fset, node)
var buf2 bytes.Buffer
FormatText(&buf2, buf1.Bytes(), -1, true, "", nil)
return buf2.String()
}
func comment_htmlFunc(comment string) string {
var buf bytes.Buffer
// TODO(gri) Provide list of words (e.g. function parameters)
// to be emphasized by ToHTML.
doc.ToHTML(&buf, []byte(comment), nil) // does html-escaping
return buf.String()
}
func pkgLinkFunc(path string) string {
relpath := relativeURL(path)
// because of the irregular mapping under goroot
// we need to correct certain relative paths
if strings.HasPrefix(relpath, "src/pkg/") {
relpath = relpath[len("src/pkg/"):]
}
return pkgHandler.pattern[1:] + relpath // remove trailing '/' for relative URL
}
func posLinkFunc(node ast.Node, fset *token.FileSet) string {
var relpath string
var line int
var low, high int // selection
if p := node.Pos(); p.IsValid() {
pos := fset.Position(p)
relpath = relativeURL(pos.Filename)
line = pos.Line
low = pos.Offset
}
if p := node.End(); p.IsValid() {
high = fset.Position(p).Offset
}
var buf bytes.Buffer
buf.WriteString(relpath)
// selection ranges are of form "s=low:high"
if low < high {
fmt.Fprintf(&buf, "?s=%d:%d", low, high)
// if we have a selection, position the page
// such that the selection is a bit below the top
line -= 10
if line < 1 {
line = 1
}
}
// line id's in html-printed source are of the
// form "L%d" where %d stands for the line number
if line > 0 {
fmt.Fprintf(&buf, "#L%d", line)
}
return buf.String()
}
// fmap describes the template functions installed with all godoc templates.
// Convention: template function names ending in "_html" produce an HTML-
// escaped string; all other function results may require HTML
// or URL escaping in the template.
var fmap = template.FuncMap{
// various helpers
"filename": filenameFunc,
"repeat": strings.Repeat,
// accss to FileInfos (directory listings)
"fileInfoName": fileInfoNameFunc, "fileInfoName": fileInfoNameFunc,
"fileInfoTime": fileInfoTimeFunc, "fileInfoTime": fileInfoTimeFunc,
"localname": localnameFunc,
"repeat": strings.Repeat, // access to search result information
}, FormatterMap{ "infoKind_html": infoKind_htmlFunc,
"url_pkg": urlFmt, "infoLine": infoLineFunc,
"url_src": urlFmt, "infoSnippet_html": infoSnippet_htmlFunc,
"url_pos": urlFmt,
"infoKind": infoKindFmt, // formatting of AST nodes
"infoLine": infoLineFmt, "node": nodeFunc,
"infoSnippet": infoSnippetFmt, "node_html": node_htmlFunc,
}) "comment_html": comment_htmlFunc,
// support for URL attributes
"pkgLink": pkgLinkFunc,
"srcLink": relativeURL,
"posLink": posLinkFunc,
}
func readTemplate(name string) *template.Template { func readTemplate(name string) *template.Template {
path := filepath.Join(*goroot, "lib", "godoc", name) path := filepath.Join(*goroot, "lib", "godoc", name)

View File

@ -18,7 +18,7 @@ import (
type Snippet struct { type Snippet struct {
Line int Line int
Text []byte Text string // HTML-escaped
} }
func newSnippet(fset *token.FileSet, decl ast.Decl, id *ast.Ident) *Snippet { func newSnippet(fset *token.FileSet, decl ast.Decl, id *ast.Ident) *Snippet {
@ -30,7 +30,7 @@ func newSnippet(fset *token.FileSet, decl ast.Decl, id *ast.Ident) *Snippet {
buf2.WriteString("<pre>") buf2.WriteString("<pre>")
FormatText(&buf2, buf1.Bytes(), -1, true, id.Name, nil) FormatText(&buf2, buf1.Bytes(), -1, true, id.Name, nil)
buf2.WriteString("</pre>") buf2.WriteString("</pre>")
return &Snippet{fset.Position(id.Pos()).Line, buf2.Bytes()} return &Snippet{fset.Position(id.Pos()).Line, buf2.String()}
} }
func findSpec(list []ast.Spec, id *ast.Ident) ast.Spec { func findSpec(list []ast.Spec, id *ast.Ident) ast.Spec {
@ -94,10 +94,7 @@ func NewSnippet(fset *token.FileSet, decl ast.Decl, id *ast.Ident) (s *Snippet)
if s == nil { if s == nil {
var buf bytes.Buffer var buf bytes.Buffer
fmt.Fprintf(&buf, `<span class="alert">could not generate a snippet for <span class="highlight">%s</span></span>`, id.Name) fmt.Fprintf(&buf, `<span class="alert">could not generate a snippet for <span class="highlight">%s</span></span>`, id.Name)
s = &Snippet{ s = &Snippet{fset.Position(id.Pos()).Line, buf.String()}
fset.Position(id.Pos()).Line,
buf.Bytes(),
}
} }
return return
} }