From 5c45e56898261c29ae44e65bd087a508c9abe0a5 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Fri, 12 Aug 2011 15:43:10 -0700 Subject: [PATCH] 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 --- lib/godoc/godoc.html | 2 +- lib/godoc/package.html | 50 +++--- lib/godoc/package.txt | 20 +-- lib/godoc/search.html | 41 ++--- lib/godoc/search.txt | 6 +- src/cmd/godoc/godoc.go | 324 +++++++++++++++++---------------------- src/cmd/godoc/snippet.go | 9 +- 7 files changed, 200 insertions(+), 252 deletions(-) diff --git a/lib/godoc/godoc.html b/lib/godoc/godoc.html index 91e521258d6..e978b309c6e 100644 --- a/lib/godoc/godoc.html +++ b/lib/godoc/godoc.html @@ -25,7 +25,7 @@
{{with .PkgRoots}} {{range .PkgRoots}} - {{html .}} | + {{html .}} | {{end}} {{else}} References: diff --git a/lib/godoc/package.html b/lib/godoc/package.html index b2b8356b048..968f69a7c39 100644 --- a/lib/godoc/package.html +++ b/lib/godoc/package.html @@ -4,21 +4,21 @@ license that can be found in the LICENSE file. --> {{with .PAst}} -
{{html_node . $.FSet}}
+
{{node_html . $.FSet}}
{{end}} {{with .PDoc}} {{if $.IsPkg}}

import "{{html .ImportPath}}"

{{end}} - {{html_comment .Doc}} + {{comment_html .Doc}} {{if $.IsPkg}} {{with .Filenames}}

Package files

{{range .}} - {{.|localname|html}} + {{.|filename|html}} {{end}}

@@ -27,58 +27,58 @@ {{with .Consts}}

Constants

{{range .}} - {{html_comment .Doc}} -
{{html_node .Decl $.FSet}}
+ {{comment_html .Doc}} +
{{node_html .Decl $.FSet}}
{{end}} {{end}} {{with .Vars}}

Variables

{{range .}} - {{html_comment .Doc}} -
{{html_node .Decl $.FSet}}
+ {{comment_html .Doc}} +
{{node_html .Decl $.FSet}}
{{end}} {{end}} {{with .Funcs}} {{range .}} {{/* Name is a string - no need for FSet */}} {{$name := html .Name}} -

func {{$name}}

-

{{html_node .Decl $.FSet}}

- {{html_comment .Doc}} +

func {{$name}}

+

{{node_html .Decl $.FSet}}

+ {{comment_html .Doc}} {{end}} {{end}} {{with .Types}} {{range .}} - {{$tname := html_node .Type.Name $.FSet}} -

type {{$tname}}

- {{html_comment .Doc}} -

{{html_node .Decl $.FSet}}

+ {{$tname := node_html .Type.Name $.FSet}} +

type {{$tname}}

+ {{comment_html .Doc}} +

{{node_html .Decl $.FSet}}

{{range .Consts}} - {{html_comment .Doc}} -
{{html_node .Decl $.FSet}}
+ {{comment_html .Doc}} +
{{node_html .Decl $.FSet}}
{{end}} {{range .Vars}} - {{html_comment .Doc}} -
{{html_node .Decl $.FSet}}
+ {{comment_html .Doc}} +
{{node_html .Decl $.FSet}}
{{end}} {{range .Factories}} {{$name := html .Name}} -

func {{$name}}

-

{{html_node .Decl $.FSet}}

- {{html_comment .Doc}} +

func {{$name}}

+

{{node_html .Decl $.FSet}}

+ {{comment_html .Doc}} {{end}} {{range .Methods}} {{$name := html .Name}} -

func ({{html_node .Recv $.FSet}}) {{$name}}

-

{{html_node .Decl $.FSet}}

- {{html_comment .Doc}} +

func ({{node_html .Recv $.FSet}}) {{$name}}

+

{{node_html .Decl $.FSet}}

+ {{comment_html .Doc}} {{end}} {{end}} {{end}} {{with .Bugs}}

Bugs

{{range .}} - {{html_comment .}} + {{comment_html .}} {{end}} {{end}} {{end}} diff --git a/lib/godoc/package.txt b/lib/godoc/package.txt index af1a6306934..45c5566e8ce 100644 --- a/lib/godoc/package.txt +++ b/lib/godoc/package.txt @@ -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}}{{/* --------------------------------------- @@ -24,7 +24,7 @@ import "{{.ImportPath}}" */}}{{with .Consts}} CONSTANTS -{{range .}}{{text_node .Decl $FSet}} +{{range .}}{{node .Decl $FSet}} {{.Doc}}{{end}} {{end}}{{/* @@ -33,7 +33,7 @@ CONSTANTS */}}{{with .Vars}} VARIABLES -{{range .}}{{text_node .Decl $FSet}} +{{range .}}{{node .Decl $FSet}} {{.Doc}}{{end}} {{end}}{{/* @@ -42,7 +42,7 @@ VARIABLES */}}{{with .Funcs}} FUNCTIONS -{{range .}}{{text_node .Decl $FSet}} +{{range .}}{{node .Decl $FSet}} {{.Doc}} {{end}}{{end}}{{/* @@ -51,15 +51,15 @@ FUNCTIONS */}}{{with .Types}} TYPES -{{range .}}{{text_node .Decl $FSet}} +{{range .}}{{node .Decl $FSet}} {{.Doc}} -{{range .Consts}}{{text_node .Decl $FSet}} +{{range .Consts}}{{node .Decl $FSet}} {{.Doc}} -{{end}}{{range .Vars}}{{text_node .Decl $FSet}} +{{end}}{{range .Vars}}{{node .Decl $FSet}} {{.Doc}} -{{end}}{{range .Factories}}{{text_node .Decl $FSet}} +{{end}}{{range .Factories}}{{node .Decl $FSet}} {{.Doc}} -{{end}}{{range .Methods}}{{text_node .Decl $FSet}} +{{end}}{{range .Methods}}{{node .Decl $FSet}} {{.Doc}} {{end}}{{end}}{{end}}{{/* diff --git a/lib/godoc/search.html b/lib/godoc/search.html index 4c956721f83..39eec9b4983 100644 --- a/lib/godoc/search.html +++ b/lib/godoc/search.html @@ -3,10 +3,9 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> -{{$SearchResult := .}} {{with .Alert}}

- {{.}} + {{html .}}

{{end}} {{with .Alt}} @@ -21,13 +20,14 @@ {{with .Decls}}

Package-level declarations

{{range .}} -

package {{html .Pak.Name}}

+ {{$pkg := pkgLink .Pak.Path}} +

package {{html .Pak.Name}}

{{range .Files}} - {{$path := url_src .File.Path}} + {{$src := srcLink .File.Path}} {{range .Groups}} {{range .Infos}} - {{$path}}:{{infoLine .}} - {{infoSnippet .}} + {{html $src}}:{{infoLine .}} + {{infoSnippet_html .}} {{end}} {{end}} {{end}} @@ -36,19 +36,20 @@ {{with .Others}}

Local declarations and uses

{{range .}} -

package {{html .Pak.Name}}

+ {{$pkg := pkgLink .Pak.Path}} +

package {{html .Pak.Name}}

{{range .Files}} - {{$path := url_src .File.Path}} - {{$path}} + {{$src := srcLink .File.Path}} + {{html $src}} {{range .Groups}} - + @@ -59,36 +60,36 @@ {{end}} {{end}} {{with .Textual}} - {{if $SearchResult.Complete}} -

{{html $SearchResult.Found}} textual occurrences

+ {{if $.Complete}} +

{{html $.Found}} textual occurrences

{{else}} -

More than {{html $SearchResult.Found}} textual occurrences

+

More than {{html $.Found}} textual occurrences

- Not all files or lines containing "{{html $SearchResult.Query}}" are shown. + Not all files or lines containing "{{html $.Query}}" are shown.

{{end}}

{{infoKind .Kind}}{{infoKind_html .Kind}} {{range .Infos}} - {{infoLine .}} + {{infoLine .}} {{end}}
{{range .}} - {{$path := url_src .Filename}} + {{$src := srcLink .Filename}} {{end}} - {{if not $SearchResult.Complete}} + {{if not $.Complete}} {{end}}
- {{$path}}: + {{html $src}}: {{len .Lines}} {{range .Lines}} - {{html .}} + {{html .}} {{end}} - {{if not $SearchResult.Complete}} + {{if not $.Complete}} ... {{end}}
...
diff --git a/lib/godoc/search.txt b/lib/godoc/search.txt index 423712155aa..71343984c76 100644 --- a/lib/godoc/search.txt +++ b/lib/godoc/search.txt @@ -17,7 +17,7 @@ DID YOU MEAN PACKAGE-LEVEL DECLARATIONS {{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}}{{/* .Decls */}}{{/* @@ -27,7 +27,7 @@ PACKAGE-LEVEL DECLARATIONS LOCAL DECLARATIONS AND USES {{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}}{{/* .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}} -{{range .Textual}}{{len .Lines}} {{url_src .Filename}} +{{range .Textual}}{{len .Lines}} {{srcLink .Filename}} {{end}}{{if not .Complete}}... ... {{end}}{{end}} diff --git a/src/cmd/godoc/godoc.go b/src/cmd/godoc/godoc.go index c70a03de821..15b60c72b08 100644 --- a/src/cmd/godoc/godoc.go +++ b/src/cmd/godoc/godoc.go @@ -371,176 +371,9 @@ func writeNode(w io.Writer, fset *token.FileSet, x interface{}) { (&printer.Config{mode, *tabwidth}).Fprint(&tconv{output: w}, fset, x) } -func fileset(x []interface{}) *token.FileSet { - if len(x) > 1 { - if fset, ok := x[1].(*token.FileSet); ok { - 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 clause", - ImportDecl: "import decl", - ConstDecl: "const decl", - TypeDecl: "type decl", - VarDecl: "var decl", - FuncDecl: "func decl", - MethodDecl: "method 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(`no snippet text available`) - 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 filenameFunc(path string) string { + _, localname := filepath.Split(path) + return localname } 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 } -func localnameFunc(path string) string { - _, localname := filepath.Split(path) - return localname +// The strings in infoKinds must be properly html-escaped. +var infoKinds = [nKinds]string{ + PackageClause: "package clause", + ImportDecl: "import decl", + ConstDecl: "const decl", + TypeDecl: "type decl", + VarDecl: "var decl", + FuncDecl: "func decl", + MethodDecl: "method decl", + Use: "use", } -var fmap = append2funcMap(template.FuncMap{ - "text_node": textNodeFunc, - "html_node": htmlNodeFunc, - "html_comment": htmlCommentFunc, +func infoKind_htmlFunc(kind SpotKind) string { + return infoKinds[kind] // infoKind entries are html-escaped +} + +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 `no snippet text available` +} + +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, "fileInfoTime": fileInfoTimeFunc, - "localname": localnameFunc, - "repeat": strings.Repeat, -}, FormatterMap{ - "url_pkg": urlFmt, - "url_src": urlFmt, - "url_pos": urlFmt, - "infoKind": infoKindFmt, - "infoLine": infoLineFmt, - "infoSnippet": infoSnippetFmt, -}) + + // access to search result information + "infoKind_html": infoKind_htmlFunc, + "infoLine": infoLineFunc, + "infoSnippet_html": infoSnippet_htmlFunc, + + // formatting of AST nodes + "node": nodeFunc, + "node_html": node_htmlFunc, + "comment_html": comment_htmlFunc, + + // support for URL attributes + "pkgLink": pkgLinkFunc, + "srcLink": relativeURL, + "posLink": posLinkFunc, +} func readTemplate(name string) *template.Template { path := filepath.Join(*goroot, "lib", "godoc", name) diff --git a/src/cmd/godoc/snippet.go b/src/cmd/godoc/snippet.go index 626b01455dd..68e27d9a0cb 100755 --- a/src/cmd/godoc/snippet.go +++ b/src/cmd/godoc/snippet.go @@ -18,7 +18,7 @@ import ( type Snippet struct { Line int - Text []byte + Text string // HTML-escaped } 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("
")
 	FormatText(&buf2, buf1.Bytes(), -1, true, id.Name, nil)
 	buf2.WriteString("
") - 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 { @@ -94,10 +94,7 @@ func NewSnippet(fset *token.FileSet, decl ast.Decl, id *ast.Ident) (s *Snippet) if s == nil { var buf bytes.Buffer fmt.Fprintf(&buf, `could not generate a snippet for %s`, id.Name) - s = &Snippet{ - fset.Position(id.Pos()).Line, - buf.Bytes(), - } + s = &Snippet{fset.Position(id.Pos()).Line, buf.String()} } return }