1
0
mirror of https://github.com/golang/go synced 2024-11-21 22:34:48 -07:00

some godoc cleanup:

- simplified dealing with parse errors: no need to intersperse them in the source
- improve visibility of highlighted identifiers by showing them in bold

R=rsc
https://golang.org/cl/163051
This commit is contained in:
Robert Griesemer 2009-12-01 09:15:05 -08:00
parent 330139e3f2
commit 9e450880e9
5 changed files with 36 additions and 109 deletions

View File

@ -194,6 +194,7 @@ span.comment {
} }
span.highlight { span.highlight {
font-weight: bold;
background-color: #ffffa0; background-color: #ffffa0;
} }

View File

@ -1,6 +0,0 @@
parse errors:
{.repeated section list}
{.section msg}
{filename}:{line}: {msg}
{.end}
{.end}

View File

@ -4,7 +4,10 @@
license that can be found in the LICENSE file. license that can be found in the LICENSE file.
--> -->
<pre> {.section Error}
{.repeated section list} <p>
{src|html}{.section msg}<b><span class="alert">«{msg|html}»</span></b>{.end}{.end} <span class="alert" style="font-size:120%">{@|html}</span>
</pre> </p>
{.or}
<pre>{Source|html}</pre>
{.end}

View File

@ -12,7 +12,6 @@ import (
"go/doc"; "go/doc";
"go/parser"; "go/parser";
"go/printer"; "go/printer";
"go/scanner";
"go/token"; "go/token";
"http"; "http";
"io"; "io";
@ -122,7 +121,7 @@ func isPkgDir(dir *os.Dir) bool {
func pkgName(filename string) string { func pkgName(filename string) string {
file, err := parse(filename, parser.PackageClauseOnly); file, err := parser.ParseFile(filename, nil, parser.PackageClauseOnly);
if err != nil || file == nil { if err != nil || file == nil {
return "" return ""
} }
@ -397,74 +396,6 @@ func listing(dirs []*os.Dir) *DirList {
} }
// ----------------------------------------------------------------------------
// Parsing
// A single error in the parsed file.
type parseError struct {
src []byte; // source before error
line int; // line number of error
msg string; // error message
}
// All the errors in the parsed file, plus surrounding source code.
// Each error has a slice giving the source text preceding it
// (starting where the last error occurred). The final element in list[]
// has msg = "", to give the remainder of the source code.
// This data structure is handed to the templates parseerror.txt and parseerror.html.
//
type parseErrors struct {
filename string; // path to file
list []parseError; // the errors
src []byte; // the file's entire source code
}
// Parses a file (path) and returns the corresponding AST and
// a sorted list (by file position) of errors, if any.
//
func parse(path string, mode uint) (*ast.File, *parseErrors) {
src, err := io.ReadFile(path);
if err != nil {
log.Stderrf("%v", err);
errs := []parseError{parseError{nil, 0, err.String()}};
return nil, &parseErrors{path, errs, nil};
}
prog, err := parser.ParseFile(path, src, mode);
if err != nil {
var errs []parseError;
if errors, ok := err.(scanner.ErrorList); ok {
// convert error list (already sorted)
// TODO(gri) If the file contains //line comments, the errors
// may not be sorted in increasing file offset value
// which will lead to incorrect output.
errs = make([]parseError, len(errors)+1); // +1 for final fragment of source
offs := 0;
for i, r := range errors {
// Should always be true, but check for robustness.
if 0 <= r.Pos.Offset && r.Pos.Offset <= len(src) {
errs[i].src = src[offs:r.Pos.Offset];
offs = r.Pos.Offset;
}
errs[i].line = r.Pos.Line;
errs[i].msg = r.Msg;
}
errs[len(errors)].src = src[offs:];
} else {
// single error of unspecified type
errs = make([]parseError, 2);
errs[0] = parseError{[]byte{}, 0, err.String()};
errs[1].src = src;
}
return nil, &parseErrors{path, errs, src};
}
return prog, nil;
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// HTML formatting support // HTML formatting support
@ -544,6 +475,12 @@ func writeText(w io.Writer, text []byte, html bool) {
} }
type StyledNode struct {
node interface{};
styler printer.Styler;
}
// Write anything to w; optionally html-escaped. // Write anything to w; optionally html-escaped.
func writeAny(w io.Writer, x interface{}, html bool) { func writeAny(w io.Writer, x interface{}, html bool) {
switch v := x.(type) { switch v := x.(type) {
@ -551,10 +488,10 @@ func writeAny(w io.Writer, x interface{}, html bool) {
writeText(w, v, html) writeText(w, v, html)
case string: case string:
writeText(w, strings.Bytes(v), html) writeText(w, strings.Bytes(v), html)
case ast.Decl: case ast.Decl, ast.Expr, ast.Stmt, *ast.File:
writeNode(w, v, html, &defaultStyler) writeNode(w, x, html, &defaultStyler)
case ast.Expr: case StyledNode:
writeNode(w, v, html, &defaultStyler) writeNode(w, v.node, html, v.styler)
default: default:
if html { if html {
var buf bytes.Buffer; var buf bytes.Buffer;
@ -713,9 +650,8 @@ var (
godocHTML, godocHTML,
packageHTML, packageHTML,
packageText, packageText,
parseerrorHTML, searchHTML,
parseerrorText, sourceHTML *template.Template;
searchHTML *template.Template;
) )
func readTemplates() { func readTemplates() {
@ -725,9 +661,8 @@ func readTemplates() {
godocHTML = readTemplate("godoc.html"); godocHTML = readTemplate("godoc.html");
packageHTML = readTemplate("package.html"); packageHTML = readTemplate("package.html");
packageText = readTemplate("package.txt"); packageText = readTemplate("package.txt");
parseerrorHTML = readTemplate("parseerror.html");
parseerrorText = readTemplate("parseerror.txt");
searchHTML = readTemplate("search.html"); searchHTML = readTemplate("search.html");
sourceHTML = readTemplate("source.html");
} }
@ -802,29 +737,24 @@ func serveHTMLDoc(c *http.Conn, r *http.Request, path string) {
} }
func serveParseErrors(c *http.Conn, errors *parseErrors) { func serveGoSource(c *http.Conn, r *http.Request, path string) {
// format errors var info struct {
var buf bytes.Buffer; Source StyledNode;
if err := parseerrorHTML.Execute(errors, &buf); err != nil { Error string;
log.Stderrf("parseerrorHTML.Execute: %s", err)
}
servePage(c, "Parse errors in source file "+errors.filename, "", buf.Bytes());
} }
file, err := parser.ParseFile(path, nil, parser.ParseComments);
func serveGoSource(c *http.Conn, r *http.Request, path string, styler printer.Styler) { info.Source = StyledNode{file, &Styler{linetags: true, highlight: r.FormValue("h")}};
prog, errors := parse(path, parser.ParseComments); if err != nil {
if errors != nil { info.Error = err.String()
serveParseErrors(c, errors);
return;
} }
var buf bytes.Buffer; var buf bytes.Buffer;
fmt.Fprintln(&buf, "<pre>"); if err := sourceHTML.Execute(info, &buf); err != nil {
writeNode(&buf, prog, true, styler); log.Stderrf("sourceHTML.Execute: %s", err)
fmt.Fprintln(&buf, "</pre>"); }
servePage(c, "Source file "+r.URL.Path, "", buf.Bytes()); servePage(c, "Source file "+path, "", buf.Bytes());
} }
@ -940,7 +870,7 @@ func serveFile(c *http.Conn, r *http.Request) {
return; return;
case ext == ".go": case ext == ".go":
serveGoSource(c, r, path, &Styler{linetags: true, highlight: r.FormValue("h")}); serveGoSource(c, r, path);
return; return;
} }

View File

@ -217,8 +217,7 @@ func main() {
// Command line mode. // Command line mode.
if *html { if *html {
packageText = packageHTML; packageText = packageHTML
parseerrorText = parseerrorHTML;
} }
info := pkgHandler.getPageInfo(flag.Arg(0)); info := pkgHandler.getPageInfo(flag.Arg(0));