You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

166 lines
4.8 KiB

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