]> Cypherpunks repositories - gostls13.git/commitdiff
godoc: support for multiple packages in a directory
authorRobert Griesemer <gri@golang.org>
Sat, 13 Mar 2010 02:16:21 +0000 (18:16 -0800)
committerRobert Griesemer <gri@golang.org>
Sat, 13 Mar 2010 02:16:21 +0000 (18:16 -0800)
- smartly select the "right" package
- provide a list of other packages

R=rsc
CC=golang-dev
https://golang.org/cl/466042

lib/godoc/package.html
lib/godoc/package.txt
src/cmd/godoc/godoc.go
src/cmd/godoc/main.go

index c0cd18f31331762e1fb90f0dd56e18733b7a8e73..d0a5970b38d0b26c2832433b8b8719668fc4552a 100644 (file)
                {.end}
        {.end}
 {.end}
+{.section PList}
+       <h2>Other packages</h2>
+       <p>
+       {.repeated section @}
+       <a href="?p={@|html}">{@|html}</a><br />
+       {.end}
+       </p>
+{.end}
 {.section Dirs}
        <h2 id="Subdirectories">Subdirectories</h2>
        <p>
index b9203ff217ad66e5481690bfcd1e65db12716a3b..124771edd1291d0f49a6ba7ceff6505f2fce083e 100644 (file)
@@ -75,6 +75,14 @@ BUGS
 {.end}
 {.end}
 {.end}
+{.section PList}
+
+OTHER PACKAGES
+
+{.repeated section @}
+{@}
+{.end}
+{.end}
 {.section Dirs}
 {.section Dirs}
 
index 04393c6dc2c9397a6cdeafa46642af7a9eccdaa1..067f82a5f91b73acf12a8baa8d6343670f10d732 100644 (file)
@@ -1087,8 +1087,9 @@ const fakePkgName = "documentation"
 
 type PageInfo struct {
        Dirname string          // directory containing the package
-       PAst    *ast.File       // nil if no AST with package exports
-       PDoc    *doc.PackageDoc // nil if no package documentation
+       PList   []string        // list of package names found
+       PAst    *ast.File       // nil if no single AST with package exports
+       PDoc    *doc.PackageDoc // nil if no single package documentation
        Dirs    *DirList        // nil if no directory information
        IsPkg   bool            // false if this is not documenting a real package
 }
@@ -1101,7 +1102,7 @@ type httpHandler struct {
 }
 
 
-// getPageInfo returns the PageInfo for a package directory dirname. If the
+// getPageInfo returns the PageInfo for a package directory abspath. If the
 // parameter genAST is set, an AST containing only the package exports is
 // computed (PageInfo.PAst), otherwise package documentation (PageInfo.Doc)
 // is extracted from the AST. If the parameter try is set, no errors are
@@ -1109,7 +1110,7 @@ type httpHandler struct {
 // directory, PageInfo.PDoc and PageInfo.PExp are nil. If there are no sub-
 // directories, PageInfo.Dirs is nil.
 //
-func (h *httpHandler) getPageInfo(dirname, relpath string, genAST, try bool) PageInfo {
+func (h *httpHandler) getPageInfo(abspath, relpath, pkgname string, genAST, try bool) PageInfo {
        // filter function to select the desired .go files
        filter := func(d *os.Dir) bool {
                // If we are looking at cmd documentation, only accept
@@ -1118,30 +1119,64 @@ func (h *httpHandler) getPageInfo(dirname, relpath string, genAST, try bool) Pag
        }
 
        // get package ASTs
-       pkgs, err := parser.ParseDir(dirname, filter, parser.ParseComments)
+       pkgs, err := parser.ParseDir(abspath, filter, parser.ParseComments)
        if err != nil && !try {
                // TODO: errors should be shown instead of an empty directory
                log.Stderrf("parser.parseDir: %s", err)
        }
-       if len(pkgs) != 1 && !try {
-               // TODO: should handle multiple packages,
-               //       error reporting disabled for now
-               // log.Stderrf("parser.parseDir: found %d packages", len(pkgs))
-       }
 
-       // Get the best matching package: either the first one, or the
-       // first one whose package name matches the directory name.
-       // The package name is the directory name within its parent.
-       _, pkgname := pathutil.Split(dirname)
-       var pkg *ast.Package
-       for _, p := range pkgs {
-               switch {
-               case pkg == nil:
+       // select package
+       var pkg *ast.Package // selected package
+       var plist []string   // list of other package (names), if any
+       if len(pkgs) == 1 {
+               // Exactly one package - select it.
+               for _, p := range pkgs {
                        pkg = p
-               case p.Name == pkgname:
-                       pkg = p
-                       break
                }
+
+       } else if len(pkgs) > 1 {
+               // Multiple packages - select the best matching package: The
+               // 1st choice is the package with pkgname, the 2nd choice is
+               // the package with dirname, and the 3rd choice is a package
+               // that is not called "main" if there is exactly one such
+               // package. Otherwise, don't select a package.
+               dirpath, dirname := pathutil.Split(abspath)
+
+               // If the dirname is "go" we might be in a sub-directory for
+               // .go files - use the outer directory name instead for better
+               // results.
+               if dirname == "go" {
+                       _, dirname = pathutil.Split(pathutil.Clean(dirpath))
+               }
+
+               var choice3 *ast.Package
+       loop:
+               for _, p := range pkgs {
+                       switch {
+                       case p.Name == pkgname:
+                               pkg = p
+                               break loop // 1st choice; we are done
+                       case p.Name == dirname:
+                               pkg = p // 2nd choice
+                       case p.Name != "main":
+                               choice3 = p
+                       }
+               }
+               if pkg == nil && len(pkgs) == 2 {
+                       pkg = choice3
+               }
+
+               // Compute the list of other packages
+               // (excluding the selected package, if any).
+               plist = make([]string, len(pkgs))
+               i := 0
+               for name, _ := range pkgs {
+                       if pkg == nil || name != pkg.Name {
+                               plist[i] = name
+                               i++
+                       }
+               }
+               plist = plist[0:i]
        }
 
        // compute package documentation
@@ -1163,16 +1198,16 @@ func (h *httpHandler) getPageInfo(dirname, relpath string, genAST, try bool) Pag
                // (may still fail if the file system was updated and the
                // new directory tree has not yet been computed)
                // TODO(gri) Need to build directory tree for fsMap entries
-               dir = tree.(*Directory).lookup(dirname)
+               dir = tree.(*Directory).lookup(abspath)
        }
        if dir == nil {
                // no directory tree present (either early after startup
                // or command-line mode, or we don't build a tree for the
                // directory; e.g. google3); compute one level for this page
-               dir = newDirectory(dirname, 1)
+               dir = newDirectory(abspath, 1)
        }
 
-       return PageInfo{dirname, past, pdoc, dir.listing(true), h.isPkg}
+       return PageInfo{abspath, plist, past, pdoc, dir.listing(true), h.isPkg}
 }
 
 
@@ -1183,7 +1218,7 @@ func (h *httpHandler) ServeHTTP(c *http.Conn, r *http.Request) {
 
        relpath := r.URL.Path[len(h.pattern):]
        abspath := absolutePath(relpath, h.fsRoot)
-       info := h.getPageInfo(abspath, relpath, r.FormValue("m") == "src", false)
+       info := h.getPageInfo(abspath, relpath, r.FormValue("p"), r.FormValue("m") == "src", false)
 
        if r.FormValue("f") == "text" {
                contents := applyTemplate(packageText, "packageText", info)
index 5436088f74596f3a284802f5cbfb4e42f8cf60b9..f7dc522f2f3da763e6131b485e13294bbb64ec19 100644 (file)
@@ -241,14 +241,16 @@ func main() {
                relpath = relativePath(path)
        }
 
-       info := pkgHandler.getPageInfo(abspath, relpath, *genAST, true)
+       // TODO(gri): Provide a mechanism (flag?) to select a package
+       //            if there are multiple packages in a directory.
+       info := pkgHandler.getPageInfo(abspath, relpath, "", *genAST, true)
 
        if info.PAst == nil && info.PDoc == nil && info.Dirs == nil {
                // try again, this time assume it's a command
                if len(path) > 0 && path[0] != '/' {
                        abspath = absolutePath(path, cmdHandler.fsRoot)
                }
-               info = cmdHandler.getPageInfo(abspath, relpath, false, false)
+               info = cmdHandler.getPageInfo(abspath, relpath, "", false, false)
        }
 
        if info.PDoc != nil && flag.NArg() > 1 {