mirror of
https://github.com/golang/go
synced 2024-11-24 17:10:03 -07:00
- 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
This commit is contained in:
parent
6e98b7f0b2
commit
be56b95770
@ -10,7 +10,7 @@
|
||||
code, .code {
|
||||
font-size: 100%;
|
||||
font-family: monospace;
|
||||
color:#007000;
|
||||
color: #007000;
|
||||
}
|
||||
|
||||
kbd {
|
||||
@ -149,12 +149,19 @@ div#linkList li.navhead {
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* Styles used by go/printer Styler implementations. */
|
||||
/* Styles used by godoc */
|
||||
|
||||
a.noline {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
table.layout {
|
||||
border-width: 0px;
|
||||
border-spacing: 0px;
|
||||
border-width: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
span.comment {
|
||||
color: #0000a0;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
<table border="0" cellpadding="0" cellspacing="0">
|
||||
<tr><td><a href="{Path|html}">{Name|html}</a></td></tr>
|
||||
{.repeated section Subdirs}
|
||||
<tr><td></td><td>{@|dir}</td></tr>
|
||||
<table class="layout">
|
||||
<tr><td colspan="2"><a href="/pkg/{Path|html}">{Name|html}</a></td></tr>
|
||||
{.repeated section Dirs}
|
||||
<tr><td width="25em"></td><td>{@|dir}</td></tr>
|
||||
{.end}
|
||||
</table>
|
||||
|
@ -34,14 +34,14 @@
|
||||
{.end}
|
||||
{.section Funcs}
|
||||
{.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>
|
||||
{Doc|html-comment}
|
||||
{.end}
|
||||
{.end}
|
||||
{.section Types}
|
||||
{.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}
|
||||
<p><pre>{Decl|html}</pre></p>
|
||||
{.repeated section Consts}
|
||||
@ -53,12 +53,12 @@
|
||||
<pre>{Decl|html}</pre>
|
||||
{.end}
|
||||
{.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>
|
||||
{Doc|html-comment}
|
||||
{.end}
|
||||
{.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>
|
||||
{Doc|html-comment}
|
||||
{.end}
|
||||
@ -72,8 +72,10 @@
|
||||
{.end}
|
||||
{.end}
|
||||
{.section Dirs}
|
||||
<h2>Subdirectories</h2>
|
||||
{.repeated section @}
|
||||
<a href="{Name|html}">{Name|html}</a><br />
|
||||
{.section Dirs}
|
||||
<h2>Subdirectories</h2>
|
||||
{.repeated section @}
|
||||
{@|dir}
|
||||
{.end}
|
||||
{.end}
|
||||
{.end}
|
||||
|
@ -69,6 +69,7 @@ BUGS
|
||||
{.end}
|
||||
{.end}
|
||||
{.section Dirs}
|
||||
{.section Dirs}
|
||||
|
||||
SUBDIRECTORIES
|
||||
|
||||
@ -76,3 +77,4 @@ SUBDIRECTORIES
|
||||
{Name}
|
||||
{.end}
|
||||
{.end}
|
||||
{.end}
|
||||
|
@ -6,7 +6,6 @@ package main
|
||||
|
||||
import (
|
||||
"bytes";
|
||||
"container/vector";
|
||||
"flag";
|
||||
"fmt";
|
||||
"go/ast";
|
||||
@ -20,7 +19,6 @@ import (
|
||||
"log";
|
||||
"os";
|
||||
pathutil "path";
|
||||
"sort";
|
||||
"strings";
|
||||
"sync";
|
||||
"template";
|
||||
@ -128,54 +126,100 @@ func htmlEscape(s string) string {
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Directory trees
|
||||
// Package directories
|
||||
|
||||
type Directory struct {
|
||||
Path string; // including Name
|
||||
Path string; // relative to *pkgroot, includes Name
|
||||
Name string;
|
||||
Subdirs []*Directory
|
||||
Dirs []*Directory;
|
||||
}
|
||||
|
||||
|
||||
func newDirTree0(path, name string) *Directory {
|
||||
list, _ := io.ReadDir(path); // ignore errors
|
||||
// determine number of subdirectories n
|
||||
n := 0;
|
||||
func newDirTree(path, name string, depth int) *Directory {
|
||||
if depth <= 0 {
|
||||
// return a dummy directory so that the parent directory
|
||||
// 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 {
|
||||
if isPkgDir(d) {
|
||||
n++;
|
||||
switch {
|
||||
case isPkgDir(d):
|
||||
ndirs++;
|
||||
case isPkgFile(d):
|
||||
nfiles++;
|
||||
}
|
||||
}
|
||||
// create Directory node
|
||||
var subdirs []*Directory;
|
||||
if n > 0 {
|
||||
subdirs = make([]*Directory, n);
|
||||
|
||||
// create subdirectory tree
|
||||
var dirs []*Directory;
|
||||
if ndirs > 0 {
|
||||
dirs = make([]*Directory, ndirs);
|
||||
i := 0;
|
||||
for _, d := range list {
|
||||
if isPkgDir(d) {
|
||||
subdirs[i] = newDirTree0(pathutil.Join(path, d.Name), d.Name);
|
||||
i++;
|
||||
dd := newDirTree(pathutil.Join(path, d.Name), d.Name, depth-1);
|
||||
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 {
|
||||
d, err := os.Lstat(root);
|
||||
if err != nil {
|
||||
log.Stderrf("%v", err);
|
||||
// newDirectory creates a new package directory tree with at most depth
|
||||
// levels, anchored at root which is relative to Pkg. The result tree
|
||||
// only contains directories that contain package files or that contain
|
||||
// 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;
|
||||
}
|
||||
if !isPkgDir(d) {
|
||||
log.Stderrf("not a package directory: %s", d.Name);
|
||||
return nil;
|
||||
return newDirTree(root, d.Name, depth);
|
||||
}
|
||||
|
||||
|
||||
// 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) {
|
||||
// ----------------------------------------------------------------------------
|
||||
// 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 {
|
||||
file, err := parse(filename, parser.PackageClauseOnly);
|
||||
if err != nil || file == nil {
|
||||
@ -635,7 +665,7 @@ func pkgName(filename string) string {
|
||||
|
||||
type PageInfo struct {
|
||||
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 {
|
||||
// the package name is the directory name within its parent
|
||||
_, pkgname := pathutil.Split(dirname);
|
||||
|
||||
// filter function to select the desired .go files and
|
||||
// collect subdirectories
|
||||
var subdirlist vector.Vector;
|
||||
subdirlist.Init(0);
|
||||
// filter function to select the desired .go files
|
||||
filter := func(d *os.Dir) bool {
|
||||
if isPkgFile(d) {
|
||||
// Some directories contain main packages: Only accept
|
||||
@ -663,9 +690,6 @@ func getPageInfo(path string) PageInfo {
|
||||
// found" errors.
|
||||
return pkgName(dirname + "/" + d.Name) == pkgname;
|
||||
}
|
||||
if isPkgDir(d) {
|
||||
subdirlist.Push(d);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
@ -673,17 +697,7 @@ func getPageInfo(path string) PageInfo {
|
||||
pkg, err := parser.ParsePackage(dirname, filter, parser.ParseComments);
|
||||
if err != nil {
|
||||
// TODO: parse errors should be shown instead of an empty directory
|
||||
log.Stderr(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);
|
||||
log.Stderrf("parser.parsePackage: %s", err);
|
||||
}
|
||||
|
||||
// compute package documentation
|
||||
@ -693,7 +707,20 @@ func getPageInfo(path string) PageInfo {
|
||||
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) {
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// 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
|
||||
|
||||
@ -795,7 +807,6 @@ func search(c *http.Conn, r *http.Request) {
|
||||
|
||||
func registerPublicHandlers(mux *http.ServeMux) {
|
||||
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("/", http.HandlerFunc(serveFile));
|
||||
}
|
||||
|
@ -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) {
|
||||
args := []string{"/bin/sh", "-c", *syncCmd};
|
||||
switch exec(c, args) {
|
||||
case 0:
|
||||
// sync succeeded and some files have changed;
|
||||
// update package tree
|
||||
pkgTree.set(newDirTree(*pkgroot));
|
||||
// update package tree.
|
||||
// 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;
|
||||
case 1:
|
||||
// sync failed because no files changed;
|
||||
@ -156,6 +162,7 @@ func main() {
|
||||
readTemplates();
|
||||
|
||||
if *httpaddr != "" {
|
||||
// Http server mode.
|
||||
var handler http.Handler = http.DefaultServeMux;
|
||||
if *verbose {
|
||||
log.Stderrf("Go Documentation Server\n");
|
||||
@ -171,8 +178,14 @@ func main() {
|
||||
http.Handle("/debug/sync", http.HandlerFunc(dosync));
|
||||
}
|
||||
|
||||
// Compute package tree with corresponding timestamp.
|
||||
pkgTree.set(newDirTree(*pkgroot));
|
||||
// Initialize package tree with corresponding timestamp.
|
||||
// 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.
|
||||
if *syncCmd != "" && *syncMin > 0 {
|
||||
@ -206,9 +219,6 @@ func main() {
|
||||
}
|
||||
|
||||
// Command line mode.
|
||||
// No package tree; set it to nil so we have a reasonable time stamp.
|
||||
pkgTree.set(nil);
|
||||
|
||||
if *html {
|
||||
packageText = packageHtml;
|
||||
parseerrorText = parseerrorHtml;
|
||||
|
Loading…
Reference in New Issue
Block a user