]> Cypherpunks repositories - gostls13.git/commitdiff
godoc: switch to go library template system
authorRuss Cox <rsc@golang.org>
Mon, 13 Apr 2009 22:25:50 +0000 (15:25 -0700)
committerRuss Cox <rsc@golang.org>
Mon, 13 Apr 2009 22:25:50 +0000 (15:25 -0700)
R=gri
DELTA=272  (38 added, 139 deleted, 95 changed)
OCL=27372
CL=27390

usr/gri/pretty/Makefile
usr/gri/pretty/godoc.go
usr/gri/pretty/template.go [deleted file]

index 0636289efd168c1022cbbb072e3ebb9b94c9ed35..836f0890ff3cc035264a92ad778d49782a8132c9 100644 (file)
@@ -36,11 +36,11 @@ pretty.6:    platform.6 astprinter.6 compilation.6
 
 compilation.6:  platform.6 typechecker.6
 
-symboltable.6: 
+symboltable.6:
 
 platform.6:     utils.6
 
-astprinter.6:   utils.6 symboltable.6 template.6
+astprinter.6:   utils.6 symboltable.6
 
 docprinter.6:  astprinter.6
 
index f3903e8a9bae18a210bd6e71bd3b9d2c7a6c6cd5..0a1ebd49b9ed98fc45a23fd38abcd83aa53a021c 100644 (file)
@@ -35,10 +35,12 @@ import (
        "io";
        "log";
        "net";
+       "once";
        "os";
        "parser";
        pathutil "path";
        "sort";
+       "strings";
        "tabwriter";
        "template";
        "time";
@@ -94,24 +96,13 @@ func init() {
 // ----------------------------------------------------------------------------
 // Support
 
-func hasPrefix(s, prefix string) bool {
-       return len(prefix) <= len(s) && s[0 : len(prefix)] == prefix;
-}
-
-
-func hasSuffix(s, suffix string) bool {
-       pos := len(s) - len(suffix);
-       return pos >= 0 && s[pos : len(s)] == suffix;
-}
-
-
 func isGoFile(dir *os.Dir) bool {
-       return dir.IsRegular() && hasSuffix(dir.Name, ".go");
+       return dir.IsRegular() && strings.HasSuffix(dir.Name, ".go");
 }
 
 
 func isHTMLFile(dir *os.Dir) bool {
-       return dir.IsRegular() && hasSuffix(dir.Name, ".html");
+       return dir.IsRegular() && strings.HasSuffix(dir.Name, ".html");
 }
 
 
@@ -127,7 +118,7 @@ func isFile(name string) bool {
 }
 
 
-func printLink(c *http.Conn, dir, name string) {
+func printLink(c io.Write, dir, name string) {
        fmt.Fprintf(c, "<a href=\"%s\">%s</a><br />\n", pathutil.Clean(filePrefix + dir + "/" + name), name);
 }
 
@@ -208,26 +199,55 @@ func parse(path string, mode uint) (*ast.Program, errorList) {
 // Templates
 
 // html template
-// TODO initialize only if needed (i.e. if run as a server)
-var godoc_html = template.NewTemplateOrDie("godoc.html");
+var godoc_html string
+
+func readTemplate() {
+       name := "usr/gri/pretty/godoc.html";
+       f, err := os.Open(name, os.O_RDONLY, 0);
+       if err != nil {
+               log.Exitf("open %s: %v", name, err);
+       }
+       var b io.ByteBuffer;
+       if n, err := io.Copy(f, &b); err != nil {
+               log.Exitf("copy %s: %v", name, err);
+       }
+       f.Close();
+       godoc_html = string(b.Data());
+}
+
+
+func servePage(c *http.Conn, title, content interface{}) {
+       once.Do(readTemplate);
 
-func servePage(c *http.Conn, title string, contents func()) {
        c.SetHeader("content-type", "text/html; charset=utf-8");
 
-       // TODO handle Apply errors
-       godoc_html.Apply(c, "<!--", template.Substitution {
-               "TITLE-->" : func() { fmt.Fprint(c, title); },
-               "HEADER-->" : func() { fmt.Fprint(c, title); },
-               "TIMESTAMP-->" : func() { fmt.Fprint(c, time.UTC().String()); },
-               "CONTENTS-->" : contents
-       });
+       type Data struct {
+               title string;
+               header string;
+               timestamp string;
+               content string;
+       }
+       
+       // TODO(rsc): Once template system can handle []byte,
+       // remove this conversion.
+       if x, ok := title.([]byte); ok {
+               title = string(x);
+       }
+       if x, ok := content.([]byte); ok {
+               content = string(x);
+       }
+
+       var d Data;
+       d.title = title.(string);
+       d.header = title.(string);
+       d.timestamp = time.UTC().String();
+       d.content = content.(string);
+       template.Execute(godoc_html, &d, nil, c);
 }
 
 
 func serveError(c *http.Conn, err, arg string) {
-       servePage(c, "Error", func () {
-               fmt.Fprintf(c, "%v (%s)\n", err, arg);
-       });
+       servePage(c, "Error", fmt.Sprintf("%v (%s)\n", err, arg));
 }
 
 
@@ -260,28 +280,29 @@ func serveDir(c *http.Conn, dirname string) {
        path := dirname + "/";
 
        // Print contents in 3 sections: directories, go files, everything else
-       servePage(c, dirname + " - Contents", func () {
-               fmt.Fprintln(c, "<h2>Directories</h2>");
-               for i, entry := range list {
-                       if entry.IsDirectory() {
-                               printLink(c, path, entry.Name);
-                       }
+       var b io.ByteBuffer;
+       fmt.Fprintln(&b, "<h2>Directories</h2>");
+       for i, entry := range list {
+               if entry.IsDirectory() {
+                       printLink(&b, path, entry.Name);
                }
+       }
 
-               fmt.Fprintln(c, "<h2>Go files</h2>");
-               for i, entry := range list {
-                       if isGoFile(&entry) {
-                               printLink(c, path, entry.Name);
-                       }
+       fmt.Fprintln(&b, "<h2>Go files</h2>");
+       for i, entry := range list {
+               if isGoFile(&entry) {
+                       printLink(&b, path, entry.Name);
                }
+       }
 
-               fmt.Fprintln(c, "<h2>Other files</h2>");
-               for i, entry := range list {
-                       if !entry.IsDirectory() && !isGoFile(&entry) {
-                               fmt.Fprintf(c, "%s<br />\n", entry.Name);
-                       }
+       fmt.Fprintln(&b, "<h2>Other files</h2>");
+       for i, entry := range list {
+               if !entry.IsDirectory() && !isGoFile(&entry) {
+                       fmt.Fprintf(&b, "%s<br />\n", entry.Name);
                }
-       });
+       }
+
+       servePage(c, dirname + " - Contents", b.Data());
 }
 
 
@@ -307,35 +328,36 @@ func serveParseErrors(c *http.Conn, filename string, errors errorList) {
        }
        src := buf.Data();
 
-       // TODO handle Apply errors
-       servePage(c, filename, func () {
-               // section title
-               fmt.Fprintf(c, "<h1>Parse errors in %s</h1>\n", filename);
+       // generate body
+       var b io.ByteBuffer;
+       // section title
+       fmt.Fprintf(&b, "<h1>Parse errors in %s</h1>\n", filename);
 
-               // handle read errors
-               if err1 != nil || err2 != nil {
-                       fmt.Fprintf(c, "could not read file %s\n", filename);
-                       return;
-               }
+       // handle read errors
+       if err1 != nil || err2 != nil {
+               fmt.Fprintf(&b, "could not read file %s\n", filename);
+               return;
+       }
 
-               // write source with error messages interspersed
-               fmt.Fprintln(c, "<pre>");
-               offs := 0;
-               for i, e := range errors {
-                       if 0 <= e.pos.Offset && e.pos.Offset <= len(src) {
-                               // TODO handle Write errors
-                               c.Write(src[offs : e.pos.Offset]);
-                               // TODO this should be done using a .css file
-                               fmt.Fprintf(c, "<b><font color=red>%s >>></font></b>", e.msg);
-                               offs = e.pos.Offset;
-                       } else {
-                               log.Stdoutf("error position %d out of bounds (len = %d)", e.pos.Offset, len(src));
-                       }
+       // write source with error messages interspersed
+       fmt.Fprintln(&b, "<pre>");
+       offs := 0;
+       for i, e := range errors {
+               if 0 <= e.pos.Offset && e.pos.Offset <= len(src) {
+                       // TODO handle Write errors
+                       b.Write(src[offs : e.pos.Offset]);
+                       // TODO this should be done using a .css file
+                       fmt.Fprintf(&b, "<b><font color=red>%s >>></font></b>", e.msg);
+                       offs = e.pos.Offset;
+               } else {
+                       log.Stdoutf("error position %d out of bounds (len = %d)", e.pos.Offset, len(src));
                }
-               // TODO handle Write errors
-               c.Write(src[offs : len(src)]);
-               fmt.Fprintln(c, "</pre>");
-       });
+       }
+       // TODO handle Write errors
+       b.Write(src[offs : len(src)]);
+       fmt.Fprintln(&b, "</pre>");
+
+       servePage(c, filename, b.Data());
 }
 
 
@@ -347,15 +369,16 @@ func serveGoSource(c *http.Conn, dirname string, filename string) {
                return;
        }
 
-       servePage(c, path + " - Go source", func () {
-               fmt.Fprintln(c, "<pre>");
-               var p astPrinter.Printer;
-               writer := makeTabwriter(c);  // for nicely formatted output
-               p.Init(writer, nil, nil, true);
-               p.DoProgram(prog);
-               writer.Flush();  // ignore errors
-               fmt.Fprintln(c, "</pre>");
-       });
+       var b io.ByteBuffer;
+       fmt.Fprintln(&b, "<pre>");
+       var p astPrinter.Printer;
+       writer := makeTabwriter(&b);  // for nicely formatted output
+       p.Init(writer, nil, nil, true);
+       p.DoProgram(prog);
+       writer.Flush();  // ignore errors
+       fmt.Fprintln(&b, "</pre>");
+
+       servePage(c, path + " - Go source", b.Data());
 }
 
 
@@ -410,7 +433,7 @@ func (p pakArray) Swap(i, j int)       { p[i], p[j] = p[j], p[i]; }
 
 
 func addFile(pmap map[string]*pakDesc, dirname string, filename string) {
-       if hasSuffix(filename, "_test.go") {
+       if strings.HasSuffix(filename, "_test.go") {
                // ignore package tests
                return;
        }
@@ -507,23 +530,25 @@ func servePackage(c *http.Conn, p *pakDesc) {
                doc.AddProgram(prog);
        }
 
-       servePage(c, doc.PackageName() + " - Go package documentation", func () {
-               writer := makeTabwriter(c);  // for nicely formatted output
-               doc.Print(writer);
-               writer.Flush();  // ignore errors
-       });
+       var b io.ByteBuffer;
+       writer := makeTabwriter(&b);  // for nicely formatted output
+       doc.Print(writer);
+       writer.Flush(); // ignore errors
+
+       servePage(c, doc.PackageName() + " - Go package documentation", b.Data());
 }
 
 
 func servePackageList(c *http.Conn, list pakArray) {
-       servePage(c, "Packages", func () {
-               for i := 0; i < len(list); i++ {
-                       p := list[i];
-                       link := pathutil.Clean(p.dirname + "/" + p.pakname);
-                       fmt.Fprintf(c, "<a href=\"%s\">%s</a> <font color=grey>(%s)</font><br />\n",
-                               p.pakname, p.pakname, link);
-               }
-       });
+       var b io.ByteBuffer;
+       for i := 0; i < len(list); i++ {
+               p := list[i];
+               link := pathutil.Clean(p.dirname + "/" + p.pakname);
+               fmt.Fprintf(&b, "<a href=\"%s\">%s</a> <font color=grey>(%s)</font><br />\n",
+                       p.pakname, p.pakname, link);
+       }
+
+       servePage(c, "Packages", b.Data());
 
        // TODO: show subdirectories
 }
diff --git a/usr/gri/pretty/template.go b/usr/gri/pretty/template.go
deleted file mode 100644 (file)
index 9aa83d4..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package template
-
-import (
-       "os";
-       "io";
-)
-
-
-type Template struct {
-       template []byte;
-}
-
-
-func (T *Template) Init(filename string) *os.Error {
-       f, err0 := os.Open(filename, os.O_RDONLY, 0);
-       defer f.Close();
-       if err0 != nil {
-               return err0;
-       }
-
-       var buf io.ByteBuffer;
-       len, err1 := io.Copy(f, &buf);
-       if err1 == io.ErrEOF {
-               err1 = nil;
-       }
-       if err1 != nil {
-               return err1;
-       }
-
-       T.template = buf.Data();
-
-       return nil;
-}
-
-
-// Returns true if buf starts with s, returns false otherwise.
-//
-func match(buf []byte, s string) bool {
-       if len(buf) < len(s) {
-               return false;
-       }
-       for i := 0; i < len(s); i++ {
-               if buf[i] != s[i] {
-                       return false;
-               }
-       }
-       return true;
-}
-
-
-// Find the position of string s in buf, starting at i.
-// Returns a value < 0 if not found.
-//
-func find(buf []byte, s string, i int) int {
-    if s == "" {
-        return i;
-    }
-L:     for ; i + len(s) <= len(buf); i++ {
-               for k := 0; k < len(s); k++ {
-                       if buf[i+k] != s[k] {
-                               continue L;
-                       }
-               }
-               return i;
-    }
-    return -1
-}
-
-
-type Substitution map [string] func()
-
-func (T *Template) Apply(w io.Write, prefix string, subs Substitution) *os.Error {
-       i0 := 0;  // position from which to write from the template
-       i1 := 0;  // position from which to look for the next prefix
-
-       for {
-               // look for a prefix
-               i2 := find(T.template, prefix, i1);  // position of prefix, if any
-               if i2 < 0 {
-                       // no prefix found, we are done
-                       break;
-               }
-
-               // we have a prefix, look for a matching key
-               i1 = i2 + len(prefix);
-               for key, action := range subs {
-                       if match(T.template[i1 : len(T.template)], key) {
-                               // found a match
-                               i1 += len(key);  // next search starting pos
-                               len, err := w.Write(T.template[i0 : i2]);  // TODO handle errors
-                               i0 = i1;  // skip placeholder
-                               action();
-                               break;
-                       }
-               }
-       }
-
-       // write the rest of the template
-       len, err := w.Write(T.template[i0 : len(T.template)]);  // TODO handle errors
-       return err;
-}
-
-
-func NewTemplate(filename string) *Template {
-       t := new(Template);
-       if t.Init(filename) != nil {
-               return nil;
-       }
-       return t;
-}
-
-
-func NewTemplateOrDie(filename string) *Template {
-       t := NewTemplate(filename);
-       if t == nil {
-               panic("could not read template: " + filename);
-       }
-       return t;
-}