This repository has no description
0

Configure Feed

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

core / appview / state / codesearch.go
3.0 kB 113 lines
1package state 2 3import ( 4 "errors" 5 "net/http" 6 "net/url" 7 "slices" 8 9 "github.com/bluesky-social/indigo/atproto/syntax" 10 "tangled.org/core/appview/codesearch" 11 "tangled.org/core/appview/db" 12 "tangled.org/core/appview/models" 13 "tangled.org/core/appview/pages" 14 "tangled.org/core/appview/pagination" 15 "tangled.org/core/orm" 16) 17 18func (s *State) handleCodeSearch(w http.ResponseWriter, r *http.Request) { 19 l := s.logger.With("handler", "CodeSearch") 20 ctx := r.Context() 21 page := pagination.FromContext(ctx) 22 q := r.URL.Query().Get("q") 23 24 var redirected bool 25 var params pages.CodeSearchParams 26 params.BaseParams = pages.BaseParamsFromContext(ctx) 27 params.FilterQuery = q 28 params.Page = page 29 defer func() { 30 if redirected { 31 return 32 } 33 if err := s.pages.CodeSearch(w, params); err != nil { 34 l.Error("failed to render code search", "err", err) 35 } 36 }() 37 38 if q == "" { 39 return 40 } 41 42 res, err := s.codesearch.Search(ctx, q, page) 43 if err != nil { 44 // repo-name-only queries belong to the repo search page; redirect with 45 // the rewritten query (repo: prefix dropped, lang: kept). 46 var repoErr *codesearch.RepoOnlyError 47 if errors.As(err, &repoErr) { 48 redirected = true 49 http.Redirect(w, r, "/search?q="+url.QueryEscape(repoErr.Query), http.StatusFound) 50 return 51 } 52 l.Error("code search failed", "err", err, "query", q) 53 params.ErrorMsg = "Failed to perform search. Please try again later." 54 return 55 } 56 results := res.Results 57 58 repoMap := map[syntax.DID]*models.Repo{} 59 var repoDids []string 60 for _, res := range results { 61 if res.RepoDID == "" { 62 continue 63 } 64 if _, ok := repoMap[res.RepoDID]; !ok { 65 repoMap[res.RepoDID] = nil 66 repoDids = append(repoDids, res.RepoDID.String()) 67 } 68 } 69 if len(repoDids) > 0 { 70 repos, err := db.GetRepos(s.db, orm.FilterIn("repo_did", repoDids)) 71 if err != nil { 72 l.Error("failed to load repos for code search", "err", err) 73 params.ErrorMsg = "Failed to load repos for code search. Please try again later." 74 return 75 } 76 for i := range repos { 77 repoMap[syntax.DID(repos[i].RepoDid)] = &repos[i] 78 } 79 } 80 81 out := make([]pages.SearchResult, 0, len(results)) 82 for _, res := range results { 83 csr := pages.SearchResult{ 84 RepoDID: res.RepoDID, 85 Repo: repoMap[res.RepoDID], 86 FilePath: res.FilePath, 87 Branches: res.Branches, 88 Commit: res.Commit, 89 Language: res.Language, 90 } 91 if f := res.File; f != nil { 92 csr.File = &pages.CodeSearchResult_File{ 93 NameSpans: pages.FileNameSpans(res.FilePath, f.Ranges), 94 } 95 } 96 slices.SortStableFunc(res.Chunks, func(a, b models.Result_ChunkMatch) int { 97 return a.ContentStartLine - b.ContentStartLine 98 }) 99 for _, c := range res.Chunks { 100 csr.Chunks = append(csr.Chunks, pages.CodeSearchResult_Chunk{ 101 Lines: pages.ChunkLines(c.Content, c.ContentStartLine, c.Ranges), 102 MatchCount: len(c.Ranges), 103 }) 104 } 105 out = append(out, csr) 106 } 107 108 params.Results = out 109 params.HasMore = res.HasMore 110 params.MatchCount = res.Stats.MatchCount 111 params.FileCount = res.Stats.FileCount 112 params.TimeTaken = res.Stats.Duration 113}