diff --git a/cmd/godoc/appinit.go b/cmd/godoc/appinit.go index cb747b30ef..6318bb75fb 100644 --- a/cmd/godoc/appinit.go +++ b/cmd/godoc/appinit.go @@ -89,12 +89,11 @@ func main() { pres = godoc.NewPresentation(corpus) pres.TabWidth = 8 pres.ShowPlayground = true - pres.ShowExamples = true pres.DeclLinks = true pres.NotesRx = regexp.MustCompile("BUG") pres.GoogleAnalytics = os.Getenv("GODOC_ANALYTICS") - readTemplates(pres, true) + readTemplates(pres) datastoreClient, memcacheClient := getClients() diff --git a/cmd/godoc/godoc_test.go b/cmd/godoc/godoc_test.go index 7200c917b0..54fe540ddf 100644 --- a/cmd/godoc/godoc_test.go +++ b/cmd/godoc/godoc_test.go @@ -54,75 +54,6 @@ func buildGodoc(t *testing.T) (bin string, cleanup func()) { return bin, func() { os.RemoveAll(tmp) } } -// Basic regression test for godoc command-line tool. -func TestCLI(t *testing.T) { - bin, cleanup := buildGodoc(t) - defer cleanup() - - tests := []struct { - args []string - matches []string // regular expressions - dontmatch []string // regular expressions - }{ - { - args: []string{"fmt"}, - matches: []string{ - `import "fmt"`, - `Package fmt implements formatted I/O`, - }, - }, - { - args: []string{"io", "WriteString"}, - matches: []string{ - `func WriteString\(`, - `WriteString writes the contents of the string s to w`, - }, - }, - { - args: []string{"nonexistingpkg"}, - matches: []string{ - `cannot find package`, - }, - }, - { - args: []string{"fmt", "NonexistentSymbol"}, - matches: []string{ - `No match found\.`, - }, - }, - { - args: []string{"-src", "syscall", "Open"}, - matches: []string{ - `func Open\(`, - }, - dontmatch: []string{ - `No match found\.`, - }, - }, - } - for _, test := range tests { - cmd := exec.Command(bin, test.args...) - cmd.Args[0] = "godoc" - out, err := cmd.CombinedOutput() - if err != nil { - t.Errorf("Running with args %#v: %v", test.args, err) - continue - } - for _, pat := range test.matches { - re := regexp.MustCompile(pat) - if !re.Match(out) { - t.Errorf("godoc %v =\n%s\nwanted /%v/", strings.Join(test.args, " "), out, pat) - } - } - for _, pat := range test.dontmatch { - re := regexp.MustCompile(pat) - if re.Match(out) { - t.Errorf("godoc %v =\n%s\ndid not want /%v/", strings.Join(test.args, " "), out, pat) - } - } - } -} - func serverAddress(t *testing.T) string { ln, err := net.Listen("tcp", "127.0.0.1:0") if err != nil { diff --git a/cmd/godoc/handlers.go b/cmd/godoc/handlers.go index fabb679779..d393992eb9 100644 --- a/cmd/godoc/handlers.go +++ b/cmd/godoc/handlers.go @@ -112,28 +112,23 @@ func readTemplate(name string) *template.Template { return t } -func readTemplates(p *godoc.Presentation, html bool) { - p.PackageText = readTemplate("package.txt") - p.SearchText = readTemplate("search.txt") - - if html || p.HTMLMode { - codewalkHTML = readTemplate("codewalk.html") - codewalkdirHTML = readTemplate("codewalkdir.html") - p.CallGraphHTML = readTemplate("callgraph.html") - p.DirlistHTML = readTemplate("dirlist.html") - p.ErrorHTML = readTemplate("error.html") - p.ExampleHTML = readTemplate("example.html") - p.GodocHTML = readTemplate("godoc.html") - p.ImplementsHTML = readTemplate("implements.html") - p.MethodSetHTML = readTemplate("methodset.html") - p.PackageHTML = readTemplate("package.html") - p.PackageRootHTML = readTemplate("packageroot.html") - p.SearchHTML = readTemplate("search.html") - p.SearchDocHTML = readTemplate("searchdoc.html") - p.SearchCodeHTML = readTemplate("searchcode.html") - p.SearchTxtHTML = readTemplate("searchtxt.html") - p.SearchDescXML = readTemplate("opensearch.xml") - } +func readTemplates(p *godoc.Presentation) { + codewalkHTML = readTemplate("codewalk.html") + codewalkdirHTML = readTemplate("codewalkdir.html") + p.CallGraphHTML = readTemplate("callgraph.html") + p.DirlistHTML = readTemplate("dirlist.html") + p.ErrorHTML = readTemplate("error.html") + p.ExampleHTML = readTemplate("example.html") + p.GodocHTML = readTemplate("godoc.html") + p.ImplementsHTML = readTemplate("implements.html") + p.MethodSetHTML = readTemplate("methodset.html") + p.PackageHTML = readTemplate("package.html") + p.PackageRootHTML = readTemplate("packageroot.html") + p.SearchHTML = readTemplate("search.html") + p.SearchDocHTML = readTemplate("searchdoc.html") + p.SearchCodeHTML = readTemplate("searchcode.html") + p.SearchTxtHTML = readTemplate("searchtxt.html") + p.SearchDescXML = readTemplate("opensearch.xml") } type fmtResponse struct { diff --git a/cmd/godoc/main.go b/cmd/godoc/main.go index 7f0ac0c985..19b5a453c4 100644 --- a/cmd/godoc/main.go +++ b/cmd/godoc/main.go @@ -53,7 +53,7 @@ import ( "golang.org/x/tools/godoc/vfs/zipfs" ) -const defaultAddr = ":6060" // default webserver address +const defaultAddr = "localhost:6060" // default webserver address var ( // file system to serve @@ -66,18 +66,11 @@ var ( analysisFlag = flag.String("analysis", "", `comma-separated list of analyses to perform (supported: type, pointer). See http://golang.org/lib/godoc/analysis/help.html`) // network - httpAddr = flag.String("http", "", "HTTP service address (e.g., '"+defaultAddr+"')") - serverAddr = flag.String("server", "", "webserver address for command line searches") + httpAddr = flag.String("http", defaultAddr, "HTTP service address") // layout control - html = flag.Bool("html", false, "print HTML in command-line mode") - srcMode = flag.Bool("src", false, "print (exported) source in command-line mode") - allMode = flag.Bool("all", false, "include unexported identifiers in command-line mode") urlFlag = flag.String("url", "", "print HTML for named URL") - // command-line searches - query = flag.Bool("q", false, "arguments are considered search queries") - verbose = flag.Bool("v", false, "verbose mode") // file system roots @@ -85,11 +78,9 @@ var ( goroot = flag.String("goroot", findGOROOT(), "Go root directory") // layout control - tabWidth = flag.Int("tabwidth", 4, "tab width") showTimestamps = flag.Bool("timestamps", false, "show timestamps with directory listings") templateDir = flag.String("templates", "", "load templates/JS/CSS from disk in this directory") showPlayground = flag.Bool("play", false, "enable playground in web interface") - showExamples = flag.Bool("ex", false, "show examples in command line mode") declLinks = flag.Bool("links", true, "link identifiers to their declarations") // search index @@ -104,9 +95,7 @@ var ( ) func usage() { - fmt.Fprintf(os.Stderr, - "usage: godoc package [name ...]\n"+ - " godoc -http="+defaultAddr+"\n") + fmt.Fprintf(os.Stderr, "usage: godoc -http="+defaultAddr+"\n") flag.PrintDefaults() os.Exit(2) } @@ -173,7 +162,7 @@ func main() { // Check usage: server and no args. if (*httpAddr != "" || *urlFlag != "") && (flag.NArg() > 0) { - fmt.Fprintln(os.Stderr, "can't use -http with args.") + fmt.Fprintln(os.Stderr, "Unexpected arguments.") usage() } @@ -183,11 +172,10 @@ func main() { usage() } - // Setting the resolved goroot. + // Set the resolved goroot. vfs.GOROOT = *goroot - var fsGate chan bool - fsGate = make(chan bool, 20) + fsGate := make(chan bool, 20) // Determine file system to use. if *zipfile == "" { @@ -214,8 +202,6 @@ func main() { fs.Bind("/src", gatefs.New(vfs.OS(p), fsGate), "/src", vfs.BindAfter) } - httpMode := *httpAddr != "" - var typeAnalysis, pointerAnalysis bool if *analysisFlag != "" { for _, a := range strings.Split(*analysisFlag, ",") { @@ -233,7 +219,7 @@ func main() { corpus := godoc.NewCorpus(fs) corpus.Verbose = *verbose corpus.MaxResults = *maxResults - corpus.IndexEnabled = *indexEnabled && httpMode + corpus.IndexEnabled = *indexEnabled if *maxResults == 0 { corpus.IndexFullText = false } @@ -245,32 +231,21 @@ func main() { corpus.IndexThrottle = 1.0 corpus.IndexEnabled = true } - if *writeIndex || httpMode || *urlFlag != "" { - if httpMode { - go initCorpus(corpus) - } else { - initCorpus(corpus) - } - } + go initCorpus(corpus) // Initialize the version info before readTemplates, which saves // the map value in a method value. corpus.InitVersionInfo() pres = godoc.NewPresentation(corpus) - pres.TabWidth = *tabWidth pres.ShowTimestamps = *showTimestamps pres.ShowPlayground = *showPlayground - pres.ShowExamples = *showExamples pres.DeclLinks = *declLinks - pres.SrcMode = *srcMode - pres.HTMLMode = *html - pres.AllMode = *allMode if *notesRx != "" { pres.NotesRx = regexp.MustCompile(*notesRx) } - readTemplates(pres, httpMode || *urlFlag != "") + readTemplates(pres) registerHandlers(pres) if *writeIndex { @@ -305,67 +280,51 @@ func main() { return } - if httpMode { - // HTTP server mode. - var handler http.Handler = http.DefaultServeMux - if *verbose { - log.Printf("Go Documentation Server") - log.Printf("version = %s", runtime.Version()) - log.Printf("address = %s", *httpAddr) - log.Printf("goroot = %s", *goroot) - log.Printf("tabwidth = %d", *tabWidth) - switch { - case !*indexEnabled: - log.Print("search index disabled") - case *maxResults > 0: - log.Printf("full text index enabled (maxresults = %d)", *maxResults) - default: - log.Print("identifier search index enabled") + var handler http.Handler = http.DefaultServeMux + if *verbose { + log.Printf("Go Documentation Server") + log.Printf("version = %s", runtime.Version()) + log.Printf("address = %s", *httpAddr) + log.Printf("goroot = %s", *goroot) + switch { + case !*indexEnabled: + log.Print("search index disabled") + case *maxResults > 0: + log.Printf("full text index enabled (maxresults = %d)", *maxResults) + default: + log.Print("identifier search index enabled") + } + fs.Fprint(os.Stderr) + handler = loggingHandler(handler) + } + + // Initialize search index. + if *indexEnabled { + go corpus.RunIndexer() + } + + // Start type/pointer analysis. + if typeAnalysis || pointerAnalysis { + go analysis.Run(pointerAnalysis, &corpus.Analysis) + } + + if runHTTPS != nil { + go func() { + if err := runHTTPS(handler); err != nil { + log.Fatalf("ListenAndServe TLS: %v", err) } - fs.Fprint(os.Stderr) - handler = loggingHandler(handler) - } - - // Initialize search index. - if *indexEnabled { - go corpus.RunIndexer() - } - - // Start type/pointer analysis. - if typeAnalysis || pointerAnalysis { - go analysis.Run(pointerAnalysis, &corpus.Analysis) - } - - if runHTTPS != nil { - go func() { - if err := runHTTPS(handler); err != nil { - log.Fatalf("ListenAndServe TLS: %v", err) - } - }() - } - - // Start http server. - if *verbose { - log.Println("starting HTTP server") - } - if wrapHTTPMux != nil { - handler = wrapHTTPMux(handler) - } - if err := http.ListenAndServe(*httpAddr, handler); err != nil { - log.Fatalf("ListenAndServe %s: %v", *httpAddr, err) - } - - return + }() } - if *query { - handleRemoteSearch() - return + // Start http server. + if *verbose { + log.Println("starting HTTP server") } - - build.Default.GOROOT = *goroot - if err := godoc.CommandLine(os.Stdout, fs, pres, flag.Args()); err != nil { - log.Print(err) + if wrapHTTPMux != nil { + handler = wrapHTTPMux(handler) + } + if err := http.ListenAndServe(*httpAddr, handler); err != nil { + log.Fatalf("ListenAndServe %s: %v", *httpAddr, err) } } diff --git a/cmd/godoc/remotesearch.go b/cmd/godoc/remotesearch.go deleted file mode 100644 index 6f27d0b33a..0000000000 --- a/cmd/godoc/remotesearch.go +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2009 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. - -// +build !golangorg - -package main - -import ( - "errors" - "flag" - "io" - "log" - "net/http" - "net/url" - "os" -) - -func handleRemoteSearch() { - // Command-line queries. - for i := 0; i < flag.NArg(); i++ { - res, err := remoteSearch(flag.Arg(i)) - if err != nil { - log.Fatalf("remoteSearch: %s", err) - } - io.Copy(os.Stdout, res.Body) - } - return -} - -// remoteSearchURL returns the search URL for a given query as needed by -// remoteSearch. If html is set, an html result is requested; otherwise -// the result is in textual form. -// Adjust this function as necessary if modeNames or FormValue parameters -// change. -func remoteSearchURL(query string, html bool) string { - s := "/search?m=text&q=" - if html { - s = "/search?q=" - } - return s + url.QueryEscape(query) -} - -func remoteSearch(query string) (res *http.Response, err error) { - // list of addresses to try - var addrs []string - if *serverAddr != "" { - // explicit server address - only try this one - addrs = []string{*serverAddr} - } else { - addrs = []string{ - defaultAddr, - "golang.org", - } - } - - // remote search - search := remoteSearchURL(query, *html) - for _, addr := range addrs { - url := "http://" + addr + search - res, err = http.Get(url) - if err == nil && res.StatusCode == http.StatusOK { - break - } - } - - if err == nil && res.StatusCode != http.StatusOK { - err = errors.New(res.Status) - } - - return -} diff --git a/godoc/cmdline.go b/godoc/cmdline.go deleted file mode 100644 index 54f5f7ee7e..0000000000 --- a/godoc/cmdline.go +++ /dev/null @@ -1,217 +0,0 @@ -// Copyright 2013 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. - -package godoc - -import ( - "fmt" - "go/ast" - "go/build" - "io" - "log" - "os" - pathpkg "path" - "path/filepath" - "regexp" - "strings" - - "golang.org/x/tools/godoc/vfs" -) - -const ( - target = "/target" - cmdPrefix = "cmd/" - srcPrefix = "src/" - toolsPath = "golang.org/x/tools/cmd/" -) - -// CommandLine returns godoc results to w. -// Note that it may add a /target path to fs. -func CommandLine(w io.Writer, fs vfs.NameSpace, pres *Presentation, args []string) error { - path := args[0] - srcMode := pres.SrcMode - cmdMode := strings.HasPrefix(path, cmdPrefix) - if strings.HasPrefix(path, srcPrefix) { - path = strings.TrimPrefix(path, srcPrefix) - srcMode = true - } - var abspath, relpath string - if cmdMode { - path = strings.TrimPrefix(path, cmdPrefix) - } else { - abspath, relpath = paths(fs, pres, path) - } - - var mode PageInfoMode - if relpath == builtinPkgPath { - // the fake built-in package contains unexported identifiers - mode = NoFiltering | NoTypeAssoc - } - if pres.AllMode { - mode |= NoFiltering - } - if srcMode { - // only filter exports if we don't have explicit command-line filter arguments - if len(args) > 1 { - mode |= NoFiltering - } - mode |= ShowSource - } - - // First, try as package unless forced as command. - var info *PageInfo - if !cmdMode { - info = pres.GetPkgPageInfo(abspath, relpath, mode) - } - - // Second, try as command (if the path is not absolute). - var cinfo *PageInfo - if !filepath.IsAbs(path) { - // First try go.tools/cmd. - abspath = pathpkg.Join(pres.PkgFSRoot(), toolsPath+path) - cinfo = pres.GetCmdPageInfo(abspath, relpath, mode) - if cinfo.IsEmpty() { - // Then try $GOROOT/src/cmd. - abspath = pathpkg.Join(pres.CmdFSRoot(), cmdPrefix, path) - cinfo = pres.GetCmdPageInfo(abspath, relpath, mode) - } - } - - // determine what to use - if info == nil || info.IsEmpty() { - if cinfo != nil && !cinfo.IsEmpty() { - // only cinfo exists - switch to cinfo - info = cinfo - } - } else if cinfo != nil && !cinfo.IsEmpty() { - // both info and cinfo exist - use cinfo if info - // contains only subdirectory information - if info.PAst == nil && info.PDoc == nil { - info = cinfo - } else if relpath != target { - // The above check handles the case where an operating system path - // is provided (see documentation for paths below). In that case, - // relpath is set to "/target" (in anticipation of accessing packages there), - // and is therefore not expected to match a command. - fmt.Fprintf(w, "use 'godoc %s%s' for documentation on the %s command \n\n", cmdPrefix, relpath, relpath) - } - } - - if info == nil { - return fmt.Errorf("%s: no such directory or package", args[0]) - } - if info.Err != nil { - return info.Err - } - - if info.PDoc != nil && info.PDoc.ImportPath == target { - // Replace virtual /target with actual argument from command line. - info.PDoc.ImportPath = args[0] - } - - // If we have more than one argument, use the remaining arguments for filtering. - if len(args) > 1 { - info.IsFiltered = true - filterInfo(args[1:], info) - } - - packageText := pres.PackageText - if pres.HTMLMode { - packageText = pres.PackageHTML - } - if err := packageText.Execute(w, info); err != nil { - return err - } - return nil -} - -// paths determines the paths to use. -// -// If we are passed an operating system path like . or ./foo or /foo/bar or c:\mysrc, -// we need to map that path somewhere in the fs name space so that routines -// like getPageInfo will see it. We use the arbitrarily-chosen virtual path "/target" -// for this. That is, if we get passed a directory like the above, we map that -// directory so that getPageInfo sees it as /target. -// Returns the absolute and relative paths. -func paths(fs vfs.NameSpace, pres *Presentation, path string) (abspath, relpath string) { - if filepath.IsAbs(path) { - fs.Bind(target, vfs.OS(path), "/", vfs.BindReplace) - return target, target - } - if build.IsLocalImport(path) { - cwd, err := os.Getwd() - if err != nil { - log.Printf("error while getting working directory: %v", err) - } - path = filepath.Join(cwd, path) - fs.Bind(target, vfs.OS(path), "/", vfs.BindReplace) - return target, target - } - bp, err := build.Import(path, "", build.FindOnly) - if err != nil { - log.Printf("error while importing build package: %v", err) - } - if bp.Dir != "" && bp.ImportPath != "" { - fs.Bind(target, vfs.OS(bp.Dir), "/", vfs.BindReplace) - return target, bp.ImportPath - } - return pathpkg.Join(pres.PkgFSRoot(), path), path -} - -// filterInfo updates info to include only the nodes that match the given -// filter args. -func filterInfo(args []string, info *PageInfo) { - rx, err := makeRx(args) - if err != nil { - log.Fatalf("illegal regular expression from %v: %v", args, err) - } - - filter := func(s string) bool { return rx.MatchString(s) } - switch { - case info.PAst != nil: - newPAst := map[string]*ast.File{} - for name, a := range info.PAst { - cmap := ast.NewCommentMap(info.FSet, a, a.Comments) - a.Comments = []*ast.CommentGroup{} // remove all comments. - ast.FilterFile(a, filter) - if len(a.Decls) > 0 { - newPAst[name] = a - } - for _, d := range a.Decls { - // add back the comments associated with d only - comments := cmap.Filter(d).Comments() - a.Comments = append(a.Comments, comments...) - } - } - info.PAst = newPAst // add only matching files. - case info.PDoc != nil: - info.PDoc.Filter(filter) - } -} - -// Does s look like a regular expression? -func isRegexp(s string) bool { - return strings.ContainsAny(s, ".(|)*+?^$[]") -} - -// Make a regular expression of the form -// names[0]|names[1]|...names[len(names)-1]. -// Returns an error if the regular expression is illegal. -func makeRx(names []string) (*regexp.Regexp, error) { - if len(names) == 0 { - return nil, fmt.Errorf("no expression provided") - } - s := "" - for i, name := range names { - if i > 0 { - s += "|" - } - if isRegexp(name) { - s += name - } else { - s += "^" + name + "$" // must match exactly - } - } - return regexp.Compile(s) -} diff --git a/godoc/cmdline_test.go b/godoc/cmdline_test.go deleted file mode 100644 index cebbf70ecf..0000000000 --- a/godoc/cmdline_test.go +++ /dev/null @@ -1,312 +0,0 @@ -// Copyright 2013 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. - -package godoc - -import ( - "bytes" - "go/build" - "io/ioutil" - "os" - "path/filepath" - "reflect" - "regexp" - "runtime" - "testing" - "text/template" - - "golang.org/x/tools/godoc/vfs" - "golang.org/x/tools/godoc/vfs/mapfs" -) - -// setupGoroot creates temporary directory to act as GOROOT when running tests -// that depend upon the build package. It updates build.Default to point to the -// new GOROOT. -// It returns a function that can be called to reset build.Default and remove -// the temporary directory. -func setupGoroot(t *testing.T) (cleanup func()) { - var stdLib = map[string]string{ - "src/fmt/fmt.go": `// Package fmt implements formatted I/O. -package fmt - -type Stringer interface { - String() string -} -`, - } - goroot, err := ioutil.TempDir("", "cmdline_test") - if err != nil { - t.Fatal(err) - } - origContext := build.Default - build.Default = build.Context{ - GOROOT: goroot, - Compiler: "gc", - } - for relname, contents := range stdLib { - name := filepath.Join(goroot, relname) - if err := os.MkdirAll(filepath.Dir(name), 0770); err != nil { - t.Fatal(err) - } - if err := ioutil.WriteFile(name, []byte(contents), 0770); err != nil { - t.Fatal(err) - } - } - - return func() { - if err := os.RemoveAll(goroot); err != nil { - t.Log(err) - } - build.Default = origContext - } -} - -func TestPaths(t *testing.T) { - cleanup := setupGoroot(t) - defer cleanup() - - pres := &Presentation{ - pkgHandler: handlerServer{ - fsRoot: "/fsroot", - }, - } - fs := make(vfs.NameSpace) - - absPath := "/foo/fmt" - if runtime.GOOS == "windows" { - absPath = `c:\foo\fmt` - } - - for _, tc := range []struct { - desc string - path string - expAbs string - expRel string - }{ - { - "Absolute path", - absPath, - "/target", - "/target", - }, - { - "Local import", - "../foo/fmt", - "/target", - "/target", - }, - { - "Import", - "fmt", - "/target", - "fmt", - }, - { - "Default", - "unknownpkg", - "/fsroot/unknownpkg", - "unknownpkg", - }, - } { - abs, rel := paths(fs, pres, tc.path) - if abs != tc.expAbs || rel != tc.expRel { - t.Errorf("%s: paths(%q) = %s,%s; want %s,%s", tc.desc, tc.path, abs, rel, tc.expAbs, tc.expRel) - } - } -} - -func TestMakeRx(t *testing.T) { - for _, tc := range []struct { - desc string - names []string - exp string - }{ - { - desc: "empty string", - names: []string{""}, - exp: `^$`, - }, - { - desc: "simple text", - names: []string{"a"}, - exp: `^a$`, - }, - { - desc: "two words", - names: []string{"foo", "bar"}, - exp: `^foo$|^bar$`, - }, - { - desc: "word & non-trivial", - names: []string{"foo", `ab?c`}, - exp: `^foo$|ab?c`, - }, - { - desc: "bad regexp", - names: []string{`(."`}, - exp: `(."`, - }, - } { - expRE, expErr := regexp.Compile(tc.exp) - if re, err := makeRx(tc.names); !reflect.DeepEqual(err, expErr) && !reflect.DeepEqual(re, expRE) { - t.Errorf("%s: makeRx(%v) = %q,%q; want %q,%q", tc.desc, tc.names, re, err, expRE, expErr) - } - } -} - -func TestCommandLine(t *testing.T) { - cleanup := setupGoroot(t) - defer cleanup() - mfs := mapfs.New(map[string]string{ - "src/bar/bar.go": `// Package bar is an example. -package bar -`, - "src/foo/foo.go": `// Package foo. -package foo - -// First function is first. -func First() { -} - -// Second function is second. -func Second() { -} - -// unexported function is third. -func unexported() { -} -`, - "src/gen/gen.go": `// Package gen -package gen - -//line notgen.go:3 -// F doc //line 1 should appear -// line 2 should appear -func F() -//line foo.go:100`, // no newline on end to check corner cases! - "src/vet/vet.go": `// Package vet -package vet -`, - "src/cmd/go/doc.go": `// The go command -package main -`, - "src/cmd/gofmt/doc.go": `// The gofmt command -package main -`, - "src/cmd/vet/vet.go": `// The vet command -package main -`, - }) - fs := make(vfs.NameSpace) - fs.Bind("/", mfs, "/", vfs.BindReplace) - c := NewCorpus(fs) - p := &Presentation{Corpus: c} - p.cmdHandler = handlerServer{ - p: p, - c: c, - pattern: "/cmd/", - fsRoot: "/src", - } - p.pkgHandler = handlerServer{ - p: p, - c: c, - pattern: "/pkg/", - fsRoot: "/src", - exclude: []string{"/src/cmd"}, - } - p.initFuncMap() - p.PackageText = template.Must(template.New("PackageText").Funcs(p.FuncMap()).Parse(`{{$info := .}}{{$filtered := .IsFiltered}}{{if $filtered}}{{range .PAst}}{{range .Decls}}{{node $info .}}{{end}}{{end}}{{else}}{{with .PAst}}{{range $filename, $ast := .}}{{$filename}}: -{{node $ $ast}}{{end}}{{end}}{{end}}{{with .PDoc}}{{if $.IsMain}}COMMAND {{.Doc}}{{else}}PACKAGE {{.Doc}}{{end}}{{with .Funcs}} -{{range .}}{{node $ .Decl}} -{{comment_text .Doc " " "\t"}}{{end}}{{end}}{{end}}`)) - - for _, tc := range []struct { - desc string - args []string - all bool - exp string - err bool - }{ - { - desc: "standard package", - args: []string{"fmt"}, - exp: "PACKAGE Package fmt implements formatted I/O.\n", - }, - { - desc: "package", - args: []string{"bar"}, - exp: "PACKAGE Package bar is an example.\n", - }, - { - desc: "package w. filter", - args: []string{"foo", "First"}, - exp: "PACKAGE \nfunc First()\n First function is first.\n", - }, - { - desc: "package w. bad filter", - args: []string{"foo", "DNE"}, - exp: "PACKAGE ", - }, - { - desc: "source mode", - args: []string{"src/bar"}, - exp: "bar/bar.go:\n// Package bar is an example.\npackage bar\n", - }, - { - desc: "source mode w. filter", - args: []string{"src/foo", "Second"}, - exp: "// Second function is second.\nfunc Second() {\n}", - }, - { - desc: "package w. unexported filter", - args: []string{"foo", "unexported"}, - all: true, - exp: "PACKAGE \nfunc unexported()\n unexported function is third.\n", - }, - { - desc: "package w. unexported filter", - args: []string{"foo", "unexported"}, - all: false, - exp: "PACKAGE ", - }, - { - desc: "package w. //line comments", - args: []string{"gen", "F"}, - exp: "PACKAGE \nfunc F()\n F doc //line 1 should appear line 2 should appear\n", - }, - { - desc: "command", - args: []string{"go"}, - exp: "COMMAND The go command\n", - }, - { - desc: "forced command", - args: []string{"cmd/gofmt"}, - exp: "COMMAND The gofmt command\n", - }, - { - desc: "bad arg", - args: []string{"doesnotexist"}, - err: true, - }, - { - desc: "both command and package", - args: []string{"vet"}, - exp: "use 'godoc cmd/vet' for documentation on the vet command \n\nPACKAGE Package vet\n", - }, - { - desc: "root directory", - args: []string{"/"}, - exp: "", - }, - } { - p.AllMode = tc.all - w := new(bytes.Buffer) - err := CommandLine(w, fs, p, tc.args) - if got, want := w.String(), tc.exp; got != want || tc.err == (err == nil) { - t.Errorf("%s: CommandLine(%v), All(%v) = %q (%v); want %q (%v)", - tc.desc, tc.args, tc.all, got, err, want, tc.err) - } - } -} diff --git a/godoc/godoc.go b/godoc/godoc.go index 0acb49bf75..5add835fc3 100644 --- a/godoc/godoc.go +++ b/godoc/godoc.go @@ -77,7 +77,6 @@ func (p *Presentation) initFuncMap() { "node": p.nodeFunc, "node_html": p.node_htmlFunc, "comment_html": comment_htmlFunc, - "comment_text": comment_textFunc, "sanitize": sanitizeFunc, // support for URL attributes @@ -91,7 +90,6 @@ func (p *Presentation) initFuncMap() { // formatting of Examples "example_html": p.example_htmlFunc, - "example_text": p.example_textFunc, "example_name": p.example_nameFunc, "example_suffix": p.example_suffixFunc, @@ -372,15 +370,6 @@ func containsOnlySpace(buf []byte) bool { return bytes.IndexFunc(buf, isNotSpace) == -1 } -func comment_textFunc(comment, indent, preIndent string) string { - var buf bytes.Buffer - doc.ToText(&buf, comment, indent, preIndent, punchCardWidth-2*len(indent)) - if containsOnlySpace(buf.Bytes()) { - return "" - } - return buf.String() -} - // sanitizeFunc sanitizes the argument src by replacing newlines with // blanks, removing extra blanks, and by removing trailing whitespace // and commas before closing parentheses. @@ -589,50 +578,6 @@ func docLinkFunc(s string, ident string) string { return pathpkg.Clean("/pkg/"+s) + "/#" + ident } -func (p *Presentation) example_textFunc(info *PageInfo, funcName, indent string) string { - if !p.ShowExamples { - return "" - } - - var buf bytes.Buffer - first := true - for _, eg := range info.Examples { - name := stripExampleSuffix(eg.Name) - if name != funcName { - continue - } - - if !first { - buf.WriteString("\n") - } - first = false - - // print code - cnode := &printer.CommentedNode{Node: eg.Code, Comments: eg.Comments} - config := &printer.Config{Mode: printer.UseSpaces, Tabwidth: p.TabWidth} - var buf1 bytes.Buffer - config.Fprint(&buf1, info.FSet, cnode) - code := buf1.String() - - // Additional formatting if this is a function body. Unfortunately, we - // can't print statements individually because we would lose comments - // on later statements. - if n := len(code); n >= 2 && code[0] == '{' && code[n-1] == '}' { - // remove surrounding braces - code = code[1 : n-1] - // unindent - code = replaceLeadingIndentation(code, strings.Repeat(" ", p.TabWidth), indent) - } - code = strings.Trim(code, "\n") - - buf.WriteString(indent) - buf.WriteString("Example:\n") - buf.WriteString(code) - buf.WriteString("\n\n") - } - return buf.String() -} - func (p *Presentation) example_htmlFunc(info *PageInfo, funcName string) string { var buf bytes.Buffer for _, eg := range info.Examples { diff --git a/godoc/pres.go b/godoc/pres.go index b0077fd581..800937af48 100644 --- a/godoc/pres.go +++ b/godoc/pres.go @@ -34,12 +34,10 @@ type Presentation struct { MethodSetHTML, PackageHTML, PackageRootHTML, - PackageText, SearchHTML, SearchDocHTML, SearchCodeHTML, SearchTxtHTML, - SearchText, SearchDescXML *template.Template // TabWidth optionally specifies the tab width. @@ -47,7 +45,6 @@ type Presentation struct { ShowTimestamps bool ShowPlayground bool - ShowExamples bool DeclLinks bool // SrcMode outputs source code instead of documentation in command-line mode. @@ -113,9 +110,8 @@ func NewPresentation(c *Corpus) *Presentation { mux: http.NewServeMux(), fileServer: http.FileServer(httpfs.New(c.fs)), - TabWidth: 4, - ShowExamples: true, - DeclLinks: true, + TabWidth: 4, + DeclLinks: true, SearchResults: []SearchResultFunc{ (*Presentation).SearchResultDoc, (*Presentation).SearchResultCode, diff --git a/godoc/search.go b/godoc/search.go index d61193f218..870aefc018 100644 --- a/godoc/search.go +++ b/godoc/search.go @@ -99,11 +99,7 @@ func (p *Presentation) HandleSearch(w http.ResponseWriter, r *http.Request) { query := strings.TrimSpace(r.FormValue("q")) result := p.Corpus.Lookup(query) - if p.GetPageInfoMode(r)&NoHTML != 0 { - p.ServeText(w, applyTemplate(p.SearchText, "searchText", result)) - return - } - contents := bytes.Buffer{} + var contents bytes.Buffer for _, f := range p.SearchResults { contents.Write(f(p, result)) } diff --git a/godoc/server.go b/godoc/server.go index 2998967f4c..39f6922c89 100644 --- a/godoc/server.go +++ b/godoc/server.go @@ -276,11 +276,6 @@ func (h *handlerServer) ServeHTTP(w http.ResponseWriter, r *http.Request) { return } - if mode&NoHTML != 0 { - h.p.ServeText(w, applyTemplate(h.p.PackageText, "packageText", info)) - return - } - var tabtitle, title, subtitle string switch { case info.PAst != nil: diff --git a/godoc/static/gen.go b/godoc/static/gen.go index 399fb84e09..76f7d34b37 100644 --- a/godoc/static/gen.go +++ b/godoc/static/gen.go @@ -57,11 +57,9 @@ var files = []string{ "opensearch.xml", "package.html", "packageroot.html", - "package.txt", "play.js", "playground.js", "search.html", - "search.txt", "searchcode.html", "searchdoc.html", "searchtxt.html", diff --git a/godoc/static/package.txt b/godoc/static/package.txt deleted file mode 100644 index e53fa6ed38..0000000000 --- a/godoc/static/package.txt +++ /dev/null @@ -1,116 +0,0 @@ -{{$info := .}}{{$filtered := .IsFiltered}}{{/* - ---------------------------------------- - -*/}}{{if $filtered}}{{range .PAst}}{{range .Decls}}{{node $info .}} - -{{end}}{{end}}{{else}}{{with .PAst}}{{range $filename, $ast := .}}{{$filename}}: -{{node $ $ast}}{{end}}{{end}}{{end}}{{/* - ---------------------------------------- - -*/}}{{if and $filtered (not (or .PDoc .PAst))}}No match found. -{{end}}{{with .PDoc}}{{if $.IsMain}}COMMAND DOCUMENTATION - -{{comment_text .Doc " " "\t"}} -{{else}}{{if not $filtered}}PACKAGE DOCUMENTATION - -package {{.Name}} - import "{{.ImportPath}}" - -{{comment_text .Doc " " "\t"}} -{{example_text $ "" " "}}{{end}}{{/* - ---------------------------------------- - -*/}}{{with .Consts}}{{if not $filtered}}CONSTANTS - -{{end}}{{range .}}{{node $ .Decl}} -{{comment_text .Doc " " "\t"}} -{{end}}{{end}}{{/* - ---------------------------------------- - -*/}}{{with .Vars}}{{if not $filtered}}VARIABLES - -{{end}}{{range .}}{{node $ .Decl}} -{{comment_text .Doc " " "\t"}} -{{end}}{{end}}{{/* - ---------------------------------------- - -*/}}{{with .Funcs}}{{if not $filtered}}FUNCTIONS - -{{end}}{{range .}}{{node $ .Decl}} -{{comment_text .Doc " " "\t"}} -{{example_text $ .Name " "}}{{end}}{{end}}{{/* - ---------------------------------------- - -*/}}{{with .Types}}{{if not $filtered}}TYPES - -{{end}}{{range .}}{{$tname := .Name}}{{node $ .Decl}} -{{comment_text .Doc " " "\t"}} -{{/* - ---------------------------------------- - -*/}}{{if .Consts}}{{range .Consts}}{{node $ .Decl}} -{{comment_text .Doc " " "\t"}} -{{end}}{{end}}{{/* - ---------------------------------------- - -*/}}{{if .Vars}}{{range .Vars}}{{node $ .Decl}} -{{comment_text .Doc " " "\t"}} -{{range $name := .Names}}{{example_text $ $name " "}}{{end}}{{end}}{{end}}{{/* - ---------------------------------------- - -*/}}{{if .Funcs}}{{range .Funcs}}{{node $ .Decl}} -{{comment_text .Doc " " "\t"}} -{{example_text $ .Name " "}}{{end}}{{end}}{{/* - ---------------------------------------- - -*/}}{{if .Methods}}{{range .Methods}}{{node $ .Decl}} -{{comment_text .Doc " " "\t"}} -{{$name := printf "%s_%s" $tname .Name}}{{example_text $ $name " "}}{{end}}{{end}}{{/* - ---------------------------------------- - -*/}}{{end}}{{end}}{{/* - ---------------------------------------- - -*/}}{{if and $filtered (not (or .Consts (or .Vars (or .Funcs .Types))))}}No match found. -{{end}}{{/* - ---------------------------------------- - -*/}}{{end}}{{/* - ---------------------------------------- - -*/}}{{with $.Notes}} -{{range $marker, $content := .}} -{{$marker}}S - -{{range $content}}{{comment_text .Body " " "\t"}} -{{end}}{{end}}{{end}}{{end}}{{/* - ---------------------------------------- - -*/}}{{if not $filtered}}{{with .Dirs}}SUBDIRECTORIES -{{if $.DirFlat}}{{range .List}}{{if .HasPkg}} - {{.Path}}{{end}}{{end}} -{{else}}{{range .List}} - {{repeat `. ` .Depth}}{{.Name}}{{end}} -{{end}}{{end}}{{/* - ---------------------------------------- - -*/}}{{end}}{{/* -Make sure there is no newline at the end of this file. -perl -i -pe 'chomp if eof' package.txt -*/}} diff --git a/godoc/static/search.txt b/godoc/static/search.txt deleted file mode 100644 index 0ae0c080db..0000000000 --- a/godoc/static/search.txt +++ /dev/null @@ -1,54 +0,0 @@ -QUERY - {{.Query}} - -{{with .Alert}}{{.}} -{{end}}{{/* .Alert */}}{{/* - ---------------------------------------- - -*/}}{{with .Alt}}DID YOU MEAN - -{{range .Alts}} {{.}} -{{end}} -{{end}}{{/* .Alt */}}{{/* - ---------------------------------------- - -*/}}{{with .Pak}}PACKAGE {{$.Query}} - -{{range .}} {{pkgLink .Pak.Path}} -{{end}} -{{end}}{{/* .Pak */}}{{/* - ---------------------------------------- - -*/}}{{range $key, $val := .Idents}}{{if $val}}{{$key.Name}} -{{range $val}} {{.Path}}.{{.Name}} -{{end}} -{{end}}{{end}}{{/* .Idents */}}{{/* - ---------------------------------------- - -*/}}{{with .Hit}}{{with .Decls}}PACKAGE-LEVEL DECLARATIONS - -{{range .}}package {{.Pak.Name}} -{{range $file := .Files}}{{range .Groups}}{{range .}} {{srcLink $file.File.Path}}:{{infoLine .}}{{end}} -{{end}}{{end}}{{/* .Files */}} -{{end}}{{end}}{{/* .Decls */}}{{/* - ---------------------------------------- - -*/}}{{with .Others}}LOCAL DECLARATIONS AND USES - -{{range .}}package {{.Pak.Name}} -{{range $file := .Files}}{{range .Groups}}{{range .}} {{srcLink $file.File.Path}}:{{infoLine .}} -{{end}}{{end}}{{end}}{{/* .Files */}} -{{end}}{{end}}{{/* .Others */}}{{end}}{{/* .Hit */}}{{/* - ---------------------------------------- - -*/}}{{if .Textual}}{{if .Complete}}{{.Found}} TEXTUAL OCCURRENCES{{else}}MORE THAN {{.Found}} TEXTUAL OCCURRENCES{{end}} - -{{range .Textual}}{{len .Lines}} {{srcLink .Filename}} -{{end}}{{if not .Complete}}... ... -{{end}}{{end}} diff --git a/godoc/static/static.go b/godoc/static/static.go index 0fc0b40674..626b13465d 100644 --- a/godoc/static/static.go +++ b/godoc/static/static.go @@ -89,16 +89,12 @@ var Files = map[string]string{ "packageroot.html": "\x0a\x0a{{with\x20.PAst}}\x0a\x09{{range\x20$filename,\x20$ast\x20:=\x20.}}\x0a\x09\x09{{$filename|filename|html}}:
{{node_html\x20$\x20$ast\x20false}}\x0a\x09{{end}}\x0a{{end}}\x0a\x0a{{with\x20.Dirs}}\x0a\x09{{/*\x20DirList\x20entries\x20are\x20numbers\x20and\x20strings\x20-\x20no\x20need\x20for\x20FSet\x20*/}}\x0a\x09{{if\x20$.PDoc}}\x0a\x09\x09
Name | \x0a\x09\x09\x09\x09\x09\x09\x09Synopsis | \x0a\x09\x09\x09\x09\x09\x09|
---|---|---|
\x0a\x09\x09\x09\x09\x09\x09\x09\x09\x09\x09\x09{{html\x20.Path}}\x0a\x09\x09\x09\x09\x09\x09\x09\x09\x09\x09 | \x0a\x09\x09\x09\x09\x09\x09\x09\x09{{end}}\x0a\x09\x09\x09\x09\x09\x09\x09{{else}}\x0a\x09\x09\x09\x09\x09\x09\x09\x09\x09\x0a\x09\x09\x09\x09\x09\x09\x09\x09\x09\x09{{html\x20.Name}}\x0a\x09\x09\x09\x09\x09\x09\x09\x09\x09 | \x0a\x09\x09\x09\x09\x09\x09\x09{{end}}\x0a\x09\x09\x09\x09\x09\x09\x09\x09\x0a\x09\x09\x09\x09\x09\x09\x09\x09\x09{{html\x20.Synopsis}}\x0a\x09\x09\x09\x09\x09\x09\x09\x09 | \x0a\x09\x09\x09\x09\x09\x09\x09{{end}}\x0a\x09\x09\x09\x09\x09\x09\x09
Name | \x0a\x09\x09\x09\x09\x09\x09\x09Synopsis | \x0a\x09\x09\x09\x09\x09\x09|
---|---|---|
\x0a\x09\x09\x09\x09\x09\x09\x09\x09\x09\x09\x09\x09{{html\x20.Path}}\x0a\x09\x09\x09\x09\x09\x09\x09\x09\x09\x09\x09 | \x0a\x09\x09\x09\x09\x09\x09\x09\x09\x09{{end}}\x0a\x09\x09\x09\x09\x09\x09\x09\x09{{else}}\x0a\x09\x09\x09\x09\x09\x09\x09\x09\x09\x09\x0a\x09\x09\x09\x09\x09\x09\x09\x09\x09\x09\x09{{html\x20.Name}}\x0a\x09\x09\x09\x09\x09\x09\x09\x09\x09\x09 | \x0a\x09\x09\x09\x09\x09\x09\x09\x09{{end}}\x0a\x09\x09\x09\x09\x09\x09\x09\x09\x09\x0a\x09\x09\x09\x09\x09\x09\x09\x09\x09\x09{{html\x20.Synopsis}}\x0a\x09\x09\x09\x09\x09\x09\x09\x09\x09 | \x0a\x09\x09\x09\x09\x09\x09\x09\x09{{end}}\x0a\x09\x09\x09\x09\x09\x09\x09
\x0a\x09These\x20packages\x20are\x20part\x20of\x20the\x20Go\x20Project\x20but\x20outside\x20the\x20main\x20Go\x20tree.\x0a\x09They\x20are\x20developed\x20under\x20looser\x20compatibility\x20requirements\x20than\x20the\x20Go\x20core.\x0a\x09Install\x20them\x20with\x20\"go\x20get\".\x0a\x09
\x0a\x09\x0a\x09These\x20services\x20can\x20help\x20you\x20find\x20Open\x20Source\x20packages\x20provided\x20by\x20the\x20community.\x0a\x09
\x0a\x09\x0a\x09{{html\x20.}}\x0a\x09
\x0a{{end}}\x0a{{with\x20.Alt}}\x0a\x09\x0a\x09Did\x20you\x20mean:\x20\x0a\x09{{range\x20.Alts}}\x0a\x09\x09{{html\x20.}}\x0a\x09{{end}}\x0a\x09
\x0a{{end}}\x0a", - "search.txt": "QUERY\x0a\x09{{.Query}}\x0a\x0a{{with\x20.Alert}}{{.}}\x0a{{end}}{{/*\x20.Alert\x20*/}}{{/*\x0a\x0a---------------------------------------\x0a\x0a*/}}{{with\x20.Alt}}DID\x20YOU\x20MEAN\x0a\x0a{{range\x20.Alts}}\x09{{.}}\x0a{{end}}\x0a{{end}}{{/*\x20.Alt\x20*/}}{{/*\x0a\x0a---------------------------------------\x0a\x0a*/}}{{with\x20.Pak}}PACKAGE\x20{{$.Query}}\x0a\x0a{{range\x20.}}\x09{{pkgLink\x20.Pak.Path}}\x0a{{end}}\x0a{{end}}{{/*\x20.Pak\x20*/}}{{/*\x0a\x0a---------------------------------------\x0a\x0a*/}}{{range\x20$key,\x20$val\x20:=\x20.Idents}}{{if\x20$val}}{{$key.Name}}\x0a{{range\x20$val}}\x20\x20\x20\x20{{.Path}}.{{.Name}}\x0a{{end}}\x0a{{end}}{{end}}{{/*\x20.Idents\x20*/}}{{/*\x0a\x0a---------------------------------------\x0a\x0a*/}}{{with\x20.Hit}}{{with\x20.Decls}}PACKAGE-LEVEL\x20DECLARATIONS\x0a\x0a{{range\x20.}}package\x20{{.Pak.Name}}\x0a{{range\x20$file\x20:=\x20.Files}}{{range\x20.Groups}}{{range\x20.}}\x09{{srcLink\x20$file.File.Path}}:{{infoLine\x20.}}{{end}}\x0a{{end}}{{end}}{{/*\x20.Files\x20*/}}\x0a{{end}}{{end}}{{/*\x20.Decls\x20*/}}{{/*\x0a\x0a---------------------------------------\x0a\x0a*/}}{{with\x20.Others}}LOCAL\x20DECLARATIONS\x20AND\x20USES\x0a\x0a{{range\x20.}}package\x20{{.Pak.Name}}\x0a{{range\x20$file\x20:=\x20.Files}}{{range\x20.Groups}}{{range\x20.}}\x09{{srcLink\x20$file.File.Path}}:{{infoLine\x20.}}\x0a{{end}}{{end}}{{end}}{{/*\x20.Files\x20*/}}\x0a{{end}}{{end}}{{/*\x20.Others\x20*/}}{{end}}{{/*\x20.Hit\x20*/}}{{/*\x0a\x0a---------------------------------------\x0a\x0a*/}}{{if\x20.Textual}}{{if\x20.Complete}}{{.Found}}\x20TEXTUAL\x20OCCURRENCES{{else}}MORE\x20THAN\x20{{.Found}}\x20TEXTUAL\x20OCCURRENCES{{end}}\x0a\x0a{{range\x20.Textual}}{{len\x20.Lines}}\x09{{srcLink\x20.Filename}}\x0a{{end}}{{if\x20not\x20.Complete}}...\x09...\x0a{{end}}{{end}}\x0a", - "searchcode.html": "\x0a{{$query_url\x20:=\x20urlquery\x20.Query}}\x0a{{if\x20not\x20.Idents}}\x0a\x09{{with\x20.Pak}}\x0a\x09\x09\x0a\x09\x09
{{$pkg_html}} |
\x0a\x09\x09\x09\x09\x09 | {{index\x20.\x200\x20|\x20infoKind_html}} | \x0a\x09\x09\x09\x09\x09\x0a\x09\x09\x09\x09\x09 | \x0a\x09\x09\x09\x09\x09{{range\x20.}}\x0a\x09\x09\x09\x09\x09\x09{{$line\x20:=\x20infoLine\x20.}}\x0a\x09\x09\x09\x09\x09\x09{{$line}}\x0a\x09\x09\x09\x09\x09{{end}}\x0a\x09\x09\x09\x09\x09 | \x0a\x09\x09\x09\x09\x09
---|
{{comment_html\x20.Doc}}
\x0a\x09\x09\x09{{else}}\x0a\x09\x09\x09\x09No\x20documentation\x20available
\x0a\x09\x09\x09{{end}}\x0a\x09\x09{{end}}\x0a\x09{{end}}\x0a{{end}}\x0a",