This PR adds zoekt as a code search engine for forgejo. This Pull Request is a continuation of the discussion #8302. The meilisearch search engine was not suitable, as it is not designed for searching by code. The zoekt project was proposed instead. Zoekt copes well with code indexing, but its operating principle differs from such search engines as elasticsearch. While elasticsearch can return a result in a ready-made form (with pagination, ready-made snippets, etc.) and forgejo only needs to show this result in the interface with a little work with the data, zoekt works completely differently. Zoekt finds matches in the repository index and returns a response. The response contains a line with the search word, its number from the file, and also a context, if specified in the request. This response is not suitable for Forgejo, so you need to assemble it yourself. To assemble the response from Zoekt into a form acceptable for Forgejo, I had to write some code and create a new function `searchZoektResult`, since the existing `searchResult` function is completely unsuitable for this search engine. I also had to write logic for pagination, highlighting, and correct display of lines in found snippets with a match, but this is a feature of Zoekt. At the moment, Zoekt does not support deleting a repository index by repo_id, it only supports complete deletion of all repositories. But I still implemented the Delete function, which deletes a specific repository by its ID. Co-authored-by: Aleksandr Gamzin <gamzin@altlinux.org> Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/8827 Reviewed-by: Shiny Nematoda <snematoda@noreply.codeberg.org> Reviewed-by: Gusted <gusted@noreply.codeberg.org>
80 lines
1.8 KiB
Go
80 lines
1.8 KiB
Go
// Copyright 2023 The Gitea Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package internal
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
|
|
"forgejo.org/models/db"
|
|
repo_model "forgejo.org/models/repo"
|
|
"forgejo.org/modules/indexer/internal"
|
|
)
|
|
|
|
// Indexer defines an interface to index and search code contents
|
|
type Indexer interface {
|
|
internal.Indexer
|
|
Index(ctx context.Context, repo *repo_model.Repository, sha string, changes *RepoChanges) error
|
|
Delete(ctx context.Context, repoID int64) error
|
|
Search(ctx context.Context, opts *SearchOptions) (int64, []*SearchResult, []*SearchResultLanguages, error)
|
|
Formatter() ResultFormatter
|
|
}
|
|
|
|
type CodeSearchMode int
|
|
|
|
const (
|
|
CodeSearchModeExact CodeSearchMode = iota
|
|
CodeSearchModeUnion
|
|
CodeSearchModeFuzzy
|
|
)
|
|
|
|
func (mode CodeSearchMode) String() string {
|
|
switch mode {
|
|
case CodeSearchModeFuzzy:
|
|
return "fuzzy"
|
|
case CodeSearchModeUnion:
|
|
return "union"
|
|
default:
|
|
return "exact"
|
|
}
|
|
}
|
|
|
|
type SearchOptions struct {
|
|
RepoIDs []int64
|
|
Keyword string
|
|
Language string
|
|
Filename string
|
|
|
|
Mode CodeSearchMode
|
|
|
|
db.Paginator
|
|
}
|
|
|
|
// NewDummyIndexer returns a dummy indexer
|
|
func NewDummyIndexer() Indexer {
|
|
return &dummyIndexer{
|
|
Indexer: internal.NewDummyIndexer(),
|
|
}
|
|
}
|
|
|
|
type dummyIndexer struct {
|
|
internal.Indexer
|
|
}
|
|
|
|
func (d *dummyIndexer) Index(ctx context.Context, repo *repo_model.Repository, sha string, changes *RepoChanges) error {
|
|
return errors.New("indexer is not ready")
|
|
}
|
|
|
|
func (d *dummyIndexer) Delete(ctx context.Context, repoID int64) error {
|
|
return errors.New("indexer is not ready")
|
|
}
|
|
|
|
func (d *dummyIndexer) Search(ctx context.Context, opts *SearchOptions) (int64, []*SearchResult, []*SearchResultLanguages, error) {
|
|
return 0, nil, nil, errors.New("indexer is not ready")
|
|
}
|
|
|
|
func (d *dummyIndexer) Formatter() ResultFormatter {
|
|
return nil
|
|
}
|