diff --git a/.air/appview.toml b/.air/appview.toml index 172d9313..11666f82 100644 --- a/.air/appview.toml +++ b/.air/appview.toml @@ -6,5 +6,5 @@ cmd = "go build -o out/appview.out cmd/appview/main.go" bin = "out/appview.out" include_ext = ["go"] -exclude_dir = ["avatar", "camo", "sites", "indexes", "nix", "tmp", "out", "target", "node_modules"] +exclude_dir = ["avatar", "bobbin", "camo", "crates", "sites", "indexes", "nix", "tmp", "out", "target", "node_modules", "web"] stop_on_error = true diff --git a/appview/xrpc/search.go b/appview/xrpc/search.go deleted file mode 100644 index 1da9bef4..00000000 --- a/appview/xrpc/search.go +++ /dev/null @@ -1,157 +0,0 @@ -package xrpc - -import ( - "errors" - "fmt" - "net/http" - "strconv" - "strings" - - "github.com/bluesky-social/indigo/atproto/syntax" - "github.com/sourcegraph/zoekt" - tangled "tangled.org/core/api/org_tangled" - "tangled.org/core/appview/codesearch" - "tangled.org/core/appview/pagination" -) - -func (x *Xrpc) SearchSearchCode(w http.ResponseWriter, r *http.Request) { - l := x.Logger.With("handler", "SearchSearchCode") - - if x.CodeSearch == nil { - writeError(w, notImplementedError("Code search is not configured."), http.StatusNotImplemented) - return - } - - q := r.URL.Query() - rawQuery := strings.TrimSpace(q.Get("q")) - if rawQuery == "" { - writeError(w, badRequestError("Missing required parameter: q."), http.StatusBadRequest) - return - } - - // scope by the repo's own did (meta.did) and language; post-filtered below - var scope []string - var repoFilter syntax.DID - if raw := strings.TrimSpace(q.Get("repoDid")); raw != "" { - repoDid, err := syntax.ParseDID(raw) - if err != nil { - writeError(w, badRequestError("Invalid repoDid."), http.StatusBadRequest) - return - } - repoFilter = repoDid - scope = append(scope, fmt.Sprintf("meta.did:%s", repoDid)) - } - if lang := strings.TrimSpace(q.Get("lang")); lang != "" { - scope = append(scope, fmt.Sprintf("lang:%s", lang)) - } - queryStr := strings.TrimSpace(strings.Join(scope, " ") + " " + rawQuery) - - page := pagination.Page{Limit: 50} - if s := q.Get("limit"); s != "" { - if n, err := strconv.Atoi(s); err == nil && n > 0 && n <= 100 { - page.Limit = n - } - } - if s := q.Get("cursor"); s != "" { - if n, err := strconv.Atoi(s); err == nil && n >= 0 { - page.Offset = n - } - } - - res, err := x.CodeSearch.Search(r.Context(), queryStr, page) - if err != nil { - var repoErr *codesearch.RepoOnlyError - if errors.As(err, &repoErr) { - writeError(w, badRequestError("Query only filters by repo name; use repo search instead."), http.StatusBadRequest) - return - } - l.Error("code search failed", "err", err, "query", queryStr) - writeError(w, errInternal, http.StatusInternalServerError) - return - } - - // meta.did is best-effort, so drop anything that isn't the requested repo - filtered := res.Results - if repoFilter != "" { - filtered = filtered[:0] - for _, item := range res.Results { - if item.RepoDID == repoFilter { - filtered = append(filtered, item) - } - } - } - - results := make([]*tangled.TempSearchSearchCode_FileResult, 0, len(filtered)) - for _, item := range filtered { - fr := &tangled.TempSearchSearchCode_FileResult{ - RepoDid: item.RepoDID.String(), - Path: item.FilePath, - } - if item.Language != "" { - lang := item.Language - fr.Language = &lang - } - for _, c := range item.Chunks { - fr.Chunks = append(fr.Chunks, &tangled.TempSearchSearchCode_Chunk{ - Content: c.Content, - LineStart: int64(c.ContentStartLine), - Highlights: chunkHighlights(c.Content, c.ContentStartLine, c.Ranges), - }) - } - results = append(results, fr) - } - - out := &tangled.TempSearchSearchCode_Output{Results: results} - if res.HasMore { - cursor := strconv.Itoa(page.Offset + page.Limit) - out.Cursor = &cursor - } - - x.writeJSON(w, out) -} - -// chunkHighlights maps zoekt (line, rune-column) ranges to byte-offset ranges -// within the chunk's content string -func chunkHighlights(content string, startLine int, ranges []zoekt.Range) []*tangled.TempSearchSearchCode_Highlight { - if startLine < 1 { - startLine = 1 - } - lines := strings.SplitAfter(content, "\n") - lineOffset := make([]int, len(lines)) - off := 0 - for i, ln := range lines { - lineOffset[i] = off - off += len(ln) - } - - // byteAt maps a 1-based (line, rune column) to a byte offset in content - byteAt := func(lineNum, runeCol int) int { - idx := lineNum - startLine - if idx < 0 || idx >= len(lines) { - return -1 - } - col := runeCol - 1 - if col < 0 { - col = 0 - } - r := 0 - for bi := range lines[idx] { - if r == col { - return lineOffset[idx] + bi - } - r++ - } - return lineOffset[idx] + len(strings.TrimSuffix(lines[idx], "\n")) - } - - var out []*tangled.TempSearchSearchCode_Highlight - for _, rg := range ranges { - s := byteAt(int(rg.Start.LineNumber), int(rg.Start.Column)) - e := byteAt(int(rg.End.LineNumber), int(rg.End.Column)) - if s < 0 || e < 0 || e <= s { - continue - } - out = append(out, &tangled.TempSearchSearchCode_Highlight{Start: int64(s), End: int64(e)}) - } - return out -} diff --git a/appview/xrpc/xrpc.go b/appview/xrpc/xrpc.go index 089ad8f6..62d82262 100644 --- a/appview/xrpc/xrpc.go +++ b/appview/xrpc/xrpc.go @@ -51,9 +51,6 @@ func (x *Xrpc) Router() http.Handler { r.Group(func(r chi.Router) { r.Use(x.ServiceAuth.VerifyServiceAuth) - // code search is gated on login, matching the appview ui - r.Get("/"+tangled.TempSearchSearchCodeNSID, x.SearchSearchCode) - // notifications r.Get("/"+tangled.TempNotificationListNotificationsNSID, x.NotificationList) r.Get("/"+tangled.TempNotificationGetUnreadCountNSID, x.NotificationGetUnreadCount)