godoc: remove the last of the global variables, unexport Server

The exported Server becomes handlerServer, and part of Presentation
now.  Presentation is also now an http.Handler with its own
internal mux (a detail, which might go away).

main.go becomes ever simpler.

R=golang-dev, adg
CC=golang-dev
https://golang.org/cl/11505043
diff --git a/cmd/godoc/main.go b/cmd/godoc/main.go
index 521b496..148b36d 100644
--- a/cmd/godoc/main.go
+++ b/cmd/godoc/main.go
@@ -110,14 +110,12 @@
 	if pres == nil {
 		panic("nil Presentation")
 	}
-	godoc.CmdHandler.RegisterWithMux(mux)
-	godoc.PkgHandler.RegisterWithMux(mux)
 	mux.HandleFunc("/doc/codewalk/", codewalk)
-	mux.Handle("/doc/play/", godoc.FileServer)
+	mux.Handle("/doc/play/", pres.FileServer())
 	mux.HandleFunc("/search", pres.HandleSearch)
-	mux.Handle("/robots.txt", godoc.FileServer)
+	mux.Handle("/robots.txt", pres.FileServer())
 	mux.HandleFunc("/opensearch.xml", serveSearchDesc)
-	mux.HandleFunc("/", pres.ServeFile)
+	mux.Handle("/", pres)
 }
 
 // ----------------------------------------------------------------------------
@@ -298,6 +296,7 @@
 	}
 
 	corpus := godoc.NewCorpus(fs)
+	corpus.Verbose = *verbose
 	corpus.IndexEnabled = *indexEnabled
 	corpus.IndexFiles = *indexFiles
 	if *writeIndex {
@@ -319,8 +318,6 @@
 
 	readTemplates(pres)
 
-	godoc.InitHandlers(pres)
-
 	if *writeIndex {
 		// Write search index and exit.
 		if *indexFiles == "" {
@@ -429,14 +426,14 @@
 		abspath = target
 		relpath = bp.ImportPath
 	} else {
-		abspath = pathpkg.Join(godoc.PkgHandler.FSRoot(), path)
+		abspath = pathpkg.Join(pres.PkgFSRoot(), path)
 	}
 	if relpath == "" {
 		relpath = abspath
 	}
 
 	var mode godoc.PageInfoMode
-	if relpath == godoc.BuiltinPkgPath {
+	if relpath == "builtin" {
 		// the fake built-in package contains unexported identifiers
 		mode = godoc.NoFiltering
 	}
@@ -451,15 +448,15 @@
 	// first, try as package unless forced as command
 	var info *godoc.PageInfo
 	if !forceCmd {
-		info = godoc.PkgHandler.GetPageInfo(abspath, relpath, mode)
+		info = pres.GetPkgPageInfo(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 *godoc.PageInfo
 	if !filepath.IsAbs(path) {
-		abspath = pathpkg.Join(godoc.CmdHandler.FSRoot(), path)
-		cinfo = godoc.CmdHandler.GetPageInfo(abspath, relpath, mode)
+		abspath = pathpkg.Join(pres.CmdFSRoot(), path)
+		cinfo = pres.GetCmdPageInfo(abspath, relpath, mode)
 	}
 
 	// determine what to use
diff --git a/godoc/corpus.go b/godoc/corpus.go
index fb88944..af9eaee 100644
--- a/godoc/corpus.go
+++ b/godoc/corpus.go
@@ -21,6 +21,9 @@
 type Corpus struct {
 	fs vfs.FileSystem
 
+	// Verbose logging.
+	Verbose bool
+
 	// IndexEnabled controls whether indexing is enabled.
 	IndexEnabled bool
 
diff --git a/godoc/godoc.go b/godoc/godoc.go
index ee55355..0e0bf71 100644
--- a/godoc/godoc.go
+++ b/godoc/godoc.go
@@ -29,12 +29,9 @@
 	"unicode/utf8"
 )
 
-// Verbose controls logging verbosity.
-var Verbose = false
-
 // Fake relative package path for built-ins. Documentation for all globals
 // (not just exported ones) will be shown for packages in this directory.
-const BuiltinPkgPath = "builtin"
+const builtinPkgPath = "builtin"
 
 // FuncMap defines template functions used in godoc templates.
 //
@@ -232,7 +229,7 @@
 	// because of the irregular mapping under goroot
 	// we need to correct certain relative paths
 	relpath = strings.TrimPrefix(relpath, "src/pkg/")
-	return PkgHandler.pattern[1:] + relpath // remove trailing '/' for relative URL
+	return "pkg/" + relpath // remove trailing '/' for relative URL
 }
 
 // n must be an ast.Node or a *doc.Note
diff --git a/godoc/index.go b/godoc/index.go
index 3040a35..5611489 100644
--- a/godoc/index.go
+++ b/godoc/index.go
@@ -1090,14 +1090,14 @@
 }
 
 func (c *Corpus) UpdateIndex() {
-	if Verbose {
+	if c.Verbose {
 		log.Printf("updating index...")
 	}
 	start := time.Now()
 	index := NewIndex(c, c.fsDirnames(), c.MaxResults > 0, c.IndexThrottle)
 	stop := time.Now()
 	c.searchIndex.Set(index)
-	if Verbose {
+	if c.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)",
diff --git a/godoc/linkify.go b/godoc/linkify.go
index ea6cbcf..0a8fb47 100644
--- a/godoc/linkify.go
+++ b/godoc/linkify.go
@@ -94,7 +94,7 @@
 			switch m {
 			case identUse:
 				if n.Obj == nil && predeclared[n.Name] {
-					info.path = BuiltinPkgPath
+					info.path = builtinPkgPath
 				}
 				info.name = n.Name
 			case identDef:
diff --git a/godoc/pres.go b/godoc/pres.go
index c97aa96..3a8b99a 100644
--- a/godoc/pres.go
+++ b/godoc/pres.go
@@ -5,15 +5,23 @@
 package godoc
 
 import (
+	"net/http"
 	"regexp"
 	"sync"
 	"text/template"
+
+	"code.google.com/p/go.tools/godoc/vfs/httpfs"
 )
 
 // Presentation generates output from a corpus.
 type Presentation struct {
 	Corpus *Corpus
 
+	mux        *http.ServeMux
+	fileServer http.Handler
+	cmdHandler handlerServer
+	pkgHandler handlerServer
+
 	DirlistHTML,
 	ErrorHTML,
 	ExampleHTML,
@@ -36,6 +44,11 @@
 	// notes to render in the output.
 	NotesRx *regexp.Regexp
 
+	// AdjustPageInfoMode optionally specifies a function to
+	// modify the PageInfoMode of a request. The default chosen
+	// value is provided.
+	AdjustPageInfoMode func(req *http.Request, mode PageInfoMode) PageInfoMode
+
 	initFuncMapOnce sync.Once
 	funcMap         template.FuncMap
 	templateFuncs   template.FuncMap
@@ -46,10 +59,47 @@
 	if c == nil {
 		panic("nil Corpus")
 	}
-	return &Presentation{
-		Corpus:       c,
+	p := &Presentation{
+		Corpus:     c,
+		mux:        http.NewServeMux(),
+		fileServer: http.FileServer(httpfs.New(c.fs)),
+
 		TabWidth:     4,
 		ShowExamples: true,
 		DeclLinks:    true,
 	}
+	p.cmdHandler = handlerServer{p, c, "/cmd/", "/src/cmd"}
+	p.pkgHandler = handlerServer{p, c, "/pkg/", "/src/pkg"}
+	p.cmdHandler.registerWithMux(p.mux)
+	p.pkgHandler.registerWithMux(p.mux)
+	p.mux.HandleFunc("/", p.ServeFile)
+	return p
+}
+
+func (p *Presentation) FileServer() http.Handler {
+	return p.fileServer
+}
+
+func (p *Presentation) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	p.mux.ServeHTTP(w, r)
+}
+
+func (p *Presentation) PkgFSRoot() string {
+	return p.pkgHandler.fsRoot
+}
+
+func (p *Presentation) CmdFSRoot() string {
+	return p.cmdHandler.fsRoot
+}
+
+// TODO(bradfitz): move this to be a method on Corpus. Just moving code around for now,
+// but this doesn't feel right.
+func (p *Presentation) GetPkgPageInfo(abspath, relpath string, mode PageInfoMode) *PageInfo {
+	return p.pkgHandler.GetPageInfo(abspath, relpath, mode)
+}
+
+// TODO(bradfitz): move this to be a method on Corpus. Just moving code around for now,
+// but this doesn't feel right.
+func (p *Presentation) GetCmdPageInfo(abspath, relpath string, mode PageInfoMode) *PageInfo {
+	return p.cmdHandler.GetPageInfo(abspath, relpath, mode)
 }
diff --git a/godoc/search.go b/godoc/search.go
index 8d5b4e3..a50de5f 100644
--- a/godoc/search.go
+++ b/godoc/search.go
@@ -78,7 +78,7 @@
 	query := strings.TrimSpace(r.FormValue("q"))
 	result := p.Corpus.Lookup(query)
 
-	if GetPageInfoMode(r)&NoHTML != 0 {
+	if p.GetPageInfoMode(r)&NoHTML != 0 {
 		p.ServeText(w, applyTemplate(p.SearchText, "searchText", result))
 		return
 	}
diff --git a/godoc/server.go b/godoc/server.go
index 91b3960..b3b05d8 100644
--- a/godoc/server.go
+++ b/godoc/server.go
@@ -25,35 +25,18 @@
 
 	"code.google.com/p/go.tools/godoc/util"
 	"code.google.com/p/go.tools/godoc/vfs"
-	"code.google.com/p/go.tools/godoc/vfs/httpfs"
 )
 
-// TODO(bradfitz,adg): these are moved from godoc.go globals.
-// Clean this up.
-var (
-	FileServer http.Handler // default file server
-	CmdHandler Server
-	PkgHandler Server
-)
-
-func InitHandlers(p *Presentation) {
-	c := p.Corpus
-	FileServer = http.FileServer(httpfs.New(c.fs))
-	CmdHandler = Server{p, c, "/cmd/", "/src/cmd"}
-	PkgHandler = Server{p, c, "/pkg/", "/src/pkg"}
-}
-
-// Server is a godoc server.
-type Server struct {
+// handlerServer is a migration from an old godoc http Handler type.
+// This should probably merge into something else.
+type handlerServer struct {
 	p       *Presentation
 	c       *Corpus // copy of p.Corpus
 	pattern string  // url pattern; e.g. "/pkg/"
 	fsRoot  string  // file system root to which the pattern is mapped
 }
 
-func (s *Server) FSRoot() string { return s.fsRoot }
-
-func (s *Server) RegisterWithMux(mux *http.ServeMux) {
+func (s *handlerServer) registerWithMux(mux *http.ServeMux) {
 	mux.Handle(s.pattern, s)
 }
 
@@ -65,7 +48,7 @@
 // directories, PageInfo.Dirs is nil. If an error occurred, PageInfo.Err is
 // set to the respective error but the error is not logged.
 //
-func (h *Server) GetPageInfo(abspath, relpath string, mode PageInfoMode) *PageInfo {
+func (h *handlerServer) GetPageInfo(abspath, relpath string, mode PageInfoMode) *PageInfo {
 	info := &PageInfo{Dirname: abspath}
 
 	// Restrict to the package files that would be used when building
@@ -194,15 +177,15 @@
 	return info
 }
 
-func (h *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+func (h *handlerServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 	if redirect(w, r) {
 		return
 	}
 
 	relpath := pathpkg.Clean(r.URL.Path[len(h.pattern):])
 	abspath := pathpkg.Join(h.fsRoot, relpath)
-	mode := GetPageInfoMode(r)
-	if relpath == BuiltinPkgPath {
+	mode := h.p.GetPageInfoMode(r)
+	if relpath == builtinPkgPath {
 		mode = NoFiltering
 	}
 	info := h.GetPageInfo(abspath, relpath, mode)
@@ -279,19 +262,16 @@
 // GetPageInfoMode computes the PageInfoMode flags by analyzing the request
 // URL form value "m". It is value is a comma-separated list of mode names
 // as defined by modeNames (e.g.: m=src,text).
-func GetPageInfoMode(r *http.Request) PageInfoMode {
+func (p *Presentation) GetPageInfoMode(r *http.Request) PageInfoMode {
 	var mode PageInfoMode
 	for _, k := range strings.Split(r.FormValue("m"), ",") {
 		if m, found := modeNames[strings.TrimSpace(k)]; found {
 			mode |= m
 		}
 	}
-	return AdjustPageInfoMode(r, mode)
-}
-
-// AdjustPageInfoMode allows specialized versions of godoc to adjust
-// PageInfoMode by overriding this variable.
-var AdjustPageInfoMode = func(_ *http.Request, mode PageInfoMode) PageInfoMode {
+	if p.AdjustPageInfoMode != nil {
+		mode = p.AdjustPageInfoMode(r, mode)
+	}
 	return mode
 }
 
@@ -584,7 +564,7 @@
 		return
 	}
 
-	FileServer.ServeHTTP(w, r)
+	p.fileServer.ServeHTTP(w, r)
 }
 
 func (p *Presentation) serveSearchDesc(w http.ResponseWriter, r *http.Request) {