summaryrefslogtreecommitdiffstats
path: root/vendor/github.com
diff options
context:
space:
mode:
authorStefan Haller <stefan@haller-berlin.de>2024-05-31 17:24:50 +0200
committerStefan Haller <stefan@haller-berlin.de>2024-06-23 11:43:12 +0200
commit6a6316cfb632a28627e067c8a4d30786acffee38 (patch)
treee9092175bcdac6fbd3df73fffb9c72fe37d54ffa /vendor/github.com
parent779e6f95a3fca869fb886201305217deb2dca8f5 (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.go119
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
}
}