1 | // Copyright 2013 The Go Authors. All rights reserved. |
---|---|
2 | // Use of this source code is governed by a BSD-style |
3 | // license that can be found in the LICENSE file. |
4 | |
5 | package godoc |
6 | |
7 | import ( |
8 | "net/http" |
9 | "regexp" |
10 | "sync" |
11 | "text/template" |
12 | |
13 | "golang.org/x/tools/godoc/vfs/httpfs" |
14 | ) |
15 | |
16 | // SearchResultFunc functions return an HTML body for displaying search results. |
17 | type SearchResultFunc func(p *Presentation, result SearchResult) []byte |
18 | |
19 | // Presentation generates output from a corpus. |
20 | type Presentation struct { |
21 | Corpus *Corpus |
22 | |
23 | mux *http.ServeMux |
24 | fileServer http.Handler |
25 | cmdHandler handlerServer |
26 | pkgHandler handlerServer |
27 | |
28 | CallGraphHTML, |
29 | DirlistHTML, |
30 | ErrorHTML, |
31 | ExampleHTML, |
32 | GodocHTML, |
33 | ImplementsHTML, |
34 | MethodSetHTML, |
35 | PackageHTML, |
36 | PackageRootHTML, |
37 | SearchHTML, |
38 | SearchDocHTML, |
39 | SearchCodeHTML, |
40 | SearchTxtHTML, |
41 | SearchDescXML *template.Template // If not nil, register a /opensearch.xml handler with this template. |
42 | |
43 | // TabWidth optionally specifies the tab width. |
44 | TabWidth int |
45 | |
46 | ShowTimestamps bool |
47 | ShowPlayground bool |
48 | DeclLinks bool |
49 | |
50 | // NotesRx optionally specifies a regexp to match |
51 | // notes to render in the output. |
52 | NotesRx *regexp.Regexp |
53 | |
54 | // AdjustPageInfoMode optionally specifies a function to |
55 | // modify the PageInfoMode of a request. The default chosen |
56 | // value is provided. |
57 | AdjustPageInfoMode func(req *http.Request, mode PageInfoMode) PageInfoMode |
58 | |
59 | // URLForSrc optionally specifies a function that takes a source file and |
60 | // returns a URL for it. |
61 | // The source file argument has the form /src/<path>/<filename>. |
62 | URLForSrc func(src string) string |
63 | |
64 | // URLForSrcPos optionally specifies a function to create a URL given a |
65 | // source file, a line from the source file (1-based), and low & high offset |
66 | // positions (0-based, bytes from beginning of file). Ideally, the returned |
67 | // URL will be for the specified line of the file, while the high & low |
68 | // positions will be used to highlight a section of the file. |
69 | // The source file argument has the form /src/<path>/<filename>. |
70 | URLForSrcPos func(src string, line, low, high int) string |
71 | |
72 | // URLForSrcQuery optionally specifies a function to create a URL given a |
73 | // source file, a query string, and a line from the source file (1-based). |
74 | // The source file argument has the form /src/<path>/<filename>. |
75 | // The query argument will be escaped for the purposes of embedding in a URL |
76 | // query parameter. |
77 | // Ideally, the returned URL will be for the specified line of the file with |
78 | // the query string highlighted. |
79 | URLForSrcQuery func(src, query string, line int) string |
80 | |
81 | // SearchResults optionally specifies a list of functions returning an HTML |
82 | // body for displaying search results. |
83 | SearchResults []SearchResultFunc |
84 | |
85 | // GoogleAnalytics optionally adds Google Analytics via the provided |
86 | // tracking ID to each page. |
87 | GoogleAnalytics string |
88 | |
89 | initFuncMapOnce sync.Once |
90 | funcMap template.FuncMap |
91 | templateFuncs template.FuncMap |
92 | } |
93 | |
94 | // NewPresentation returns a new Presentation from a corpus. |
95 | // It sets SearchResults to: |
96 | // [SearchResultDoc SearchResultCode SearchResultTxt]. |
97 | func NewPresentation(c *Corpus) *Presentation { |
98 | if c == nil { |
99 | panic("nil Corpus") |
100 | } |
101 | p := &Presentation{ |
102 | Corpus: c, |
103 | mux: http.NewServeMux(), |
104 | fileServer: http.FileServer(httpfs.New(c.fs)), |
105 | |
106 | TabWidth: 4, |
107 | DeclLinks: true, |
108 | SearchResults: []SearchResultFunc{ |
109 | (*Presentation).SearchResultDoc, |
110 | (*Presentation).SearchResultCode, |
111 | (*Presentation).SearchResultTxt, |
112 | }, |
113 | } |
114 | p.cmdHandler = handlerServer{ |
115 | p: p, |
116 | c: c, |
117 | pattern: "/cmd/", |
118 | fsRoot: "/src", |
119 | } |
120 | p.pkgHandler = handlerServer{ |
121 | p: p, |
122 | c: c, |
123 | pattern: "/pkg/", |
124 | stripPrefix: "pkg/", |
125 | fsRoot: "/src", |
126 | exclude: []string{"/src/cmd"}, |
127 | } |
128 | p.cmdHandler.registerWithMux(p.mux) |
129 | p.pkgHandler.registerWithMux(p.mux) |
130 | p.mux.HandleFunc("/", p.ServeFile) |
131 | p.mux.HandleFunc("/search", p.HandleSearch) |
132 | if p.SearchDescXML != nil { |
133 | p.mux.HandleFunc("/opensearch.xml", p.serveSearchDesc) |
134 | } |
135 | return p |
136 | } |
137 | |
138 | func (p *Presentation) FileServer() http.Handler { |
139 | return p.fileServer |
140 | } |
141 | |
142 | func (p *Presentation) ServeHTTP(w http.ResponseWriter, r *http.Request) { |
143 | p.mux.ServeHTTP(w, r) |
144 | } |
145 | |
146 | func (p *Presentation) PkgFSRoot() string { |
147 | return p.pkgHandler.fsRoot |
148 | } |
149 | |
150 | func (p *Presentation) CmdFSRoot() string { |
151 | return p.cmdHandler.fsRoot |
152 | } |
153 | |
154 | // TODO(bradfitz): move this to be a method on Corpus. Just moving code around for now, |
155 | // but this doesn't feel right. |
156 | func (p *Presentation) GetPkgPageInfo(abspath, relpath string, mode PageInfoMode) *PageInfo { |
157 | return p.pkgHandler.GetPageInfo(abspath, relpath, mode, "", "") |
158 | } |
159 | |
160 | // TODO(bradfitz): move this to be a method on Corpus. Just moving code around for now, |
161 | // but this doesn't feel right. |
162 | func (p *Presentation) GetCmdPageInfo(abspath, relpath string, mode PageInfoMode) *PageInfo { |
163 | return p.cmdHandler.GetPageInfo(abspath, relpath, mode, "", "") |
164 | } |
165 |
Members