mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-06-27 00:51:18 +02:00
Use model searching in commits (and sub-commits) view
This commit is contained in:
119
vendor/github.com/jesseduffield/gocui/view.go
generated
vendored
119
vendor/github.com/jesseduffield/gocui/view.go
generated
vendored
@ -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
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user