summaryrefslogtreecommitdiffstats
path: root/modules/indexer/code/search.go
diff options
context:
space:
mode:
authorLunny Xiao <xiaolunwen@gmail.com>2019-12-23 20:31:16 +0800
committerGitHub <noreply@github.com>2019-12-23 20:31:16 +0800
commit89b4e0477b4e1b9e1cccd87b68fde4ea8a578e9c (patch)
tree46141746472fc33dfa8c262fa96176895bc9fba8 /modules/indexer/code/search.go
parent2f9564f993ba02ba503d7088eb8cc70536b7a6df (diff)
downloadgitea-89b4e0477b4e1b9e1cccd87b68fde4ea8a578e9c.tar.gz
gitea-89b4e0477b4e1b9e1cccd87b68fde4ea8a578e9c.zip
Refactor code indexer (#9313)
* Refactor code indexer * fix test * fix test * refactor code indexer * fix import * improve code * fix typo * fix test and make code clean * fix lint
Diffstat (limited to 'modules/indexer/code/search.go')
-rw-r--r--modules/indexer/code/search.go130
1 files changed, 130 insertions, 0 deletions
diff --git a/modules/indexer/code/search.go b/modules/indexer/code/search.go
new file mode 100644
index 0000000000..18f193a532
--- /dev/null
+++ b/modules/indexer/code/search.go
@@ -0,0 +1,130 @@
+// Copyright 2017 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package code
+
+import (
+ "bytes"
+ "html"
+ gotemplate "html/template"
+ "strings"
+
+ "code.gitea.io/gitea/modules/highlight"
+ "code.gitea.io/gitea/modules/util"
+)
+
+// Result a search result to display
+type Result struct {
+ RepoID int64
+ Filename string
+ HighlightClass string
+ LineNumbers []int
+ FormattedLines gotemplate.HTML
+}
+
+func indices(content string, selectionStartIndex, selectionEndIndex int) (int, int) {
+ startIndex := selectionStartIndex
+ numLinesBefore := 0
+ for ; startIndex > 0; startIndex-- {
+ if content[startIndex-1] == '\n' {
+ if numLinesBefore == 1 {
+ break
+ }
+ numLinesBefore++
+ }
+ }
+
+ endIndex := selectionEndIndex
+ numLinesAfter := 0
+ for ; endIndex < len(content); endIndex++ {
+ if content[endIndex] == '\n' {
+ if numLinesAfter == 1 {
+ break
+ }
+ numLinesAfter++
+ }
+ }
+
+ return startIndex, endIndex
+}
+
+func writeStrings(buf *bytes.Buffer, strs ...string) error {
+ for _, s := range strs {
+ _, err := buf.WriteString(s)
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func searchResult(result *SearchResult, startIndex, endIndex int) (*Result, error) {
+ startLineNum := 1 + strings.Count(result.Content[:startIndex], "\n")
+
+ var formattedLinesBuffer bytes.Buffer
+
+ contentLines := strings.SplitAfter(result.Content[startIndex:endIndex], "\n")
+ lineNumbers := make([]int, len(contentLines))
+ index := startIndex
+ for i, line := range contentLines {
+ var err error
+ if index < result.EndIndex &&
+ result.StartIndex < index+len(line) &&
+ result.StartIndex < result.EndIndex {
+ openActiveIndex := util.Max(result.StartIndex-index, 0)
+ closeActiveIndex := util.Min(result.EndIndex-index, len(line))
+ err = writeStrings(&formattedLinesBuffer,
+ `<li>`,
+ html.EscapeString(line[:openActiveIndex]),
+ `<span class='active'>`,
+ html.EscapeString(line[openActiveIndex:closeActiveIndex]),
+ `</span>`,
+ html.EscapeString(line[closeActiveIndex:]),
+ `</li>`,
+ )
+ } else {
+ err = writeStrings(&formattedLinesBuffer,
+ `<li>`,
+ html.EscapeString(line),
+ `</li>`,
+ )
+ }
+ if err != nil {
+ return nil, err
+ }
+
+ lineNumbers[i] = startLineNum + i
+ index += len(line)
+ }
+ return &Result{
+ RepoID: result.RepoID,
+ Filename: result.Filename,
+ HighlightClass: highlight.FileNameToHighlightClass(result.Filename),
+ LineNumbers: lineNumbers,
+ FormattedLines: gotemplate.HTML(formattedLinesBuffer.String()),
+ }, nil
+}
+
+// PerformSearch perform a search on a repository
+func PerformSearch(repoIDs []int64, keyword string, page, pageSize int) (int, []*Result, error) {
+ if len(keyword) == 0 {
+ return 0, nil, nil
+ }
+
+ total, results, err := indexer.Search(repoIDs, keyword, page, pageSize)
+ if err != nil {
+ return 0, nil, err
+ }
+
+ displayResults := make([]*Result, len(results))
+
+ for i, result := range results {
+ startIndex, endIndex := indices(result.Content, result.StartIndex, result.EndIndex)
+ displayResults[i], err = searchResult(result, startIndex, endIndex)
+ if err != nil {
+ return 0, nil, err
+ }
+ }
+ return int(total), displayResults, nil
+}