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: "",
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 defer func() {
43 if err := rp.pages.RepoSearchResultsFragment(w, params); err != nil {
44 l.Error("failed to render", "err", err)
45 }
46 }()
47
48 if q == "" {
49 return
50 }
51
52 q = fmt.Sprintf(`meta.did:%s %q`, repo.RepoDid, q)
53
54 ctx := r.Context()
55
56 res, err := rp.codesearch.Search(ctx, q, pagination.Page{Limit: 50})
57 if err != nil {
58 l.Error("failed to search files", "err", err)
59 params.ErrorMsg = "Failed to perform search. Please try again later."
60 return
61 }
62
63 if len(res.Results) == 0 {
64 return
65 }
66
67 out := make([]pages.SearchResult, 0, len(res.Results))
68 for _, res := range res.Results {
69 if res.RepoDID != syntax.DID(repo.RepoDid) {
70 continue
71 }
72 csr := pages.SearchResult{
73 RepoDID: res.RepoDID,
74 Repo: repo,
75 FilePath: res.FilePath,
76 Branches: res.Branches,
77 Commit: res.Commit,
78 Language: res.Language,
79 }
80 if f := res.File; f != nil {
81 csr.File = &pages.CodeSearchResult_File{
82 NameSpans: pages.FileNameSpans(res.FilePath, f.Ranges),
83 }
84 }
85 slices.SortStableFunc(res.Chunks, func(a, b models.Result_ChunkMatch) int {
86 return a.ContentStartLine - b.ContentStartLine
87 })
88 for _, c := range res.Chunks {
89 csr.Chunks = append(csr.Chunks, pages.CodeSearchResult_Chunk{
90 Lines: pages.ChunkLines(c.Content, c.ContentStartLine, c.Ranges),
91 MatchCount: len(c.Ranges),
92 })
93 }
94 out = append(out, csr)
95 }
96
97 l.Debug("repo file search result", "len", len(out), "duration", res.Stats.Duration)
98 params.Results = out
99}