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.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. // Copyright 2017 The Gitea Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package code
  5. import (
  6. "bytes"
  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. return &Result{
  85. RepoID: result.RepoID,
  86. Filename: result.Filename,
  87. CommitID: result.CommitID,
  88. UpdatedUnix: result.UpdatedUnix,
  89. Language: result.Language,
  90. Color: result.Color,
  91. LineNumbers: lineNumbers,
  92. FormattedLines: highlight.Code(result.Filename, formattedLinesBuffer.String()),
  93. }, nil
  94. }
  95. // PerformSearch perform a search on a repository
  96. func PerformSearch(repoIDs []int64, language, keyword string, page, pageSize int) (int, []*Result, []*SearchResultLanguages, error) {
  97. if len(keyword) == 0 {
  98. return 0, nil, nil, nil
  99. }
  100. total, results, resultLanguages, err := indexer.Search(repoIDs, language, keyword, page, pageSize)
  101. if err != nil {
  102. return 0, nil, nil, err
  103. }
  104. displayResults := make([]*Result, len(results))
  105. for i, result := range results {
  106. startIndex, endIndex := indices(result.Content, result.StartIndex, result.EndIndex)
  107. displayResults[i], err = searchResult(result, startIndex, endIndex)
  108. if err != nil {
  109. return 0, nil, nil, err
  110. }
  111. }
  112. return int(total), displayResults, resultLanguages, nil
  113. }