diff options
author | Ondřej Surý <ondrej@sury.org> | 2011-02-18 09:50:58 +0100 |
---|---|---|
committer | Ondřej Surý <ondrej@sury.org> | 2011-02-18 09:50:58 +0100 |
commit | c072558b90f1bbedc2022b0f30c8b1ac4712538e (patch) | |
tree | 67767591619e4bd8111fb05fac185cde94fb7378 /src/cmd/godoc | |
parent | 5859517b767c99749a45651c15d4bae5520ebae8 (diff) | |
download | golang-c072558b90f1bbedc2022b0f30c8b1ac4712538e.tar.gz |
Imported Upstream version 2011.02.15upstream/2011.02.15
Diffstat (limited to 'src/cmd/godoc')
-rw-r--r-- | src/cmd/godoc/format.go | 21 | ||||
-rw-r--r-- | src/cmd/godoc/godoc.go | 104 | ||||
-rw-r--r-- | src/cmd/godoc/index.go | 7 | ||||
-rw-r--r-- | src/cmd/godoc/main.go | 30 | ||||
-rwxr-xr-x | src/cmd/godoc/snippet.go | 11 | ||||
-rw-r--r-- | src/cmd/godoc/utils.go | 6 |
6 files changed, 98 insertions, 81 deletions
diff --git a/src/cmd/godoc/format.go b/src/cmd/godoc/format.go index 66b01aa64..da1466b21 100644 --- a/src/cmd/godoc/format.go +++ b/src/cmd/godoc/format.go @@ -11,7 +11,6 @@ package main import ( - "bytes" "fmt" "go/scanner" "go/token" @@ -335,12 +334,12 @@ func selectionTag(w io.Writer, text []byte, selections int) { } -// FormatText HTML-escapes text and returns it wrapped in <pre> tags. -// Conscutive text segments are wrapped in HTML spans (with tags as +// FormatText HTML-escapes text and writes it to w. +// Consecutive text segments are wrapped in HTML spans (with tags as // defined by startTags and endTag) as follows: // -// - if line >= 0, line numbers are printed before each line, starting -// with the value of line +// - if line >= 0, line number (ln) spans are inserted before each line, +// starting with the value of line // - if the text is Go source, comments get the "comment" span class // - each occurrence of the regular expression pattern gets the "highlight" // span class @@ -349,10 +348,7 @@ func selectionTag(w io.Writer, text []byte, selections int) { // Comments, highlights, and selections may overlap arbitrarily; the respective // HTML span classes are specified in the startTags variable. // -func FormatText(text []byte, line int, goSource bool, pattern string, selection Selection) []byte { - var buf bytes.Buffer - buf.WriteString("<pre>\n") - +func FormatText(w io.Writer, text []byte, line int, goSource bool, pattern string, selection Selection) { var comments, highlights Selection if goSource { comments = commentSelection(text) @@ -370,11 +366,8 @@ func FormatText(text []byte, line int, goSource bool, pattern string, selection } } } - FormatSelections(&buf, text, lineTag, lineSelection(text), selectionTag, comments, highlights, selection) + FormatSelections(w, text, lineTag, lineSelection(text), selectionTag, comments, highlights, selection) } else { - template.HTMLEscape(&buf, text) + template.HTMLEscape(w, text) } - - buf.WriteString("</pre>\n") - return buf.Bytes() } 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 diff --git a/src/cmd/godoc/index.go b/src/cmd/godoc/index.go index 581409cde..56f31f5cf 100644 --- a/src/cmd/godoc/index.go +++ b/src/cmd/godoc/index.go @@ -430,7 +430,6 @@ func (a *AltWords) filter(s string) *AltWords { // Indexer // Adjust these flags as seems best. -const includeNonGoFiles = true const includeMainPackages = true const includeTestFiles = true @@ -728,7 +727,7 @@ func isWhitelisted(filename string) bool { } -func (x *Indexer) visitFile(dirname string, f *os.FileInfo) { +func (x *Indexer) visitFile(dirname string, f *os.FileInfo, fulltextIndex bool) { if !f.IsRegular() { return } @@ -746,7 +745,7 @@ func (x *Indexer) visitFile(dirname string, f *os.FileInfo) { } goFile = true - case !includeNonGoFiles || !isWhitelisted(f.Name): + case !fulltextIndex || !isWhitelisted(f.Name): return } @@ -811,7 +810,7 @@ func NewIndex(dirnames <-chan string, fulltextIndex bool) *Index { } for _, f := range list { if !f.IsDirectory() { - x.visitFile(dirname, f) + x.visitFile(dirname, f, fulltextIndex) } } } diff --git a/src/cmd/godoc/main.go b/src/cmd/godoc/main.go index f1b11a760..ea1e3c42e 100644 --- a/src/cmd/godoc/main.go +++ b/src/cmd/godoc/main.go @@ -83,20 +83,21 @@ func exec(rw http.ResponseWriter, args []string) (status int) { if *verbose { log.Printf("executing %v", args) } - pid, err := os.ForkExec(bin, args, os.Environ(), *goroot, fds) + p, err := os.StartProcess(bin, args, os.Environ(), *goroot, fds) defer r.Close() w.Close() if err != nil { - log.Printf("os.ForkExec(%q): %v", bin, err) + log.Printf("os.StartProcess(%q): %v", bin, err) return 2 } + defer p.Release() var buf bytes.Buffer io.Copy(&buf, r) - wait, err := os.Wait(pid, 0) + wait, err := p.Wait(0) if err != nil { os.Stderr.Write(buf.Bytes()) - log.Printf("os.Wait(%d, 0): %v", pid, err) + log.Printf("os.Wait(%d, 0): %v", p.Pid, err) return 2 } status = wait.ExitStatus() @@ -317,7 +318,7 @@ func main() { } relpath := path abspath := path - if len(path) > 0 && path[0] != '/' { + if !pathutil.IsAbs(path) { abspath = absolutePath(path, pkgHandler.fsRoot) } else { relpath = relativePath(path) @@ -336,12 +337,17 @@ func main() { // if there are multiple packages in a directory. info := pkgHandler.getPageInfo(abspath, relpath, "", mode) - if info.Err != nil || info.PAst == nil && info.PDoc == nil && info.Dirs == nil { + if info.IsEmpty() { // try again, this time assume it's a command - if len(path) > 0 && path[0] != '/' { + if !pathutil.IsAbs(path) { abspath = absolutePath(path, cmdHandler.fsRoot) } - info = cmdHandler.getPageInfo(abspath, relpath, "", mode) + cmdInfo := cmdHandler.getPageInfo(abspath, relpath, "", mode) + // only use the cmdInfo if it actually contains a result + // (don't hide errors reported from looking up a package) + if !cmdInfo.IsEmpty() { + info = cmdInfo + } } if info.Err != nil { log.Fatalf("%v", info.Err) @@ -366,7 +372,11 @@ func main() { if i > 0 { fmt.Println() } - writeAny(os.Stdout, info.FSet, *html, d) + if *html { + writeAnyHTML(os.Stdout, info.FSet, d) + } else { + writeAny(os.Stdout, info.FSet, d) + } fmt.Println() } return @@ -376,7 +386,7 @@ func main() { } } - if err := packageText.Execute(info, os.Stdout); err != nil { + if err := packageText.Execute(os.Stdout, info); err != nil { log.Printf("packageText.Execute: %s", err) } } diff --git a/src/cmd/godoc/snippet.go b/src/cmd/godoc/snippet.go index c2838ed5a..c5f4c1edf 100755 --- a/src/cmd/godoc/snippet.go +++ b/src/cmd/godoc/snippet.go @@ -25,9 +25,14 @@ type Snippet struct { func newSnippet(fset *token.FileSet, decl ast.Decl, id *ast.Ident) *Snippet { // TODO instead of pretty-printing the node, should use the original source instead - var buf bytes.Buffer - writeNode(&buf, fset, decl, false) - return &Snippet{fset.Position(id.Pos()).Line, FormatText(buf.Bytes(), -1, true, id.Name, nil)} + var buf1 bytes.Buffer + writeNode(&buf1, fset, decl) + // wrap text with <pre> tag + var buf2 bytes.Buffer + buf2.WriteString("<pre>") + FormatText(&buf2, buf1.Bytes(), -1, true, id.Name, nil) + buf2.WriteString("</pre>") + return &Snippet{fset.Position(id.Pos()).Line, buf2.Bytes()} } diff --git a/src/cmd/godoc/utils.go b/src/cmd/godoc/utils.go index a032bd331..cc028cc4d 100644 --- a/src/cmd/godoc/utils.go +++ b/src/cmd/godoc/utils.go @@ -60,10 +60,10 @@ func canonicalizePaths(list []string, filter func(path string) bool) []string { continue // ignore empty paths (don't assume ".") } // len(path) > 0: normalize path - if path[0] != '/' { - path = pathutil.Join(cwd, path) - } else { + if pathutil.IsAbs(path) { path = pathutil.Clean(path) + } else { + path = pathutil.Join(cwd, path) } // we have a non-empty absolute path if filter != nil && !filter(path) { |