Commit be56b957 authored by Robert Griesemer's avatar Robert Griesemer

- show recursive package directory structure in package pages

- removed some underbars in section headings for better looks
- various minor tweaks

R=rsc
http://go/go-review/1018026
parent 6e98b7f0
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
code, .code { code, .code {
font-size: 100%; font-size: 100%;
font-family: monospace; font-family: monospace;
color:#007000; color: #007000;
} }
kbd { kbd {
...@@ -149,12 +149,19 @@ div#linkList li.navhead { ...@@ -149,12 +149,19 @@ div#linkList li.navhead {
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
/* Styles used by go/printer Styler implementations. */ /* Styles used by godoc */
a.noline { a.noline {
text-decoration: none; text-decoration: none;
} }
table.layout {
border-width: 0px;
border-spacing: 0px;
border-width: 0px;
padding: 0px;
}
span.comment { span.comment {
color: #0000a0; color: #0000a0;
} }
......
<table border="0" cellpadding="0" cellspacing="0"> <table class="layout">
<tr><td><a href="{Path|html}">{Name|html}</a></td></tr> <tr><td colspan="2"><a href="/pkg/{Path|html}">{Name|html}</a></td></tr>
{.repeated section Subdirs} {.repeated section Dirs}
<tr><td></td><td>{@|dir}</td></tr> <tr><td width="25em"></td><td>{@|dir}</td></tr>
{.end} {.end}
</table> </table>
...@@ -34,14 +34,14 @@ ...@@ -34,14 +34,14 @@
{.end} {.end}
{.section Funcs} {.section Funcs}
{.repeated section @} {.repeated section @}
<h2>func <a href="{Decl|link}">{Name|html}</a></h2> <h2>func <a href="{Decl|link}" class="noline">{Name|html}</a></h2>
<p><code>{Decl|html}</code></p> <p><code>{Decl|html}</code></p>
{Doc|html-comment} {Doc|html-comment}
{.end} {.end}
{.end} {.end}
{.section Types} {.section Types}
{.repeated section @} {.repeated section @}
<h2>type <a href="{Decl|link}">{Type.Name|html}</a></h2> <h2>type <a href="{Decl|link}" class="noline">{Type.Name|html}</a></h2>
{Doc|html-comment} {Doc|html-comment}
<p><pre>{Decl|html}</pre></p> <p><pre>{Decl|html}</pre></p>
{.repeated section Consts} {.repeated section Consts}
...@@ -53,12 +53,12 @@ ...@@ -53,12 +53,12 @@
<pre>{Decl|html}</pre> <pre>{Decl|html}</pre>
{.end} {.end}
{.repeated section Factories} {.repeated section Factories}
<h3>func <a href="{Decl|link}">{Name|html}</a></h3> <h3>func <a href="{Decl|link}" class="noline">{Name|html}</a></h3>
<p><code>{Decl|html}</code></p> <p><code>{Decl|html}</code></p>
{Doc|html-comment} {Doc|html-comment}
{.end} {.end}
{.repeated section Methods} {.repeated section Methods}
<h3>func ({Recv|html}) <a href="{Decl|link}">{Name|html}</a></h3> <h3>func ({Recv|html}) <a href="{Decl|link}" class="noline">{Name|html}</a></h3>
<p><code>{Decl|html}</code></p> <p><code>{Decl|html}</code></p>
{Doc|html-comment} {Doc|html-comment}
{.end} {.end}
...@@ -72,8 +72,10 @@ ...@@ -72,8 +72,10 @@
{.end} {.end}
{.end} {.end}
{.section Dirs} {.section Dirs}
<h2>Subdirectories</h2> {.section Dirs}
{.repeated section @} <h2>Subdirectories</h2>
<a href="{Name|html}">{Name|html}</a><br /> {.repeated section @}
{@|dir}
{.end}
{.end} {.end}
{.end} {.end}
...@@ -69,6 +69,7 @@ BUGS ...@@ -69,6 +69,7 @@ BUGS
{.end} {.end}
{.end} {.end}
{.section Dirs} {.section Dirs}
{.section Dirs}
SUBDIRECTORIES SUBDIRECTORIES
...@@ -76,3 +77,4 @@ SUBDIRECTORIES ...@@ -76,3 +77,4 @@ SUBDIRECTORIES
{Name} {Name}
{.end} {.end}
{.end} {.end}
{.end}
...@@ -6,7 +6,6 @@ package main ...@@ -6,7 +6,6 @@ package main
import ( import (
"bytes"; "bytes";
"container/vector";
"flag"; "flag";
"fmt"; "fmt";
"go/ast"; "go/ast";
...@@ -20,7 +19,6 @@ import ( ...@@ -20,7 +19,6 @@ import (
"log"; "log";
"os"; "os";
pathutil "path"; pathutil "path";
"sort";
"strings"; "strings";
"sync"; "sync";
"template"; "template";
...@@ -128,54 +126,100 @@ func htmlEscape(s string) string { ...@@ -128,54 +126,100 @@ func htmlEscape(s string) string {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Directory trees // Package directories
type Directory struct { type Directory struct {
Path string; // including Name Path string; // relative to *pkgroot, includes Name
Name string; Name string;
Subdirs []*Directory Dirs []*Directory;
} }
func newDirTree0(path, name string) *Directory { func newDirTree(path, name string, depth int) *Directory {
list, _ := io.ReadDir(path); // ignore errors if depth <= 0 {
// determine number of subdirectories n // return a dummy directory so that the parent directory
n := 0; // doesn't get discarded just because we reached the max
// directory depth
return &Directory{path, name, nil};
}
fullpath := pathutil.Join(*pkgroot, path);
list, _ := io.ReadDir(fullpath); // ignore errors
// determine number of subdirectories and package files
ndirs := 0;
nfiles := 0;
for _, d := range list { for _, d := range list {
if isPkgDir(d) { switch {
n++; case isPkgDir(d):
ndirs++;
case isPkgFile(d):
nfiles++;
} }
} }
// create Directory node
var subdirs []*Directory; // create subdirectory tree
if n > 0 { var dirs []*Directory;
subdirs = make([]*Directory, n); if ndirs > 0 {
dirs = make([]*Directory, ndirs);
i := 0; i := 0;
for _, d := range list { for _, d := range list {
if isPkgDir(d) { if isPkgDir(d) {
subdirs[i] = newDirTree0(pathutil.Join(path, d.Name), d.Name); dd := newDirTree(pathutil.Join(path, d.Name), d.Name, depth-1);
i++; if dd != nil {
dirs[i] = dd;
i++;
}
} }
} }
dirs = dirs[0:i];
} }
if strings.HasPrefix(path, "src/") {
path = path[len("src/") : len(path)]; // if there are no package files and no subdirectories
// (with package files), ignore the directory
if nfiles == 0 && len(dirs) == 0 {
return nil;
} }
return &Directory{path, name, subdirs};
return &Directory{path, name, dirs};
} }
func newDirTree(root string) *Directory { // newDirectory creates a new package directory tree with at most depth
d, err := os.Lstat(root); // levels, anchored at root which is relative to Pkg. The result tree
if err != nil { // only contains directories that contain package files or that contain
log.Stderrf("%v", err); // subdirectories containing package files (transitively).
//
func newDirectory(root string, depth int) *Directory {
fullpath := pathutil.Join(*pkgroot, root);
d, err := os.Lstat(fullpath);
if err != nil || !isPkgDir(d) {
return nil; return nil;
} }
if !isPkgDir(d) { return newDirTree(root, d.Name, depth);
log.Stderrf("not a package directory: %s", d.Name); }
return nil;
// lookup looks for the *Directory for a given path, relative to dir.
func (dir *Directory) lookup(path string) *Directory {
path = pathutil.Clean(path); // no trailing '/'
if dir == nil || path == "" || path == "." {
return dir;
} }
return newDirTree0(root, d.Name);
dpath, dname := pathutil.Split(path);
if dpath == "" {
// directory-local name
for _, d := range dir.Dirs {
if dname == d.Name {
return d;
}
}
return nil
}
return dir.lookup(dpath).lookup(dname);
} }
...@@ -610,20 +654,6 @@ func serveFile(c *http.Conn, r *http.Request) { ...@@ -610,20 +654,6 @@ func serveFile(c *http.Conn, r *http.Request) {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Packages // Packages
// TODO if we don't plan to use the directory information, simplify to []string
type dirList []*os.Dir
func (d dirList) Len() int {
return len(d);
}
func (d dirList) Less(i, j int) bool {
return d[i].Name < d[j].Name;
}
func (d dirList) Swap(i, j int) {
d[i], d[j] = d[j], d[i];
}
func pkgName(filename string) string { func pkgName(filename string) string {
file, err := parse(filename, parser.PackageClauseOnly); file, err := parse(filename, parser.PackageClauseOnly);
if err != nil || file == nil { if err != nil || file == nil {
...@@ -635,7 +665,7 @@ func pkgName(filename string) string { ...@@ -635,7 +665,7 @@ func pkgName(filename string) string {
type PageInfo struct { type PageInfo struct {
PDoc *doc.PackageDoc; // nil if no package found PDoc *doc.PackageDoc; // nil if no package found
Dirs dirList; // nil if no subdirectories found Dirs *Directory; // nil if no directory information found
} }
...@@ -651,10 +681,7 @@ func getPageInfo(path string) PageInfo { ...@@ -651,10 +681,7 @@ func getPageInfo(path string) PageInfo {
// the package name is the directory name within its parent // the package name is the directory name within its parent
_, pkgname := pathutil.Split(dirname); _, pkgname := pathutil.Split(dirname);
// filter function to select the desired .go files and // filter function to select the desired .go files
// collect subdirectories
var subdirlist vector.Vector;
subdirlist.Init(0);
filter := func(d *os.Dir) bool { filter := func(d *os.Dir) bool {
if isPkgFile(d) { if isPkgFile(d) {
// Some directories contain main packages: Only accept // Some directories contain main packages: Only accept
...@@ -663,9 +690,6 @@ func getPageInfo(path string) PageInfo { ...@@ -663,9 +690,6 @@ func getPageInfo(path string) PageInfo {
// found" errors. // found" errors.
return pkgName(dirname + "/" + d.Name) == pkgname; return pkgName(dirname + "/" + d.Name) == pkgname;
} }
if isPkgDir(d) {
subdirlist.Push(d);
}
return false; return false;
}; };
...@@ -673,17 +697,7 @@ func getPageInfo(path string) PageInfo { ...@@ -673,17 +697,7 @@ func getPageInfo(path string) PageInfo {
pkg, err := parser.ParsePackage(dirname, filter, parser.ParseComments); pkg, err := parser.ParsePackage(dirname, filter, parser.ParseComments);
if err != nil { if err != nil {
// TODO: parse errors should be shown instead of an empty directory // TODO: parse errors should be shown instead of an empty directory
log.Stderr(err); log.Stderrf("parser.parsePackage: %s", err);
}
// convert and sort subdirectory list, if any
var subdirs dirList;
if subdirlist.Len() > 0 {
subdirs = make(dirList, subdirlist.Len());
for i := 0; i < subdirlist.Len(); i++ {
subdirs[i] = subdirlist.At(i).(*os.Dir);
}
sort.Sort(subdirs);
} }
// compute package documentation // compute package documentation
...@@ -693,7 +707,20 @@ func getPageInfo(path string) PageInfo { ...@@ -693,7 +707,20 @@ func getPageInfo(path string) PageInfo {
pdoc = doc.NewPackageDoc(pkg, pathutil.Clean(path)); // no trailing '/' in importpath pdoc = doc.NewPackageDoc(pkg, pathutil.Clean(path)); // no trailing '/' in importpath
} }
return PageInfo{pdoc, subdirs}; // get directory information
var dir *Directory;
if tree, _ := pkgTree.get(); tree != nil {
// directory tree is present; lookup respective directory
// (may still fail if the file system was updated and the
// new directory tree has not yet beet computed)
dir = tree.(*Directory).lookup(pathutil.Clean(path));
} else {
// no directory tree present (either early after startup
// or command-line mode); compute one level for this page
dir = newDirectory(path, 1);
}
return PageInfo{pdoc, dir};
} }
...@@ -734,21 +761,6 @@ func servePkg(c *http.Conn, r *http.Request) { ...@@ -734,21 +761,6 @@ func servePkg(c *http.Conn, r *http.Request) {
} }
// ----------------------------------------------------------------------------
// Directory tree
// TODO(gri): Temporary - integrate with package serving.
func serveTree(c *http.Conn, r *http.Request) {
dir, _ := pkgTree.get();
var buf bytes.Buffer;
dirFmt(&buf, dir, "");
servePage(c, "Package tree", "", buf.Bytes());
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Search // Search
...@@ -795,7 +807,6 @@ func search(c *http.Conn, r *http.Request) { ...@@ -795,7 +807,6 @@ func search(c *http.Conn, r *http.Request) {
func registerPublicHandlers(mux *http.ServeMux) { func registerPublicHandlers(mux *http.ServeMux) {
mux.Handle(Pkg, http.HandlerFunc(servePkg)); mux.Handle(Pkg, http.HandlerFunc(servePkg));
mux.Handle("/tree", http.HandlerFunc(serveTree)); // TODO(gri): integrate with package serving
mux.Handle("/search", http.HandlerFunc(search)); mux.Handle("/search", http.HandlerFunc(search));
mux.Handle("/", http.HandlerFunc(serveFile)); mux.Handle("/", http.HandlerFunc(serveFile));
} }
......
...@@ -97,13 +97,19 @@ func exec(c *http.Conn, args []string) (status int) { ...@@ -97,13 +97,19 @@ func exec(c *http.Conn, args []string) (status int) {
} }
// Maximum package directory depth, adjust as needed.
const maxPkgDirDepth = 16;
func dosync(c *http.Conn, r *http.Request) { func dosync(c *http.Conn, r *http.Request) {
args := []string{"/bin/sh", "-c", *syncCmd}; args := []string{"/bin/sh", "-c", *syncCmd};
switch exec(c, args) { switch exec(c, args) {
case 0: case 0:
// sync succeeded and some files have changed; // sync succeeded and some files have changed;
// update package tree // update package tree.
pkgTree.set(newDirTree(*pkgroot)); // TODO(gri): The directory tree may be temporarily out-of-sync.
// Consider keeping separate time stamps so the web-
// page can indicate this discrepancy.
pkgTree.set(newDirectory(".", maxPkgDirDepth));
fallthrough; fallthrough;
case 1: case 1:
// sync failed because no files changed; // sync failed because no files changed;
...@@ -156,6 +162,7 @@ func main() { ...@@ -156,6 +162,7 @@ func main() {
readTemplates(); readTemplates();
if *httpaddr != "" { if *httpaddr != "" {
// Http server mode.
var handler http.Handler = http.DefaultServeMux; var handler http.Handler = http.DefaultServeMux;
if *verbose { if *verbose {
log.Stderrf("Go Documentation Server\n"); log.Stderrf("Go Documentation Server\n");
...@@ -171,8 +178,14 @@ func main() { ...@@ -171,8 +178,14 @@ func main() {
http.Handle("/debug/sync", http.HandlerFunc(dosync)); http.Handle("/debug/sync", http.HandlerFunc(dosync));
} }
// Compute package tree with corresponding timestamp. // Initialize package tree with corresponding timestamp.
pkgTree.set(newDirTree(*pkgroot)); // Do it in two steps:
// 1) set timestamp right away so that the indexer is kicked on
pkgTree.set(nil);
// 2) compute initial package tree in a goroutine so that launch is quick
go func() {
pkgTree.set(newDirectory(".", maxPkgDirDepth));
}();
// Start sync goroutine, if enabled. // Start sync goroutine, if enabled.
if *syncCmd != "" && *syncMin > 0 { if *syncCmd != "" && *syncMin > 0 {
...@@ -206,9 +219,6 @@ func main() { ...@@ -206,9 +219,6 @@ func main() {
} }
// Command line mode. // Command line mode.
// No package tree; set it to nil so we have a reasonable time stamp.
pkgTree.set(nil);
if *html { if *html {
packageText = packageHtml; packageText = packageHtml;
parseerrorText = parseerrorHtml; parseerrorText = parseerrorHtml;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment