+++ /dev/null
-// 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.
-
-package godoc
-
-import (
- "bytes"
- "fmt"
- "net/http"
- "regexp"
- "strings"
-)
-
-type SearchResult struct {
- Query string
- Alert string // error or warning message
-
- // identifier matches
- Pak HitList // packages matching Query
- Hit *LookupResult // identifier matches of Query
- Alt *AltWords // alternative identifiers to look for
-
- // textual matches
- Found int // number of textual occurrences found
- Textual []FileLines // textual matches of Query
- Complete bool // true if all textual occurrences of Query are reported
- Idents map[SpotKind][]Ident
-}
-
-func (c *Corpus) Lookup(query string) SearchResult {
- result := &SearchResult{Query: query}
-
- index, timestamp := c.CurrentIndex()
- if index != nil {
- // identifier search
- if r, err := index.Lookup(query); err == nil {
- result = r
- } else if err != nil && !c.IndexFullText {
- // ignore the error if full text search is enabled
- // since the query may be a valid regular expression
- result.Alert = "Error in query string: " + err.Error()
- return *result
- }
-
- // full text search
- if c.IndexFullText && query != "" {
- rx, err := regexp.Compile(query)
- if err != nil {
- result.Alert = "Error in query regular expression: " + err.Error()
- return *result
- }
- // If we get maxResults+1 results we know that there are more than
- // maxResults results and thus the result may be incomplete (to be
- // precise, we should remove one result from the result set, but
- // nobody is going to count the results on the result page).
- result.Found, result.Textual = index.LookupRegexp(rx, c.MaxResults+1)
- result.Complete = result.Found <= c.MaxResults
- if !result.Complete {
- result.Found-- // since we looked for maxResults+1
- }
- }
- }
-
- // is the result accurate?
- if c.IndexEnabled {
- if ts := c.FSModifiedTime(); timestamp.Before(ts) {
- // The index is older than the latest file system change under godoc's observation.
- result.Alert = "Indexing in progress: result may be inaccurate"
- }
- } else {
- result.Alert = "Search index disabled: no results available"
- }
-
- return *result
-}
-
-// SearchResultDoc optionally specifies a function returning an HTML body
-// displaying search results matching godoc documentation.
-func (p *Presentation) SearchResultDoc(result SearchResult) []byte {
- return applyTemplate(p.SearchDocHTML, "searchDocHTML", result)
-}
-
-// SearchResultCode optionally specifies a function returning an HTML body
-// displaying search results matching source code.
-func (p *Presentation) SearchResultCode(result SearchResult) []byte {
- return applyTemplate(p.SearchCodeHTML, "searchCodeHTML", result)
-}
-
-// SearchResultTxt optionally specifies a function returning an HTML body
-// displaying search results of textual matches.
-func (p *Presentation) SearchResultTxt(result SearchResult) []byte {
- return applyTemplate(p.SearchTxtHTML, "searchTxtHTML", result)
-}
-
-// HandleSearch obtains results for the requested search and returns a page
-// to display them.
-func (p *Presentation) HandleSearch(w http.ResponseWriter, r *http.Request) {
- query := strings.TrimSpace(r.FormValue("q"))
- result := p.Corpus.Lookup(query)
-
- var contents bytes.Buffer
- for _, f := range p.SearchResults {
- contents.Write(f(p, result))
- }
-
- var title string
- if haveResults := contents.Len() > 0; haveResults {
- title = fmt.Sprintf(`Results for query: %v`, query)
- if !p.Corpus.IndexEnabled {
- result.Alert = ""
- }
- } else {
- title = fmt.Sprintf(`No results found for query %q`, query)
- }
-
- body := bytes.NewBuffer(applyTemplate(p.SearchHTML, "searchHTML", result))
- body.Write(contents.Bytes())
-
- p.ServePage(w, Page{
- Title: title,
- Tabtitle: query,
- Query: query,
- Body: body.Bytes(),
- GoogleCN: googleCN(r),
- })
-}
-
-func (p *Presentation) serveSearchDesc(w http.ResponseWriter, r *http.Request) {
- w.Header().Set("Content-Type", "application/opensearchdescription+xml")
- data := map[string]interface{}{
- "BaseURL": fmt.Sprintf("http://%s", r.Host),
- }
- applyTemplateToResponseWriter(w, p.SearchDescXML, &data)
-}
-
-// tocColCount returns the no. of columns
-// to split the toc table to.
-func tocColCount(result SearchResult) int {
- tocLen := tocLen(result)
- colCount := 0
- // Simple heuristic based on visual aesthetic in manual testing.
- switch {
- case tocLen <= 10:
- colCount = 1
- case tocLen <= 20:
- colCount = 2
- case tocLen <= 80:
- colCount = 3
- default:
- colCount = 4
- }
- return colCount
-}
-
-// tocLen calculates the no. of items in the toc table
-// by going through various fields in the SearchResult
-// that is rendered in the UI.
-func tocLen(result SearchResult) int {
- tocLen := 0
- for _, val := range result.Idents {
- if len(val) != 0 {
- tocLen++
- }
- }
- // If no identifiers, then just one item for the header text "Package <result.Query>".
- // See searchcode.html for further details.
- if len(result.Idents) == 0 {
- tocLen++
- }
- if result.Hit != nil {
- if len(result.Hit.Decls) > 0 {
- tocLen += len(result.Hit.Decls)
- // We need one extra item for the header text "Package-level declarations".
- tocLen++
- }
- if len(result.Hit.Others) > 0 {
- tocLen += len(result.Hit.Others)
- // We need one extra item for the header text "Local declarations and uses".
- tocLen++
- }
- }
- // For "textual occurrences".
- tocLen++
- return tocLen
-}