// 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 ( "net/http" "regexp" "sync" "text/template" "golang.org/x/tools/godoc/vfs/httpfs" ) // SearchResultFunc functions return an HTML body for displaying search results. type SearchResultFunc func(p *Presentation, result SearchResult) []byte // Presentation generates output from a corpus. type Presentation struct { Corpus *Corpus mux *http.ServeMux fileServer http.Handler cmdHandler handlerServer pkgHandler handlerServer CallGraphHTML, DirlistHTML, ErrorHTML, ExampleHTML, GodocHTML, ImplementsHTML, MethodSetHTML, PackageHTML, PackageRootHTML, SearchHTML, SearchDocHTML, SearchCodeHTML, SearchTxtHTML, SearchDescXML *template.Template // If not nil, register a /opensearch.xml handler with this template. // TabWidth optionally specifies the tab width. TabWidth int ShowTimestamps bool ShowPlayground bool DeclLinks bool // NotesRx optionally specifies a regexp to match // 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 // URLForSrc optionally specifies a function that takes a source file and // returns a URL for it. // The source file argument has the form /src//. URLForSrc func(src string) string // URLForSrcPos optionally specifies a function to create a URL given a // source file, a line from the source file (1-based), and low & high offset // positions (0-based, bytes from beginning of file). Ideally, the returned // URL will be for the specified line of the file, while the high & low // positions will be used to highlight a section of the file. // The source file argument has the form /src//. URLForSrcPos func(src string, line, low, high int) string // URLForSrcQuery optionally specifies a function to create a URL given a // source file, a query string, and a line from the source file (1-based). // The source file argument has the form /src//. // The query argument will be escaped for the purposes of embedding in a URL // query parameter. // Ideally, the returned URL will be for the specified line of the file with // the query string highlighted. URLForSrcQuery func(src, query string, line int) string // SearchResults optionally specifies a list of functions returning an HTML // body for displaying search results. SearchResults []SearchResultFunc // GoogleAnalytics optionally adds Google Analytics via the provided // tracking ID to each page. GoogleAnalytics string initFuncMapOnce sync.Once funcMap template.FuncMap templateFuncs template.FuncMap } // NewPresentation returns a new Presentation from a corpus. // It sets SearchResults to: // [SearchResultDoc SearchResultCode SearchResultTxt]. func NewPresentation(c *Corpus) *Presentation { if c == nil { panic("nil Corpus") } p := &Presentation{ Corpus: c, mux: http.NewServeMux(), fileServer: http.FileServer(httpfs.New(c.fs)), TabWidth: 4, DeclLinks: true, SearchResults: []SearchResultFunc{ (*Presentation).SearchResultDoc, (*Presentation).SearchResultCode, (*Presentation).SearchResultTxt, }, } p.cmdHandler = handlerServer{ p: p, c: c, pattern: "/cmd/", fsRoot: "/src", } p.pkgHandler = handlerServer{ p: p, c: c, pattern: "/pkg/", stripPrefix: "pkg/", fsRoot: "/src", exclude: []string{"/src/cmd"}, } p.cmdHandler.registerWithMux(p.mux) p.pkgHandler.registerWithMux(p.mux) p.mux.HandleFunc("/", p.ServeFile) p.mux.HandleFunc("/search", p.HandleSearch) if p.SearchDescXML != nil { p.mux.HandleFunc("/opensearch.xml", p.serveSearchDesc) } 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, "", "") }