This repository has no description
1package repo
2
3import (
4 "fmt"
5 "net/http"
6 "slices"
7
8 "github.com/bluesky-social/indigo/atproto/syntax"
9 "tangled.org/core/appview/models"
10 "tangled.org/core/appview/pages"
11 "tangled.org/core/appview/pagination"
12)
13
14func (rp *Repo) Search(w http.ResponseWriter, r *http.Request) {
15 if r.Header.Get("Hx-Request") == "true" {
16 if rp.oauth.GetMultiAccountUser(r) != nil {
17 rp.searchResultsFragment(w, r)
18 } else {
19 w.WriteHeader(http.StatusForbidden)
20 }
21 return
22 }
23 if err := rp.pages.RepoSearchPage(w, pages.RepoSearchParams{
24 BaseParams: pages.BaseParamsFromContext(r.Context()),
25 RepoInfo: rp.repoResolver.GetRepoInfo(r, rp.oauth.GetMultiAccountUser(r)),
26 FilterQuery: r.URL.Query().Get("q"),
27 }); err != nil {
28 rp.logger.Error("failed to render", "err", err)
29 }
30}
31
32func (rp *Repo) searchResultsFragment(w http.ResponseWriter, r *http.Request) {
33 l := rp.logger.With("handler", "Search")
34 repo, err := rp.repoResolver.Resolve(r)
35 if err != nil {
36 l.Error("failed to get repo", "err", err)
37 return
38 }
39 q := r.URL.Query().Get("q")
40
41 var params pages.RepoSearchResultsFragmentParams
42 params.Query = q
43 defer func() {
44 if err := rp.pages.RepoSearchResultsFragment(w, params); err != nil {
45 l.Error("failed to render", "err", err)
46 }
47 }()
48
49 if q == "" {
50 return
51 }
52
53 q = fmt.Sprintf(`meta.did:%s %q`, repo.RepoDid, q)
54
55 ctx := r.Context()
56
57 res, err := rp.codesearch.Search(ctx, q, pagination.Page{Limit: 50})
58 if err != nil {
59 l.Error("failed to search files", "err", err)
60 params.ErrorMsg = "Failed to perform search. Please try again later."
61 return
62 }
63
64 if len(res.Results) == 0 {
65 return
66 }
67
68 out := make([]pages.SearchResult, 0, len(res.Results))
69 for _, res := range res.Results {
70 if res.RepoDID != syntax.DID(repo.RepoDid) {
71 continue
72 }
73 csr := pages.SearchResult{
74 RepoDID: res.RepoDID,
75 Repo: repo,
76 FilePath: res.FilePath,
77 Branches: res.Branches,
78 Commit: res.Commit,
79 Language: res.Language,
80 }
81 if f := res.File; f != nil {
82 csr.File = &pages.CodeSearchResult_File{
83 NameSpans: pages.FileNameSpans(res.FilePath, f.Ranges),
84 }
85 }
86 slices.SortStableFunc(res.Chunks, func(a, b models.Result_ChunkMatch) int {
87 return a.ContentStartLine - b.ContentStartLine
88 })
89 for _, c := range res.Chunks {
90 csr.Chunks = append(csr.Chunks, pages.CodeSearchResult_Chunk{
91 Lines: pages.ChunkLines(c.Content, c.ContentStartLine, c.Ranges),
92 MatchCount: len(c.Ranges),
93 })
94 }
95 out = append(out, csr)
96 }
97
98 l.Debug("repo file search result", "len", len(out), "duration", res.Stats.Duration)
99 params.Results = out
100}