This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

core / appview / repo / filesearch.go
2.5 kB 99 lines
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}