mirror of
https://github.com/golang/go
synced 2024-11-18 10:54:40 -07:00
godoc: move bulk of the code to the package
R=golang-dev, adg CC=golang-dev https://golang.org/cl/11424043
This commit is contained in:
parent
2392be72c2
commit
e6ff53bcc8
@ -26,6 +26,9 @@ import (
|
||||
"strings"
|
||||
"text/template"
|
||||
"unicode/utf8"
|
||||
|
||||
"code.google.com/p/go.tools/godoc"
|
||||
"code.google.com/p/go.tools/godoc/vfs"
|
||||
)
|
||||
|
||||
// Handler for /doc/codewalk/ and below.
|
||||
@ -40,7 +43,7 @@ func codewalk(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
// If directory exists, serve list of code walks.
|
||||
dir, err := fs.Lstat(abspath)
|
||||
dir, err := godoc.FS.Lstat(abspath)
|
||||
if err == nil && dir.IsDir() {
|
||||
codewalkDir(w, r, relpath, abspath)
|
||||
return
|
||||
@ -59,7 +62,7 @@ func codewalk(w http.ResponseWriter, r *http.Request) {
|
||||
cw, err := loadCodewalk(abspath + ".xml")
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
serveError(w, r, relpath, err)
|
||||
godoc.ServeError(w, r, relpath, err)
|
||||
return
|
||||
}
|
||||
|
||||
@ -68,7 +71,7 @@ func codewalk(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
servePage(w, Page{
|
||||
godoc.ServePage(w, godoc.Page{
|
||||
Title: "Codewalk: " + cw.Title,
|
||||
Tabtitle: cw.Title,
|
||||
Body: applyTemplate(codewalkHTML, "codewalk", cw),
|
||||
@ -114,7 +117,7 @@ func (st *Codestep) String() string {
|
||||
|
||||
// loadCodewalk reads a codewalk from the named XML file.
|
||||
func loadCodewalk(filename string) (*Codewalk, error) {
|
||||
f, err := fs.Open(filename)
|
||||
f, err := godoc.FS.Open(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -135,7 +138,7 @@ func loadCodewalk(filename string) (*Codewalk, error) {
|
||||
i = len(st.Src)
|
||||
}
|
||||
filename := st.Src[0:i]
|
||||
data, err := ReadFile(fs, filename)
|
||||
data, err := vfs.ReadFile(godoc.FS, filename)
|
||||
if err != nil {
|
||||
st.Err = err
|
||||
continue
|
||||
@ -182,10 +185,10 @@ func codewalkDir(w http.ResponseWriter, r *http.Request, relpath, abspath string
|
||||
Title string
|
||||
}
|
||||
|
||||
dir, err := fs.ReadDir(abspath)
|
||||
dir, err := godoc.FS.ReadDir(abspath)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
serveError(w, r, relpath, err)
|
||||
godoc.ServeError(w, r, relpath, err)
|
||||
return
|
||||
}
|
||||
var v []interface{}
|
||||
@ -202,7 +205,7 @@ func codewalkDir(w http.ResponseWriter, r *http.Request, relpath, abspath string
|
||||
}
|
||||
}
|
||||
|
||||
servePage(w, Page{
|
||||
godoc.ServePage(w, godoc.Page{
|
||||
Title: "Codewalks",
|
||||
Body: applyTemplate(codewalkdirHTML, "codewalkdir", v),
|
||||
})
|
||||
@ -216,10 +219,10 @@ func codewalkDir(w http.ResponseWriter, r *http.Request, relpath, abspath string
|
||||
// the usual godoc HTML wrapper.
|
||||
func codewalkFileprint(w http.ResponseWriter, r *http.Request, f string) {
|
||||
abspath := f
|
||||
data, err := ReadFile(fs, abspath)
|
||||
data, err := vfs.ReadFile(godoc.FS, abspath)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
serveError(w, r, f, err)
|
||||
godoc.ServeError(w, r, f, err)
|
||||
return
|
||||
}
|
||||
lo, _ := strconv.Atoi(r.FormValue("lo"))
|
||||
|
@ -1,48 +0,0 @@
|
||||
// Copyright 2011 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 defines types for abstract file system access and
|
||||
// provides an implementation accessing the file system of the
|
||||
// underlying OS.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
|
||||
"code.google.com/p/go.tools/godoc/vfs"
|
||||
)
|
||||
|
||||
// fs is the file system that godoc reads from and serves.
|
||||
// It is a virtual file system that operates on slash-separated paths,
|
||||
// and its root corresponds to the Go distribution root: /src/pkg
|
||||
// holds the source tree, and so on. This means that the URLs served by
|
||||
// the godoc server are the same as the paths in the virtual file
|
||||
// system, which helps keep things simple.
|
||||
//
|
||||
// New file trees - implementations of FileSystem - can be added to
|
||||
// the virtual file system using nameSpace's Bind method.
|
||||
// The usual setup is to bind OS(runtime.GOROOT) to the root
|
||||
// of the name space and then bind any GOPATH/src directories
|
||||
// on top of /src/pkg, so that all sources are in /src/pkg.
|
||||
//
|
||||
// For more about name spaces, see the NameSpace type's
|
||||
// documentation in code.google.com/p/go.tools/godoc/vfs.
|
||||
//
|
||||
// The use of this virtual file system means that most code processing
|
||||
// paths can assume they are slash-separated and should be using
|
||||
// package path (often imported as pathpkg) to manipulate them,
|
||||
// even on Windows.
|
||||
//
|
||||
var fs = vfs.NameSpace{} // the underlying file system for godoc
|
||||
|
||||
// ReadFile reads the file named by path from fs and returns the contents.
|
||||
func ReadFile(fs vfs.FileSystem, path string) ([]byte, error) {
|
||||
rc, err := fs.Open(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rc.Close()
|
||||
return ioutil.ReadAll(rc)
|
||||
}
|
1355
cmd/godoc/godoc.go
1355
cmd/godoc/godoc.go
File diff suppressed because it is too large
Load Diff
@ -49,6 +49,7 @@ import (
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"code.google.com/p/go.tools/godoc"
|
||||
"code.google.com/p/go.tools/godoc/vfs"
|
||||
"code.google.com/p/go.tools/godoc/vfs/zipfs"
|
||||
)
|
||||
@ -76,15 +77,6 @@ var (
|
||||
query = flag.Bool("q", false, "arguments are considered search queries")
|
||||
)
|
||||
|
||||
func serveError(w http.ResponseWriter, r *http.Request, relpath string, err error) {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
servePage(w, Page{
|
||||
Title: "File " + relpath,
|
||||
Subtitle: relpath,
|
||||
Body: applyTemplate(errorHTML, "errorHTML", err), // err may contain an absolute path!
|
||||
})
|
||||
}
|
||||
|
||||
func usage() {
|
||||
fmt.Fprintf(os.Stderr,
|
||||
"usage: godoc package [name ...]\n"+
|
||||
@ -165,8 +157,8 @@ func main() {
|
||||
usage()
|
||||
}
|
||||
|
||||
if *tabwidth < 0 {
|
||||
log.Fatalf("negative tabwidth %d", *tabwidth)
|
||||
if godoc.TabWidth < 0 {
|
||||
log.Fatalf("negative tabwidth %d", godoc.TabWidth)
|
||||
}
|
||||
|
||||
// Determine file system to use.
|
||||
@ -175,9 +167,9 @@ func main() {
|
||||
// same is true for the http handlers in initHandlers.
|
||||
if *zipfile == "" {
|
||||
// use file system of underlying OS
|
||||
fs.Bind("/", vfs.OS(*goroot), "/", vfs.BindReplace)
|
||||
godoc.FS.Bind("/", vfs.OS(*goroot), "/", vfs.BindReplace)
|
||||
if *templateDir != "" {
|
||||
fs.Bind("/lib/godoc", vfs.OS(*templateDir), "/", vfs.BindBefore)
|
||||
godoc.FS.Bind("/lib/godoc", vfs.OS(*templateDir), "/", vfs.BindBefore)
|
||||
}
|
||||
} else {
|
||||
// use file system specified via .zip file (path separator must be '/')
|
||||
@ -186,20 +178,20 @@ func main() {
|
||||
log.Fatalf("%s: %s\n", *zipfile, err)
|
||||
}
|
||||
defer rc.Close() // be nice (e.g., -writeIndex mode)
|
||||
fs.Bind("/", zipvfs.New(rc, *zipfile), *goroot, vfs.BindReplace)
|
||||
godoc.FS.Bind("/", zipvfs.New(rc, *zipfile), *goroot, vfs.BindReplace)
|
||||
}
|
||||
|
||||
// Bind $GOPATH trees into Go root.
|
||||
for _, p := range filepath.SplitList(build.Default.GOPATH) {
|
||||
fs.Bind("/src/pkg", vfs.OS(p), "/src", vfs.BindAfter)
|
||||
godoc.FS.Bind("/src/pkg", vfs.OS(p), "/src", vfs.BindAfter)
|
||||
}
|
||||
|
||||
readTemplates()
|
||||
initHandlers()
|
||||
godoc.InitHandlers(godoc.FS)
|
||||
|
||||
if *writeIndex {
|
||||
// Write search index and exit.
|
||||
if *indexFiles == "" {
|
||||
if godoc.IndexFiles == "" {
|
||||
log.Fatal("no index file specified")
|
||||
}
|
||||
|
||||
@ -207,16 +199,16 @@ func main() {
|
||||
*verbose = true // want to see what happens
|
||||
initFSTree()
|
||||
|
||||
*indexThrottle = 1
|
||||
updateIndex()
|
||||
godoc.IndexThrottle = 1.0
|
||||
godoc.UpdateIndex()
|
||||
|
||||
log.Println("writing index file", *indexFiles)
|
||||
f, err := os.Create(*indexFiles)
|
||||
log.Println("writing index file", godoc.IndexFiles)
|
||||
f, err := os.Create(godoc.IndexFiles)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
index, _ := searchIndex.Get()
|
||||
err = index.(*Index).Write(f)
|
||||
index, _ := godoc.SearchIndex.Get()
|
||||
err = index.(*godoc.Index).Write(f)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
@ -229,7 +221,7 @@ func main() {
|
||||
if *urlFlag != "" {
|
||||
registerPublicHandlers(http.DefaultServeMux)
|
||||
initFSTree()
|
||||
updateMetadata()
|
||||
godoc.UpdateMetadata()
|
||||
// Try up to 10 fetches, following redirects.
|
||||
urlstr := *urlFlag
|
||||
for i := 0; i < 10; i++ {
|
||||
@ -273,16 +265,16 @@ func main() {
|
||||
log.Printf("version = %s", runtime.Version())
|
||||
log.Printf("address = %s", *httpAddr)
|
||||
log.Printf("goroot = %s", *goroot)
|
||||
log.Printf("tabwidth = %d", *tabwidth)
|
||||
log.Printf("tabwidth = %d", godoc.TabWidth)
|
||||
switch {
|
||||
case !*indexEnabled:
|
||||
case !godoc.IndexEnabled:
|
||||
log.Print("search index disabled")
|
||||
case *maxResults > 0:
|
||||
log.Printf("full text index enabled (maxresults = %d)", *maxResults)
|
||||
case godoc.MaxResults > 0:
|
||||
log.Printf("full text index enabled (maxresults = %d)", godoc.MaxResults)
|
||||
default:
|
||||
log.Print("identifier search index enabled")
|
||||
}
|
||||
fs.Fprint(os.Stderr)
|
||||
godoc.FS.Fprint(os.Stderr)
|
||||
handler = loggingHandler(handler)
|
||||
}
|
||||
|
||||
@ -293,13 +285,13 @@ func main() {
|
||||
go initFSTree()
|
||||
|
||||
// Immediately update metadata.
|
||||
updateMetadata()
|
||||
godoc.UpdateMetadata()
|
||||
// Periodically refresh metadata.
|
||||
go refreshMetadataLoop()
|
||||
go godoc.RefreshMetadataLoop()
|
||||
|
||||
// Initialize search index.
|
||||
if *indexEnabled {
|
||||
go indexer()
|
||||
if godoc.IndexEnabled {
|
||||
go godoc.RunIndexer()
|
||||
}
|
||||
|
||||
// Start http server.
|
||||
@ -310,10 +302,11 @@ func main() {
|
||||
return
|
||||
}
|
||||
|
||||
packageText := godoc.PackageText
|
||||
|
||||
// Command line mode.
|
||||
if *html {
|
||||
packageText = packageHTML
|
||||
searchText = packageHTML
|
||||
packageText = godoc.PackageHTML
|
||||
}
|
||||
|
||||
if *query {
|
||||
@ -341,52 +334,52 @@ func main() {
|
||||
var forceCmd bool
|
||||
var abspath, relpath string
|
||||
if filepath.IsAbs(path) {
|
||||
fs.Bind(target, vfs.OS(path), "/", vfs.BindReplace)
|
||||
godoc.FS.Bind(target, vfs.OS(path), "/", vfs.BindReplace)
|
||||
abspath = target
|
||||
} else if build.IsLocalImport(path) {
|
||||
cwd, _ := os.Getwd() // ignore errors
|
||||
path = filepath.Join(cwd, path)
|
||||
fs.Bind(target, vfs.OS(path), "/", vfs.BindReplace)
|
||||
godoc.FS.Bind(target, vfs.OS(path), "/", vfs.BindReplace)
|
||||
abspath = target
|
||||
} else if strings.HasPrefix(path, cmdPrefix) {
|
||||
path = strings.TrimPrefix(path, cmdPrefix)
|
||||
forceCmd = true
|
||||
} else if bp, _ := build.Import(path, "", build.FindOnly); bp.Dir != "" && bp.ImportPath != "" {
|
||||
fs.Bind(target, vfs.OS(bp.Dir), "/", vfs.BindReplace)
|
||||
godoc.FS.Bind(target, vfs.OS(bp.Dir), "/", vfs.BindReplace)
|
||||
abspath = target
|
||||
relpath = bp.ImportPath
|
||||
} else {
|
||||
abspath = pathpkg.Join(pkgHandler.fsRoot, path)
|
||||
abspath = pathpkg.Join(godoc.PkgHandler.FSRoot(), path)
|
||||
}
|
||||
if relpath == "" {
|
||||
relpath = abspath
|
||||
}
|
||||
|
||||
var mode PageInfoMode
|
||||
if relpath == builtinPkgPath {
|
||||
var mode godoc.PageInfoMode
|
||||
if relpath == godoc.BuiltinPkgPath {
|
||||
// the fake built-in package contains unexported identifiers
|
||||
mode = noFiltering
|
||||
mode = godoc.NoFiltering
|
||||
}
|
||||
if *srcMode {
|
||||
// only filter exports if we don't have explicit command-line filter arguments
|
||||
if flag.NArg() > 1 {
|
||||
mode |= noFiltering
|
||||
mode |= godoc.NoFiltering
|
||||
}
|
||||
mode |= showSource
|
||||
mode |= godoc.ShowSource
|
||||
}
|
||||
|
||||
// first, try as package unless forced as command
|
||||
var info *PageInfo
|
||||
var info *godoc.PageInfo
|
||||
if !forceCmd {
|
||||
info = pkgHandler.getPageInfo(abspath, relpath, mode)
|
||||
info = godoc.PkgHandler.GetPageInfo(abspath, relpath, mode)
|
||||
}
|
||||
|
||||
// second, try as command unless the path is absolute
|
||||
// (the go command invokes godoc w/ absolute paths; don't override)
|
||||
var cinfo *PageInfo
|
||||
var cinfo *godoc.PageInfo
|
||||
if !filepath.IsAbs(path) {
|
||||
abspath = pathpkg.Join(cmdHandler.fsRoot, path)
|
||||
cinfo = cmdHandler.getPageInfo(abspath, relpath, mode)
|
||||
abspath = pathpkg.Join(godoc.CmdHandler.FSRoot(), path)
|
||||
cinfo = godoc.CmdHandler.GetPageInfo(abspath, relpath, mode)
|
||||
}
|
||||
|
||||
// determine what to use
|
||||
@ -442,10 +435,10 @@ func main() {
|
||||
}
|
||||
if *html {
|
||||
var buf bytes.Buffer
|
||||
writeNode(&buf, info.FSet, cn)
|
||||
FormatText(os.Stdout, buf.Bytes(), -1, true, "", nil)
|
||||
godoc.WriteNode(&buf, info.FSet, cn)
|
||||
godoc.FormatText(os.Stdout, buf.Bytes(), -1, true, "", nil)
|
||||
} else {
|
||||
writeNode(os.Stdout, info.FSet, cn)
|
||||
godoc.WriteNode(os.Stdout, info.FSet, cn)
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
|
@ -2,6 +2,12 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build playground
|
||||
|
||||
// TODO(bradfitz,adg): move the
|
||||
// code.google.com/p/go.talks/pkg/playground package elsewhere, so
|
||||
// go.tools doesn't depend on go.talks.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
// This file contains the code dealing with package directory trees.
|
||||
|
||||
package main
|
||||
package godoc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@ -69,7 +69,7 @@ func (b *treeBuilder) newDirTree(fset *token.FileSet, path, name string, depth i
|
||||
}
|
||||
}
|
||||
|
||||
list, _ := fs.ReadDir(path)
|
||||
list, _ := FS.ReadDir(path)
|
||||
|
||||
// determine number of subdirectories and if there are package files
|
||||
ndirs := 0
|
||||
@ -161,9 +161,9 @@ func (b *treeBuilder) newDirTree(fset *token.FileSet, path, name string, depth i
|
||||
// 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 {
|
||||
func NewDirectory(root string, maxDepth int) *Directory {
|
||||
// The root could be a symbolic link so use Stat not Lstat.
|
||||
d, err := fs.Stat(root)
|
||||
d, err := FS.Stat(root)
|
||||
// If we fail here, report detailed error messages; otherwise
|
||||
// is is hard to see why a directory tree was not built.
|
||||
switch {
|
@ -8,7 +8,7 @@
|
||||
// built on top of FormatSelections, a generic formatter
|
||||
// for "selected" text.
|
||||
|
||||
package main
|
||||
package godoc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@ -284,11 +284,10 @@ func regexpSelection(text []byte, expr string) Selection {
|
||||
|
||||
var selRx = regexp.MustCompile(`^([0-9]+):([0-9]+)`)
|
||||
|
||||
// rangeSelection computes the Selection for a text range described
|
||||
// RangeSelection computes the Selection for a text range described
|
||||
// by the argument str; the range description must match the selRx
|
||||
// regular expression.
|
||||
//
|
||||
func rangeSelection(str string) Selection {
|
||||
func RangeSelection(str string) Selection {
|
||||
m := selRx.FindStringSubmatch(str)
|
||||
if len(m) >= 2 {
|
||||
from, _ := strconv.Atoi(m[1])
|
@ -35,21 +35,25 @@
|
||||
// - translate the Pos values back into file and line information and
|
||||
// sort the result
|
||||
|
||||
package main
|
||||
package godoc
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/gob"
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"index/suffixarray"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
pathpkg "path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
@ -58,6 +62,19 @@ import (
|
||||
"code.google.com/p/go.tools/godoc/util"
|
||||
)
|
||||
|
||||
// TODO(bradfitz,adg): legacy flag vars. clean up.
|
||||
var (
|
||||
MaxResults = 1000
|
||||
|
||||
// index throttle value; 0.0 = no time allocated, 1.0 = full throttle
|
||||
IndexThrottle float64 = 0.75
|
||||
|
||||
// IndexFiles is a glob pattern specifying index files; if
|
||||
// not empty, the index is read from these files in sorted
|
||||
// order")
|
||||
IndexFiles string
|
||||
)
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// InterfaceSlice is a helper type for sorting interface
|
||||
// slices according to some slice-specific sort criteria.
|
||||
@ -116,67 +133,6 @@ func (h RunList) reduce(less Comparer, newRun func(h RunList) interface{}) RunLi
|
||||
return hh
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// SpotInfo
|
||||
|
||||
// A SpotInfo value describes a particular identifier spot in a given file;
|
||||
// It encodes three values: the SpotKind (declaration or use), a line or
|
||||
// snippet index "lori", and whether it's a line or index.
|
||||
//
|
||||
// The following encoding is used:
|
||||
//
|
||||
// bits 32 4 1 0
|
||||
// value [lori|kind|isIndex]
|
||||
//
|
||||
type SpotInfo uint32
|
||||
|
||||
// SpotKind describes whether an identifier is declared (and what kind of
|
||||
// declaration) or used.
|
||||
type SpotKind uint32
|
||||
|
||||
const (
|
||||
PackageClause SpotKind = iota
|
||||
ImportDecl
|
||||
ConstDecl
|
||||
TypeDecl
|
||||
VarDecl
|
||||
FuncDecl
|
||||
MethodDecl
|
||||
Use
|
||||
nKinds
|
||||
)
|
||||
|
||||
func init() {
|
||||
// sanity check: if nKinds is too large, the SpotInfo
|
||||
// accessor functions may need to be updated
|
||||
if nKinds > 8 {
|
||||
panic("internal error: nKinds > 8")
|
||||
}
|
||||
}
|
||||
|
||||
// makeSpotInfo makes a SpotInfo.
|
||||
func makeSpotInfo(kind SpotKind, lori int, isIndex bool) SpotInfo {
|
||||
// encode lori: bits [4..32)
|
||||
x := SpotInfo(lori) << 4
|
||||
if int(x>>4) != lori {
|
||||
// lori value doesn't fit - since snippet indices are
|
||||
// most certainly always smaller then 1<<28, this can
|
||||
// only happen for line numbers; give it no line number (= 0)
|
||||
x = 0
|
||||
}
|
||||
// encode kind: bits [1..4)
|
||||
x |= SpotInfo(kind) << 1
|
||||
// encode isIndex: bit 0
|
||||
if isIndex {
|
||||
x |= 1
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
func (x SpotInfo) Kind() SpotKind { return SpotKind(x >> 1 & 7) }
|
||||
func (x SpotInfo) Lori() int { return int(x >> 4) }
|
||||
func (x SpotInfo) IsIndex() bool { return x&1 != 0 }
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// KindRun
|
||||
|
||||
@ -482,8 +438,8 @@ func (x *Indexer) visitIdent(kind SpotKind, id *ast.Ident) {
|
||||
}
|
||||
}
|
||||
|
||||
func (x *Indexer) visitFieldList(kind SpotKind, list *ast.FieldList) {
|
||||
for _, f := range list.List {
|
||||
func (x *Indexer) visitFieldList(kind SpotKind, flist *ast.FieldList) {
|
||||
for _, f := range flist.List {
|
||||
x.decl = nil // no snippets for fields
|
||||
for _, name := range f.Names {
|
||||
x.visitIdent(kind, name)
|
||||
@ -593,7 +549,7 @@ func pkgName(filename string) string {
|
||||
// failed (that is, if the file was not added), it returns file == nil.
|
||||
func (x *Indexer) addFile(filename string, goFile bool) (file *token.File, ast *ast.File) {
|
||||
// open file
|
||||
f, err := fs.Open(filename)
|
||||
f, err := FS.Open(filename)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@ -772,7 +728,7 @@ func NewIndex(dirnames <-chan string, fulltextIndex bool, throttle float64) *Ind
|
||||
|
||||
// index all files in the directories given by dirnames
|
||||
for dirname := range dirnames {
|
||||
list, err := fs.ReadDir(dirname)
|
||||
list, err := FS.ReadDir(dirname)
|
||||
if err != nil {
|
||||
continue // ignore this directory
|
||||
}
|
||||
@ -1079,3 +1035,113 @@ func (x *Index) LookupRegexp(r *regexp.Regexp, n int) (found int, result []FileL
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// InvalidateIndex should be called whenever any of the file systems
|
||||
// under godoc's observation change so that the indexer is kicked on.
|
||||
func InvalidateIndex() {
|
||||
FSModified.Set(nil)
|
||||
refreshMetadata()
|
||||
}
|
||||
|
||||
// indexUpToDate() returns true if the search index is not older
|
||||
// than any of the file systems under godoc's observation.
|
||||
//
|
||||
func indexUpToDate() bool {
|
||||
_, fsTime := FSModified.Get()
|
||||
_, siTime := SearchIndex.Get()
|
||||
return !fsTime.After(siTime)
|
||||
}
|
||||
|
||||
// feedDirnames feeds the directory names of all directories
|
||||
// under the file system given by root to channel c.
|
||||
//
|
||||
func feedDirnames(root *util.RWValue, c chan<- string) {
|
||||
if dir, _ := root.Get(); dir != nil {
|
||||
for d := range dir.(*Directory).iter(false) {
|
||||
c <- d.Path
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fsDirnames() returns a channel sending all directory names
|
||||
// of all the file systems under godoc's observation.
|
||||
//
|
||||
func fsDirnames() <-chan string {
|
||||
c := make(chan string, 256) // buffered for fewer context switches
|
||||
go func() {
|
||||
feedDirnames(&FSTree, c)
|
||||
close(c)
|
||||
}()
|
||||
return c
|
||||
}
|
||||
|
||||
func readIndex(filenames string) error {
|
||||
matches, err := filepath.Glob(filenames)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if matches == nil {
|
||||
return fmt.Errorf("no index files match %q", filenames)
|
||||
}
|
||||
sort.Strings(matches) // make sure files are in the right order
|
||||
files := make([]io.Reader, 0, len(matches))
|
||||
for _, filename := range matches {
|
||||
f, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
files = append(files, f)
|
||||
}
|
||||
x := new(Index)
|
||||
if err := x.Read(io.MultiReader(files...)); err != nil {
|
||||
return err
|
||||
}
|
||||
SearchIndex.Set(x)
|
||||
return nil
|
||||
}
|
||||
|
||||
func UpdateIndex() {
|
||||
if Verbose {
|
||||
log.Printf("updating index...")
|
||||
}
|
||||
start := time.Now()
|
||||
index := NewIndex(fsDirnames(), MaxResults > 0, IndexThrottle)
|
||||
stop := time.Now()
|
||||
SearchIndex.Set(index)
|
||||
if Verbose {
|
||||
secs := stop.Sub(start).Seconds()
|
||||
stats := index.Stats()
|
||||
log.Printf("index updated (%gs, %d bytes of source, %d files, %d lines, %d unique words, %d spots)",
|
||||
secs, stats.Bytes, stats.Files, stats.Lines, stats.Words, stats.Spots)
|
||||
}
|
||||
memstats := new(runtime.MemStats)
|
||||
runtime.ReadMemStats(memstats)
|
||||
log.Printf("before GC: bytes = %d footprint = %d", memstats.HeapAlloc, memstats.Sys)
|
||||
runtime.GC()
|
||||
runtime.ReadMemStats(memstats)
|
||||
log.Printf("after GC: bytes = %d footprint = %d", memstats.HeapAlloc, memstats.Sys)
|
||||
}
|
||||
|
||||
// RunIndexer runs forever, indexing.
|
||||
func RunIndexer() {
|
||||
// initialize the index from disk if possible
|
||||
if IndexFiles != "" {
|
||||
if err := readIndex(IndexFiles); err != nil {
|
||||
log.Printf("error reading index: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
// repeatedly update the index when it goes out of date
|
||||
for {
|
||||
if !indexUpToDate() {
|
||||
// index possibly out of date - make a new one
|
||||
UpdateIndex()
|
||||
}
|
||||
delay := 60 * time.Second // by default, try every 60s
|
||||
if false { // TODO(bradfitz): was: *testDir != "" {
|
||||
// in test mode, try once a second for fast startup
|
||||
delay = 1 * time.Second
|
||||
}
|
||||
time.Sleep(delay)
|
||||
}
|
||||
}
|
@ -8,7 +8,7 @@
|
||||
// doesn't have complete type information, but it's
|
||||
// reasonably good for browsing.
|
||||
|
||||
package main
|
||||
package godoc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@ -94,7 +94,7 @@ func linksFor(node ast.Node) (list []link) {
|
||||
switch m {
|
||||
case identUse:
|
||||
if n.Obj == nil && predeclared[n.Name] {
|
||||
info.path = builtinPkgPath
|
||||
info.path = BuiltinPkgPath
|
||||
}
|
||||
info.name = n.Name
|
||||
case identDef:
|
@ -5,17 +5,19 @@
|
||||
// This file contains support functions for parsing .go files
|
||||
// accessed via godoc's file system fs.
|
||||
|
||||
package main
|
||||
package godoc
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
pathpkg "path"
|
||||
|
||||
"code.google.com/p/go.tools/godoc/vfs"
|
||||
)
|
||||
|
||||
func parseFile(fset *token.FileSet, filename string, mode parser.Mode) (*ast.File, error) {
|
||||
src, err := ReadFile(fs, filename)
|
||||
src, err := vfs.ReadFile(FS, filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
@ -7,7 +7,7 @@
|
||||
//
|
||||
// Note: At the moment, this only creates HTML snippets.
|
||||
|
||||
package main
|
||||
package godoc
|
||||
|
||||
import (
|
||||
"bytes"
|
@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
package godoc
|
||||
|
||||
// This file contains the mechanism to "linkify" html source
|
||||
// text containing EBNF sections (as found in go_spec.html).
|
@ -29,7 +29,7 @@
|
||||
// lines in the input that will not appear in the output but are easy
|
||||
// to identify by pattern.
|
||||
|
||||
package main
|
||||
package godoc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@ -38,19 +38,21 @@ import (
|
||||
"regexp"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"code.google.com/p/go.tools/godoc/vfs"
|
||||
)
|
||||
|
||||
// Functions in this file panic on error, but the panic is recovered
|
||||
// to an error by 'code'.
|
||||
|
||||
var templateFuncs = template.FuncMap{
|
||||
var TemplateFuncs = template.FuncMap{
|
||||
"code": code,
|
||||
}
|
||||
|
||||
// contents reads and returns the content of the named file
|
||||
// (from the virtual file system, so for example /doc refers to $GOROOT/doc).
|
||||
func contents(name string) string {
|
||||
file, err := ReadFile(fs, name)
|
||||
file, err := vfs.ReadFile(FS, name)
|
||||
if err != nil {
|
||||
log.Panic(err)
|
||||
}
|
@ -8,6 +8,7 @@ package vfs
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
)
|
||||
|
||||
@ -32,3 +33,13 @@ type ReadSeekCloser interface {
|
||||
io.Seeker
|
||||
io.Closer
|
||||
}
|
||||
|
||||
// ReadFile reads the file named by path from fs and returns the contents.
|
||||
func ReadFile(fs Opener, path string) ([]byte, error) {
|
||||
rc, err := fs.Open(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rc.Close()
|
||||
return ioutil.ReadAll(rc)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user