You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

search.go 3.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. // Copyright 2017 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package code
  4. import (
  5. "bytes"
  6. "context"
  7. "strings"
  8. "code.gitea.io/gitea/modules/highlight"
  9. "code.gitea.io/gitea/modules/timeutil"
  10. "code.gitea.io/gitea/modules/util"
  11. )
  12. // Result a search result to display
  13. type Result struct {
  14. RepoID int64
  15. Filename string
  16. CommitID string
  17. UpdatedUnix timeutil.TimeStamp
  18. Language string
  19. Color string
  20. LineNumbers []int
  21. FormattedLines string
  22. }
  23. func indices(content string, selectionStartIndex, selectionEndIndex int) (int, int) {
  24. startIndex := selectionStartIndex
  25. numLinesBefore := 0
  26. for ; startIndex > 0; startIndex-- {
  27. if content[startIndex-1] == '\n' {
  28. if numLinesBefore == 1 {
  29. break
  30. }
  31. numLinesBefore++
  32. }
  33. }
  34. endIndex := selectionEndIndex
  35. numLinesAfter := 0
  36. for ; endIndex < len(content); endIndex++ {
  37. if content[endIndex] == '\n' {
  38. if numLinesAfter == 1 {
  39. break
  40. }
  41. numLinesAfter++
  42. }
  43. }
  44. return startIndex, endIndex
  45. }
  46. func writeStrings(buf *bytes.Buffer, strs ...string) error {
  47. for _, s := range strs {
  48. _, err := buf.WriteString(s)
  49. if err != nil {
  50. return err
  51. }
  52. }
  53. return nil
  54. }
  55. func searchResult(result *SearchResult, startIndex, endIndex int) (*Result, error) {
  56. startLineNum := 1 + strings.Count(result.Content[:startIndex], "\n")
  57. var formattedLinesBuffer bytes.Buffer
  58. contentLines := strings.SplitAfter(result.Content[startIndex:endIndex], "\n")
  59. lineNumbers := make([]int, len(contentLines))
  60. index := startIndex
  61. for i, line := range contentLines {
  62. var err error
  63. if index < result.EndIndex &&
  64. result.StartIndex < index+len(line) &&
  65. result.StartIndex < result.EndIndex {
  66. openActiveIndex := util.Max(result.StartIndex-index, 0)
  67. closeActiveIndex := util.Min(result.EndIndex-index, len(line))
  68. err = writeStrings(&formattedLinesBuffer,
  69. line[:openActiveIndex],
  70. line[openActiveIndex:closeActiveIndex],
  71. line[closeActiveIndex:],
  72. )
  73. } else {
  74. err = writeStrings(&formattedLinesBuffer,
  75. line,
  76. )
  77. }
  78. if err != nil {
  79. return nil, err
  80. }
  81. lineNumbers[i] = startLineNum + i
  82. index += len(line)
  83. }
  84. highlighted, _ := highlight.Code(result.Filename, "", formattedLinesBuffer.String())
  85. return &Result{
  86. RepoID: result.RepoID,
  87. Filename: result.Filename,
  88. CommitID: result.CommitID,
  89. UpdatedUnix: result.UpdatedUnix,
  90. Language: result.Language,
  91. Color: result.Color,
  92. LineNumbers: lineNumbers,
  93. FormattedLines: highlighted,
  94. }, nil
  95. }
  96. // PerformSearch perform a search on a repository
  97. func PerformSearch(ctx context.Context, repoIDs []int64, language, keyword string, page, pageSize int, isMatch bool) (int, []*Result, []*SearchResultLanguages, error) {
  98. if len(keyword) == 0 {
  99. return 0, nil, nil, nil
  100. }
  101. total, results, resultLanguages, err := indexer.Search(ctx, repoIDs, language, keyword, page, pageSize, isMatch)
  102. if err != nil {
  103. return 0, nil, nil, err
  104. }
  105. displayResults := make([]*Result, len(results))
  106. for i, result := range results {
  107. startIndex, endIndex := indices(result.Content, result.StartIndex, result.EndIndex)
  108. displayResults[i], err = searchResult(result, startIndex, endIndex)
  109. if err != nil {
  110. return 0, nil, nil, err
  111. }
  112. }
  113. return int(total), displayResults, resultLanguages, nil
  114. }