diff options
author | Stefan Haller <stefan@haller-berlin.de> | 2024-05-31 17:24:50 +0200 |
---|---|---|
committer | Stefan Haller <stefan@haller-berlin.de> | 2024-06-23 11:43:12 +0200 |
commit | 6a6316cfb632a28627e067c8a4d30786acffee38 (patch) | |
tree | e9092175bcdac6fbd3df73fffb9c72fe37d54ffa /vendor/github.com | |
parent | 779e6f95a3fca869fb886201305217deb2dca8f5 (diff) |
Use model searching in commits (and sub-commits) view
Diffstat (limited to 'vendor/github.com')
-rw-r--r-- | vendor/github.com/jesseduffield/gocui/view.go | 119 |
1 files changed, 90 insertions, 29 deletions
diff --git a/vendor/github.com/jesseduffield/gocui/view.go b/vendor/github.com/jesseduffield/gocui/view.go index a84e1b0ce..68b0f49c6 100644 --- a/vendor/github.com/jesseduffield/gocui/view.go +++ b/vendor/github.com/jesseduffield/gocui/view.go @@ -184,7 +184,8 @@ func (v *View) clearViewLines() { type searcher struct { searchString string - searchPositions []cellPos + searchPositions []SearchPosition + modelSearchResults []SearchPosition currentSearchIndex int onSelectItem func(int, int, int) error } @@ -228,7 +229,7 @@ func (v *View) SelectSearchResult(index int) error { index = itemCount - 1 } - y := v.searcher.searchPositions[index].y + y := v.searcher.searchPositions[index].Y v.FocusPoint(v.ox, y) if v.searcher.onSelectItem != nil { @@ -242,9 +243,22 @@ func (v *View) GetSearchStatus() (int, int) { return v.searcher.currentSearchIndex, len(v.searcher.searchPositions) } -func (v *View) Search(str string) error { +// modelSearchResults is optional; pass nil to search the view. If non-nil, +// these positions will be used for highlighting search results. Even in this +// case the view will still be searched on a per-line basis, so that the caller +// doesn't have to make assumptions where in the rendered line the search result +// is. The XStart and XEnd values in the modelSearchResults are only used in +// case the search string is not found in the given line, which can happen if +// the view renders an abbreviated version of some of the model data. +// +// Mind the difference between nil and empty slice: nil means we're not +// searching the model, empty slice means we *are* searching the model but we +// didn't find any matches. +func (v *View) UpdateSearchResults(str string, modelSearchResults []SearchPosition) { v.writeMutex.Lock() - v.searcher.search(str) + defer v.writeMutex.Unlock() + + v.searcher.search(str, modelSearchResults) v.updateSearchPositions() if len(v.searcher.searchPositions) > 0 { @@ -253,20 +267,25 @@ func (v *View) Search(str string) error { adjustedY := v.oy + v.cy adjustedX := v.ox + v.cx for i, pos := range v.searcher.searchPositions { - if pos.y > adjustedY || (pos.y == adjustedY && pos.x > adjustedX) { + if pos.Y > adjustedY || (pos.Y == adjustedY && pos.XStart > adjustedX) { currentIndex = i break } } v.searcher.currentSearchIndex = currentIndex - v.writeMutex.Unlock() - return v.SelectSearchResult(currentIndex) - } else { - v.writeMutex.Unlock() - return v.searcher.onSelectItem(-1, -1, 0) } } +func (v *View) Search(str string, modelSearchResults []SearchPosition) error { + v.UpdateSearchResults(str, modelSearchResults) + + if len(v.searcher.searchPositions) > 0 { + return v.SelectSearchResult(v.searcher.currentSearchIndex) + } + + return v.searcher.onSelectItem(-1, -1, 0) +} + func (v *View) ClearSearch() { v.searcher.clearSearch() } @@ -324,21 +343,23 @@ func calculateNewOrigin(selectedLine int, oldOrigin int, lineCount int, viewHeig return oldOrigin } -func (s *searcher) search(str string) { +func (s *searcher) search(str string, modelSearchResults []SearchPosition) { s.searchString = str - s.searchPositions = []cellPos{} + s.searchPositions = []SearchPosition{} + s.modelSearchResults = modelSearchResults s.currentSearchIndex = 0 } func (s *searcher) clearSearch() { s.searchString = "" - s.searchPositions = []cellPos{} + s.searchPositions = []SearchPosition{} s.currentSearchIndex = 0 } -type cellPos struct { - x int - y int +type SearchPosition struct { + XStart int + XEnd int + Y int } type viewLine struct { @@ -489,6 +510,14 @@ func (v *View) setRune(x, y int, ch rune, fgColor, bgColor Attribute) error { } } + if matched, selected := v.isPatternMatchedRune(x, y); matched { + if selected { + bgColor = ColorCyan + } else { + bgColor = ColorYellow + } + } + // Don't display NUL characters if ch == 0 { ch = ' ' @@ -752,6 +781,8 @@ func (v *View) writeRunes(p []rune) { } } } + + v.updateSearchPositions() } // exported functions use the mutex. Non-exported functions are for internal use @@ -957,8 +988,11 @@ func (v *View) updateSearchPositions() { normalizedSearchStr = strings.ToLower(v.searcher.searchString) } - v.searcher.searchPositions = []cellPos{} - for y, line := range v.lines { + v.searcher.searchPositions = []SearchPosition{} + + searchPositionsForLine := func(line []cell, y int) []SearchPosition { + var result []SearchPosition + searchStringWidth := runewidth.StringWidth(v.searcher.searchString) x := 0 for startIdx, c := range line { found := true @@ -975,10 +1009,46 @@ func (v *View) updateSearchPositions() { offset += 1 } if found { - v.searcher.searchPositions = append(v.searcher.searchPositions, cellPos{x: x, y: y}) + result = append(result, SearchPosition{XStart: x, XEnd: x + searchStringWidth, Y: y}) } x += runewidth.RuneWidth(c.chr) } + return result + } + + if v.searcher.modelSearchResults != nil { + for _, result := range v.searcher.modelSearchResults { + if result.Y >= len(v.lines) { + break + } + + // If a view line exists for this line index: + if v.lines[result.Y] != nil { + // search this view line for the search string + positions := searchPositionsForLine(v.lines[result.Y], result.Y) + if len(positions) > 0 { + // If we found any occurrences, add them + v.searcher.searchPositions = append(v.searcher.searchPositions, positions...) + } else { + // Otherwise, the search string was found in the model + // but not in the view line; this can happen if the view + // renders only truncated versions of the model strings. + // In this case, add one search position with what the + // model search function returned. + v.searcher.searchPositions = append(v.searcher.searchPositions, result) + } + } else { + // We don't have a view line for this line index. Add a + // searchPosition anyway, just for the sake of being able to + // show the "n of m" search status. The X positions don't + // matter in this case. + v.searcher.searchPositions = append(v.searcher.searchPositions, SearchPosition{XStart: -1, XEnd: -1, Y: result.Y}) + } + } + } else { + for y, line := range v.lines { + v.searcher.searchPositions = append(v.searcher.searchPositions, searchPositionsForLine(line, y)...) + } } } } @@ -999,7 +1069,6 @@ func (v *View) draw() error { v.clearRunes() - v.updateSearchPositions() maxX, maxY := v.Size() if v.Wrap { @@ -1103,13 +1172,6 @@ func (v *View) draw() error { if bgColor == ColorDefault { bgColor = v.BgColor } - if matched, selected := v.isPatternMatchedRune(x, y); matched { - if selected { - bgColor = ColorCyan - } else { - bgColor = ColorYellow - } - } if err := v.setRune(x, y, c.chr, fgColor, bgColor); err != nil { return err @@ -1137,11 +1199,10 @@ func (v *View) viewLineLengthIgnoringTrailingBlankLines() int { } func (v *View) isPatternMatchedRune(x, y int) (bool, bool) { - searchStringWidth := runewidth.StringWidth(v.searcher.searchString) for i, pos := range v.searcher.searchPositions { adjustedY := y + v.oy adjustedX := x + v.ox - if adjustedY == pos.y && adjustedX >= pos.x && adjustedX < pos.x+searchStringWidth { + if adjustedY == pos.Y && adjustedX >= pos.XStart && adjustedX < pos.XEnd { return true, i == v.searcher.currentSearchIndex } } |