// Copyright 2017 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT package code import ( "bytes" "context" "html/template" "strings" "code.gitea.io/gitea/modules/highlight" "code.gitea.io/gitea/modules/indexer/code/internal" "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/services/gitdiff" ) // Result a search result to display type Result struct { RepoID int64 Filename string CommitID string UpdatedUnix timeutil.TimeStamp Language string Color string Lines []ResultLine } type ResultLine struct { Num int FormattedContent template.HTML } type SearchResultLanguages = internal.SearchResultLanguages type SearchOptions = internal.SearchOptions var CodeSearchOptions = [2]string{"exact", "fuzzy"} 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 } const ( highlightTagStart = "" highlightTagEnd = "" ) func HighlightSearchResultCode(filename string, lineNums []int, highlightRanges [][3]int, code string) []ResultLine { hcd := gitdiff.NewHighlightCodeDiff() hcd.CollectUsedRunes(code) startTag, endTag := hcd.NextPlaceholder(), hcd.NextPlaceholder() hcd.PlaceholderTokenMap[startTag] = highlightTagStart hcd.PlaceholderTokenMap[endTag] = highlightTagEnd // we should highlight the whole code block first, otherwise it doesn't work well with multiple line highlighting hl, _ := highlight.Code(filename, "", code) conv := hcd.ConvertToPlaceholders(string(hl)) convLines := strings.Split(conv, "\n") // each highlightRange is of the form [line number, start pos, end pos] for _, highlightRange := range highlightRanges { ln, start, end := highlightRange[0], highlightRange[1], highlightRange[2] line := convLines[ln] if line == "" || len(line) <= start || len(line) < end { continue } sb := strings.Builder{} count := -1 isOpen := false for _, r := range line { if token, ok := hcd.PlaceholderTokenMap[r]; // token was not found !ok || // token was marked as used token == "" || // the token is not an valid html tag emitted by chroma !(len(token) > 6 && (token[0:5] == "