summaryrefslogtreecommitdiff
path: root/src/cmd/godoc
diff options
context:
space:
mode:
authorOndřej Surý <ondrej@sury.org>2011-02-18 09:50:58 +0100
committerOndřej Surý <ondrej@sury.org>2011-02-18 09:50:58 +0100
commitc072558b90f1bbedc2022b0f30c8b1ac4712538e (patch)
tree67767591619e4bd8111fb05fac185cde94fb7378 /src/cmd/godoc
parent5859517b767c99749a45651c15d4bae5520ebae8 (diff)
downloadgolang-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.go21
-rw-r--r--src/cmd/godoc/godoc.go104
-rw-r--r--src/cmd/godoc/index.go7
-rw-r--r--src/cmd/godoc/main.go30
-rwxr-xr-xsrc/cmd/godoc/snippet.go11
-rw-r--r--src/cmd/godoc/utils.go6
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) {