]> Cypherpunks repositories - gostls13.git/commitdiff
godoc: moved package directory support code into separate file
authorRobert Griesemer <gri@golang.org>
Wed, 8 Sep 2010 00:21:00 +0000 (17:21 -0700)
committerRobert Griesemer <gri@golang.org>
Wed, 8 Sep 2010 00:21:00 +0000 (17:21 -0700)
- in prep. for some restructuring to be able to better deal
  with very large file systems
- moved a utility function into index.go
- no functionality changes, only code reorg.

R=r, adg1
CC=golang-dev
https://golang.org/cl/2098044

src/cmd/godoc/Makefile
src/cmd/godoc/dirtrees.go [new file with mode: 0644]
src/cmd/godoc/godoc.go
src/cmd/godoc/index.go

index 106f46effa53d942c443369595689b223f630050..f93324f281909f7a09c83de3f76f7df945e24375 100644 (file)
@@ -7,6 +7,7 @@ include ../../Make.inc
 TARG=godoc
 GOFILES=\
        codewalk.go\
+       dirtrees.go\
        godoc.go\
        index.go\
        main.go\
diff --git a/src/cmd/godoc/dirtrees.go b/src/cmd/godoc/dirtrees.go
new file mode 100644 (file)
index 0000000..937d104
--- /dev/null
@@ -0,0 +1,301 @@
+// Copyright 2010 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.
+
+// This file contains the code dealing with package directory trees.
+
+package main
+
+import (
+       "go/doc"
+       "go/parser"
+       "io/ioutil"
+       "os"
+       pathutil "path"
+       "strings"
+       "unicode"
+)
+
+
+type Directory struct {
+       Depth int
+       Path  string // includes Name
+       Name  string
+       Text  string       // package documentation, if any
+       Dirs  []*Directory // subdirectories
+}
+
+
+func isGoFile(f *os.FileInfo) bool {
+       return f.IsRegular() &&
+               !strings.HasPrefix(f.Name, ".") && // ignore .files
+               pathutil.Ext(f.Name) == ".go"
+}
+
+
+func isPkgFile(f *os.FileInfo) bool {
+       return isGoFile(f) &&
+               !strings.HasSuffix(f.Name, "_test.go") // ignore test files
+}
+
+
+func isPkgDir(f *os.FileInfo) bool {
+       return f.IsDirectory() && len(f.Name) > 0 && f.Name[0] != '_'
+}
+
+
+func firstSentence(s string) string {
+       i := -1 // index+1 of first terminator (punctuation ending a sentence)
+       j := -1 // index+1 of first terminator followed by white space
+       prev := 'A'
+       for k, ch := range s {
+               k1 := k + 1
+               if ch == '.' || ch == '!' || ch == '?' {
+                       if i < 0 {
+                               i = k1 // first terminator
+                       }
+                       if k1 < len(s) && s[k1] <= ' ' {
+                               if j < 0 {
+                                       j = k1 // first terminator followed by white space
+                               }
+                               if !unicode.IsUpper(prev) {
+                                       j = k1
+                                       break
+                               }
+                       }
+               }
+               prev = ch
+       }
+
+       if j < 0 {
+               // use the next best terminator
+               j = i
+               if j < 0 {
+                       // no terminator at all, use the entire string
+                       j = len(s)
+               }
+       }
+
+       return s[0:j]
+}
+
+
+func newDirTree(path, name string, depth, maxDepth int) *Directory {
+       if depth >= maxDepth {
+               // return a dummy directory so that the parent directory
+               // doesn't get discarded just because we reached the max
+               // directory depth
+               return &Directory{depth, path, name, "", nil}
+       }
+
+       list, _ := ioutil.ReadDir(path) // ignore errors
+
+       // determine number of subdirectories and package files
+       ndirs := 0
+       nfiles := 0
+       var synopses [4]string // prioritized package documentation (0 == highest priority)
+       for _, d := range list {
+               switch {
+               case isPkgDir(d):
+                       ndirs++
+               case isPkgFile(d):
+                       nfiles++
+                       if synopses[0] == "" {
+                               // no "optimal" package synopsis yet; continue to collect synopses
+                               file, err := parser.ParseFile(pathutil.Join(path, d.Name), nil,
+                                       parser.ParseComments|parser.PackageClauseOnly)
+                               if err == nil && file.Doc != nil {
+                                       // prioritize documentation
+                                       i := -1
+                                       switch file.Name.Name {
+                                       case name:
+                                               i = 0 // normal case: directory name matches package name
+                                       case fakePkgName:
+                                               i = 1 // synopses for commands
+                                       case "main":
+                                               i = 2 // directory contains a main package
+                                       default:
+                                               i = 3 // none of the above
+                                       }
+                                       if 0 <= i && i < len(synopses) && synopses[i] == "" {
+                                               synopses[i] = firstSentence(doc.CommentText(file.Doc))
+                                       }
+                               }
+                       }
+               }
+       }
+
+       // create subdirectory tree
+       var dirs []*Directory
+       if ndirs > 0 {
+               dirs = make([]*Directory, ndirs)
+               i := 0
+               for _, d := range list {
+                       if isPkgDir(d) {
+                               dd := newDirTree(pathutil.Join(path, d.Name), d.Name, depth+1, maxDepth)
+                               if dd != nil {
+                                       dirs[i] = dd
+                                       i++
+                               }
+                       }
+               }
+               dirs = dirs[0:i]
+       }
+
+       // if there are no package files and no subdirectories
+       // (with package files), ignore the directory
+       if nfiles == 0 && len(dirs) == 0 {
+               return nil
+       }
+
+       // select the highest-priority synopsis for the directory entry, if any
+       synopsis := ""
+       for _, synopsis = range synopses {
+               if synopsis != "" {
+                       break
+               }
+       }
+
+       return &Directory{depth, path, name, synopsis, dirs}
+}
+
+
+// newDirectory creates a new package directory tree with at most maxDepth
+// levels, anchored at root. The result tree is pruned such that it only
+// contains directories that contain package files or that contain
+// subdirectories containing package files (transitively). If maxDepth is
+// too shallow, the leaf nodes are assumed to contain package files even if
+// their contents are not known (i.e., in this case the tree may contain
+// directories w/o any package files).
+//
+func newDirectory(root string, maxDepth int) *Directory {
+       d, err := os.Lstat(root)
+       if err != nil || !isPkgDir(d) {
+               return nil
+       }
+       return newDirTree(root, d.Name, 0, maxDepth)
+}
+
+
+func (dir *Directory) walk(c chan<- *Directory, skipRoot bool) {
+       if dir != nil {
+               if !skipRoot {
+                       c <- dir
+               }
+               for _, d := range dir.Dirs {
+                       d.walk(c, false)
+               }
+       }
+}
+
+
+func (dir *Directory) iter(skipRoot bool) <-chan *Directory {
+       c := make(chan *Directory)
+       go func() {
+               dir.walk(c, skipRoot)
+               close(c)
+       }()
+       return c
+}
+
+
+func (dir *Directory) lookupLocal(name string) *Directory {
+       for _, d := range dir.Dirs {
+               if d.Name == name {
+                       return d
+               }
+       }
+       return nil
+}
+
+
+// lookup looks for the *Directory for a given path, relative to dir.
+func (dir *Directory) lookup(path string) *Directory {
+       d := strings.Split(dir.Path, "/", -1)
+       p := strings.Split(path, "/", -1)
+       i := 0
+       for i < len(d) {
+               if i >= len(p) || d[i] != p[i] {
+                       return nil
+               }
+               i++
+       }
+       for dir != nil && i < len(p) {
+               dir = dir.lookupLocal(p[i])
+               i++
+       }
+       return dir
+}
+
+
+// DirEntry describes a directory entry. The Depth and Height values
+// are useful for presenting an entry in an indented fashion.
+//
+type DirEntry struct {
+       Depth    int    // >= 0
+       Height   int    // = DirList.MaxHeight - Depth, > 0
+       Path     string // includes Name, relative to DirList root
+       Name     string
+       Synopsis string
+}
+
+
+type DirList struct {
+       MaxHeight int // directory tree height, > 0
+       List      []DirEntry
+}
+
+
+// listing creates a (linear) directory listing from a directory tree.
+// If skipRoot is set, the root directory itself is excluded from the list.
+//
+func (root *Directory) listing(skipRoot bool) *DirList {
+       if root == nil {
+               return nil
+       }
+
+       // determine number of entries n and maximum height
+       n := 0
+       minDepth := 1 << 30 // infinity
+       maxDepth := 0
+       for d := range root.iter(skipRoot) {
+               n++
+               if minDepth > d.Depth {
+                       minDepth = d.Depth
+               }
+               if maxDepth < d.Depth {
+                       maxDepth = d.Depth
+               }
+       }
+       maxHeight := maxDepth - minDepth + 1
+
+       if n == 0 {
+               return nil
+       }
+
+       // create list
+       list := make([]DirEntry, n)
+       i := 0
+       for d := range root.iter(skipRoot) {
+               p := &list[i]
+               p.Depth = d.Depth - minDepth
+               p.Height = maxHeight - p.Depth
+               // the path is relative to root.Path - remove the root.Path
+               // prefix (the prefix should always be present but avoid
+               // crashes and check)
+               path := d.Path
+               if strings.HasPrefix(d.Path, root.Path) {
+                       path = d.Path[len(root.Path):]
+               }
+               // remove trailing '/' if any - path must be relative
+               if len(path) > 0 && path[0] == '/' {
+                       path = path[1:]
+               }
+               p.Path = path
+               p.Name = d.Name
+               p.Synopsis = d.Text
+               i++
+       }
+
+       return &DirList{maxHeight, list}
+}
index a6b9acc707022beb9cf239ff9dc5645bf259d974..b1456bb8128e519a493df779c58de321022dce8d 100644 (file)
@@ -25,7 +25,6 @@ import (
        "sync"
        "template"
        "time"
-       "unicode"
        "utf8"
 )
 
@@ -115,70 +114,7 @@ func registerPublicHandlers(mux *http.ServeMux) {
 
 
 // ----------------------------------------------------------------------------
-// Predicates and small utility functions
-
-func isGoFile(f *os.FileInfo) bool {
-       return f.IsRegular() &&
-               !strings.HasPrefix(f.Name, ".") && // ignore .files
-               pathutil.Ext(f.Name) == ".go"
-}
-
-
-func isPkgFile(f *os.FileInfo) bool {
-       return isGoFile(f) &&
-               !strings.HasSuffix(f.Name, "_test.go") // ignore test files
-}
-
-
-func isPkgDir(f *os.FileInfo) bool {
-       return f.IsDirectory() && len(f.Name) > 0 && f.Name[0] != '_'
-}
-
-
-func pkgName(filename string) string {
-       file, err := parser.ParseFile(filename, nil, parser.PackageClauseOnly)
-       if err != nil || file == nil {
-               return ""
-       }
-       return file.Name.Name
-}
-
-
-func firstSentence(s string) string {
-       i := -1 // index+1 of first terminator (punctuation ending a sentence)
-       j := -1 // index+1 of first terminator followed by white space
-       prev := 'A'
-       for k, ch := range s {
-               k1 := k + 1
-               if ch == '.' || ch == '!' || ch == '?' {
-                       if i < 0 {
-                               i = k1 // first terminator
-                       }
-                       if k1 < len(s) && s[k1] <= ' ' {
-                               if j < 0 {
-                                       j = k1 // first terminator followed by white space
-                               }
-                               if !unicode.IsUpper(prev) {
-                                       j = k1
-                                       break
-                               }
-                       }
-               }
-               prev = ch
-       }
-
-       if j < 0 {
-               // use the next best terminator
-               j = i
-               if j < 0 {
-                       // no terminator at all, use the entire string
-                       j = len(s)
-               }
-       }
-
-       return s[0:j]
-}
-
+// Path mapping
 
 func absolutePath(path, defaultRoot string) string {
        abspath := fsMap.ToAbsolute(path)
@@ -205,239 +141,6 @@ func relativePath(path string) string {
 }
 
 
-// ----------------------------------------------------------------------------
-// Package directories
-
-type Directory struct {
-       Depth int
-       Path  string // includes Name
-       Name  string
-       Text  string       // package documentation, if any
-       Dirs  []*Directory // subdirectories
-}
-
-
-func newDirTree(path, name string, depth, maxDepth int) *Directory {
-       if depth >= maxDepth {
-               // return a dummy directory so that the parent directory
-               // doesn't get discarded just because we reached the max
-               // directory depth
-               return &Directory{depth, path, name, "", nil}
-       }
-
-       list, _ := ioutil.ReadDir(path) // ignore errors
-
-       // determine number of subdirectories and package files
-       ndirs := 0
-       nfiles := 0
-       var synopses [4]string // prioritized package documentation (0 == highest priority)
-       for _, d := range list {
-               switch {
-               case isPkgDir(d):
-                       ndirs++
-               case isPkgFile(d):
-                       nfiles++
-                       if synopses[0] == "" {
-                               // no "optimal" package synopsis yet; continue to collect synopses
-                               file, err := parser.ParseFile(pathutil.Join(path, d.Name), nil,
-                                       parser.ParseComments|parser.PackageClauseOnly)
-                               if err == nil && file.Doc != nil {
-                                       // prioritize documentation
-                                       i := -1
-                                       switch file.Name.Name {
-                                       case name:
-                                               i = 0 // normal case: directory name matches package name
-                                       case fakePkgName:
-                                               i = 1 // synopses for commands
-                                       case "main":
-                                               i = 2 // directory contains a main package
-                                       default:
-                                               i = 3 // none of the above
-                                       }
-                                       if 0 <= i && i < len(synopses) && synopses[i] == "" {
-                                               synopses[i] = firstSentence(doc.CommentText(file.Doc))
-                                       }
-                               }
-                       }
-               }
-       }
-
-       // create subdirectory tree
-       var dirs []*Directory
-       if ndirs > 0 {
-               dirs = make([]*Directory, ndirs)
-               i := 0
-               for _, d := range list {
-                       if isPkgDir(d) {
-                               dd := newDirTree(pathutil.Join(path, d.Name), d.Name, depth+1, maxDepth)
-                               if dd != nil {
-                                       dirs[i] = dd
-                                       i++
-                               }
-                       }
-               }
-               dirs = dirs[0:i]
-       }
-
-       // if there are no package files and no subdirectories
-       // (with package files), ignore the directory
-       if nfiles == 0 && len(dirs) == 0 {
-               return nil
-       }
-
-       // select the highest-priority synopsis for the directory entry, if any
-       synopsis := ""
-       for _, synopsis = range synopses {
-               if synopsis != "" {
-                       break
-               }
-       }
-
-       return &Directory{depth, path, name, synopsis, dirs}
-}
-
-
-// newDirectory creates a new package directory tree with at most maxDepth
-// levels, anchored at root. The result tree is pruned such that it only
-// contains directories that contain package files or that contain
-// subdirectories containing package files (transitively). If maxDepth is
-// too shallow, the leaf nodes are assumed to contain package files even if
-// their contents are not known (i.e., in this case the tree may contain
-// directories w/o any package files).
-//
-func newDirectory(root string, maxDepth int) *Directory {
-       d, err := os.Lstat(root)
-       if err != nil || !isPkgDir(d) {
-               return nil
-       }
-       return newDirTree(root, d.Name, 0, maxDepth)
-}
-
-
-func (dir *Directory) walk(c chan<- *Directory, skipRoot bool) {
-       if dir != nil {
-               if !skipRoot {
-                       c <- dir
-               }
-               for _, d := range dir.Dirs {
-                       d.walk(c, false)
-               }
-       }
-}
-
-
-func (dir *Directory) iter(skipRoot bool) <-chan *Directory {
-       c := make(chan *Directory)
-       go func() {
-               dir.walk(c, skipRoot)
-               close(c)
-       }()
-       return c
-}
-
-
-func (dir *Directory) lookupLocal(name string) *Directory {
-       for _, d := range dir.Dirs {
-               if d.Name == name {
-                       return d
-               }
-       }
-       return nil
-}
-
-
-// lookup looks for the *Directory for a given path, relative to dir.
-func (dir *Directory) lookup(path string) *Directory {
-       d := strings.Split(dir.Path, "/", -1)
-       p := strings.Split(path, "/", -1)
-       i := 0
-       for i < len(d) {
-               if i >= len(p) || d[i] != p[i] {
-                       return nil
-               }
-               i++
-       }
-       for dir != nil && i < len(p) {
-               dir = dir.lookupLocal(p[i])
-               i++
-       }
-       return dir
-}
-
-
-// DirEntry describes a directory entry. The Depth and Height values
-// are useful for presenting an entry in an indented fashion.
-//
-type DirEntry struct {
-       Depth    int    // >= 0
-       Height   int    // = DirList.MaxHeight - Depth, > 0
-       Path     string // includes Name, relative to DirList root
-       Name     string
-       Synopsis string
-}
-
-
-type DirList struct {
-       MaxHeight int // directory tree height, > 0
-       List      []DirEntry
-}
-
-
-// listing creates a (linear) directory listing from a directory tree.
-// If skipRoot is set, the root directory itself is excluded from the list.
-//
-func (root *Directory) listing(skipRoot bool) *DirList {
-       if root == nil {
-               return nil
-       }
-
-       // determine number of entries n and maximum height
-       n := 0
-       minDepth := 1 << 30 // infinity
-       maxDepth := 0
-       for d := range root.iter(skipRoot) {
-               n++
-               if minDepth > d.Depth {
-                       minDepth = d.Depth
-               }
-               if maxDepth < d.Depth {
-                       maxDepth = d.Depth
-               }
-       }
-       maxHeight := maxDepth - minDepth + 1
-
-       if n == 0 {
-               return nil
-       }
-
-       // create list
-       list := make([]DirEntry, n)
-       i := 0
-       for d := range root.iter(skipRoot) {
-               p := &list[i]
-               p.Depth = d.Depth - minDepth
-               p.Height = maxHeight - p.Depth
-               // the path is relative to root.Path - remove the root.Path
-               // prefix (the prefix should always be present but avoid
-               // crashes and check)
-               path := d.Path
-               if strings.HasPrefix(d.Path, root.Path) {
-                       path = d.Path[len(root.Path):]
-               }
-               // remove trailing '/' if any - path must be relative
-               if len(path) > 0 && path[0] == '/' {
-                       path = path[1:]
-               }
-               p.Path = path
-               p.Name = d.Name
-               p.Synopsis = d.Text
-               i++
-       }
-
-       return &DirList{maxHeight, list}
-}
-
-
 // ----------------------------------------------------------------------------
 // HTML formatting support
 
index d5d8e3e36029e25f1bc6eced62778599ae274974..c21c8bda01059a312188582ed21facb315de251b 100644 (file)
@@ -583,6 +583,15 @@ func (x *Indexer) VisitDir(path string, f *os.FileInfo) bool {
 }
 
 
+func pkgName(filename string) string {
+       file, err := parser.ParseFile(filename, nil, parser.PackageClauseOnly)
+       if err != nil || file == nil {
+               return ""
+       }
+       return file.Name.Name
+}
+
+
 func (x *Indexer) VisitFile(path string, f *os.FileInfo) {
        if !isGoFile(f) {
                return