diff options
Diffstat (limited to 'src/cmd/godoc/godoc.go')
-rw-r--r-- | src/cmd/godoc/godoc.go | 104 |
1 files changed, 57 insertions, 47 deletions
diff --git a/src/cmd/godoc/godoc.go b/src/cmd/godoc/godoc.go index 6a00a3e70..c91dc33db 100644 --- a/src/cmd/godoc/godoc.go +++ b/src/cmd/godoc/godoc.go @@ -274,7 +274,7 @@ func relativePath(path string) string { // ---------------------------------------------------------------------------- // Tab conversion -var spaces = []byte(" ") // 16 spaces seems like a good number +var spaces = []byte(" ") // 32 spaces seems like a good number const ( indenting = iota @@ -291,25 +291,31 @@ type tconv struct { func (p *tconv) writeIndent() (err os.Error) { i := p.indent - for i > len(spaces) { + for i >= len(spaces) { i -= len(spaces) if _, err = p.output.Write(spaces); err != nil { return } } - _, err = p.output.Write(spaces[0:i]) + // i < len(spaces) + if i > 0 { + _, err = p.output.Write(spaces[0:i]) + } return } func (p *tconv) Write(data []byte) (n int, err os.Error) { + if len(data) == 0 { + return + } pos := 0 // valid if p.state == collecting var b byte for n, b = range data { switch p.state { case indenting: switch b { - case '\t', '\v': + case '\t': p.indent += *tabwidth case '\n': p.indent = 0 @@ -336,7 +342,7 @@ func (p *tconv) Write(data []byte) (n int, err os.Error) { } } n = len(data) - if p.state == collecting { + if pos < n && p.state == collecting { _, err = p.output.Write(data[pos:]) } return @@ -346,47 +352,51 @@ func (p *tconv) Write(data []byte) (n int, err os.Error) { // ---------------------------------------------------------------------------- // Templates -// Write an AST-node to w; optionally html-escaped. -func writeNode(w io.Writer, fset *token.FileSet, node interface{}, html bool) { - mode := printer.TabIndent | printer.UseSpaces - if html { - mode |= printer.GenHTML - } +// Write an AST node to w. +func writeNode(w io.Writer, fset *token.FileSet, x interface{}) { // convert trailing tabs into spaces using a tconv filter // to ensure a good outcome in most browsers (there may still // be tabs in comments and strings, but converting those into // the right number of spaces is much harder) - (&printer.Config{mode, *tabwidth, nil}).Fprint(&tconv{output: w}, fset, node) + // + // TODO(gri) rethink printer flags - perhaps tconv can be eliminated + // with an another printer mode (which is more efficiently + // implemented in the printer than here with another layer) + mode := printer.TabIndent | printer.UseSpaces + (&printer.Config{mode, *tabwidth}).Fprint(&tconv{output: w}, fset, x) } -// Write text to w; optionally html-escaped. -func writeText(w io.Writer, text []byte, html bool) { - if html { - template.HTMLEscape(w, text) - return +// Write anything to w. +func writeAny(w io.Writer, fset *token.FileSet, x interface{}) { + switch v := x.(type) { + case []byte: + w.Write(v) + case string: + w.Write([]byte(v)) + case ast.Decl, ast.Expr, ast.Stmt, *ast.File: + writeNode(w, fset, x) + default: + fmt.Fprint(w, x) } - w.Write(text) } -// Write anything to w; optionally html-escaped. -func writeAny(w io.Writer, fset *token.FileSet, html bool, x interface{}) { +// Write anything html-escaped to w. +func writeAnyHTML(w io.Writer, fset *token.FileSet, x interface{}) { switch v := x.(type) { case []byte: - writeText(w, v, html) + template.HTMLEscape(w, v) case string: - writeText(w, []byte(v), html) + template.HTMLEscape(w, []byte(v)) case ast.Decl, ast.Expr, ast.Stmt, *ast.File: - writeNode(w, fset, x, html) + var buf bytes.Buffer + writeNode(&buf, fset, x) + FormatText(w, buf.Bytes(), -1, true, "", nil) default: - if html { - var buf bytes.Buffer - fmt.Fprint(&buf, x) - writeText(w, buf.Bytes(), true) - } else { - fmt.Fprint(w, x) - } + var buf bytes.Buffer + fmt.Fprint(&buf, x) + template.HTMLEscape(w, buf.Bytes()) } } @@ -401,24 +411,16 @@ func fileset(x []interface{}) *token.FileSet { } -// Template formatter for "html" format. -func htmlFmt(w io.Writer, format string, x ...interface{}) { - writeAny(w, fileset(x), true, x[0]) -} - - // Template formatter for "html-esc" format. func htmlEscFmt(w io.Writer, format string, x ...interface{}) { - var buf bytes.Buffer - writeAny(&buf, fileset(x), false, x[0]) - template.HTMLEscape(w, buf.Bytes()) + writeAnyHTML(w, fileset(x), x[0]) } // Template formatter for "html-comment" format. func htmlCommentFmt(w io.Writer, format string, x ...interface{}) { var buf bytes.Buffer - writeAny(&buf, fileset(x), false, x[0]) + writeAny(&buf, fileset(x), x[0]) // TODO(gri) Provide list of words (e.g. function parameters) // to be emphasized by ToHTML. doc.ToHTML(w, buf.Bytes(), nil) // does html-escaping @@ -427,14 +429,14 @@ func htmlCommentFmt(w io.Writer, format string, x ...interface{}) { // Template formatter for "" (default) format. func textFmt(w io.Writer, format string, x ...interface{}) { - writeAny(w, fileset(x), false, x[0]) + writeAny(w, fileset(x), x[0]) } // Template formatter for "urlquery-esc" format. func urlQueryEscFmt(w io.Writer, format string, x ...interface{}) { var buf bytes.Buffer - writeAny(&buf, fileset(x), false, x[0]) + writeAny(&buf, fileset(x), x[0]) template.HTMLEscape(w, []byte(http.URLEscape(string(buf.Bytes())))) } @@ -603,7 +605,6 @@ func numlinesFmt(w io.Writer, format string, x ...interface{}) { var fmap = template.FormatterMap{ "": textFmt, - "html": htmlFmt, "html-esc": htmlEscFmt, "html-comment": htmlCommentFmt, "urlquery-esc": urlQueryEscFmt, @@ -683,7 +684,7 @@ func servePage(w http.ResponseWriter, title, subtitle, query string, content []b content, } - if err := godocHTML.Execute(&d, w); err != nil { + if err := godocHTML.Execute(w, &d); err != nil { log.Printf("godocHTML.Execute: %s", err) } } @@ -751,7 +752,7 @@ func serveHTMLDoc(w http.ResponseWriter, r *http.Request, abspath, relpath strin func applyTemplate(t *template.Template, name string, data interface{}) []byte { var buf bytes.Buffer - if err := t.Execute(data, &buf); err != nil { + if err := t.Execute(&buf, data); err != nil { log.Printf("%s.Execute: %s", name, err) } return buf.Bytes() @@ -775,8 +776,12 @@ func serveTextFile(w http.ResponseWriter, r *http.Request, abspath, relpath, tit return } - contents := FormatText(src, 1, pathutil.Ext(abspath) == ".go", r.FormValue("h"), rangeSelection(r.FormValue("s"))) - servePage(w, title+" "+relpath, "", "", contents) + var buf bytes.Buffer + buf.WriteString("<pre>") + FormatText(&buf, src, 1, pathutil.Ext(abspath) == ".go", r.FormValue("h"), rangeSelection(r.FormValue("s"))) + buf.WriteString("</pre>") + + servePage(w, title+" "+relpath, "", "", buf.Bytes()) } @@ -891,6 +896,11 @@ type PageInfo struct { } +func (info *PageInfo) IsEmpty() bool { + return info.Err != nil || info.PAst == nil && info.PDoc == nil && info.Dirs == nil +} + + type httpHandler struct { pattern string // url pattern; e.g. "/pkg/" fsRoot string // file system root to which the pattern is mapped |