mirror of
https://github.com/jesseduffield/lazygit.git
synced 2026-01-26 01:41:35 +03:00
Bump gocui and adapt code accordingly
This commit is contained in:
2
go.mod
2
go.mod
@@ -18,7 +18,7 @@ require (
|
||||
github.com/integrii/flaggy v1.4.0
|
||||
github.com/jesseduffield/generics v0.0.0-20250517122708-b0b4a53a6f5c
|
||||
github.com/jesseduffield/go-git/v5 v5.14.1-0.20250407170251-e1a013310ccd
|
||||
github.com/jesseduffield/gocui v0.3.1-0.20260103133810-b7e030324985
|
||||
github.com/jesseduffield/gocui v0.3.1-0.20260104174656-7b510338b235
|
||||
github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5
|
||||
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0
|
||||
github.com/karimkhaleel/jsonschema v0.0.0-20231001195015-d933f0d94ea3
|
||||
|
||||
4
go.sum
4
go.sum
@@ -189,8 +189,8 @@ github.com/jesseduffield/generics v0.0.0-20250517122708-b0b4a53a6f5c h1:tC2Paiis
|
||||
github.com/jesseduffield/generics v0.0.0-20250517122708-b0b4a53a6f5c/go.mod h1:F2fEBk0ddf6ixrBrJjY7phfQ3hL9rXG0uSjvwYe50bE=
|
||||
github.com/jesseduffield/go-git/v5 v5.14.1-0.20250407170251-e1a013310ccd h1:ViKj6qth8FgcIWizn9KiACWwPemWSymx62OPN0tHT+Q=
|
||||
github.com/jesseduffield/go-git/v5 v5.14.1-0.20250407170251-e1a013310ccd/go.mod h1:lRhCiBr6XjQrvcQVa+UYsy/99d3wMXn/a0nSQlhnhlA=
|
||||
github.com/jesseduffield/gocui v0.3.1-0.20260103133810-b7e030324985 h1:qdjGSiNnlGtoi+nzyERQJvee50JpJjeQ6sEhP7jCfMo=
|
||||
github.com/jesseduffield/gocui v0.3.1-0.20260103133810-b7e030324985/go.mod h1:lQCd2TvvNXVKFBowy4A7xxZbUp+1KEiGs4j0Q5Zt9gQ=
|
||||
github.com/jesseduffield/gocui v0.3.1-0.20260104174656-7b510338b235 h1:1MjdFm1rUneE1eMYeRkAA3kXswY+h5eLhgJFaZQs9j0=
|
||||
github.com/jesseduffield/gocui v0.3.1-0.20260104174656-7b510338b235/go.mod h1:lQCd2TvvNXVKFBowy4A7xxZbUp+1KEiGs4j0Q5Zt9gQ=
|
||||
github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5 h1:CDuQmfOjAtb1Gms6a1p5L2P8RhbLUq5t8aL7PiQd2uY=
|
||||
github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5/go.mod h1:qxN4mHOAyeIDLP7IK7defgPClM/z1Kze8VVQiaEjzsQ=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
|
||||
@@ -68,7 +68,8 @@ func NewCommitFilesContext(c *ContextCommon) *CommitFilesContext {
|
||||
},
|
||||
}
|
||||
|
||||
ctx.GetView().SetOnSelectItem(ctx.SearchTrait.onSelectItemWrapper(ctx.OnSearchSelect))
|
||||
ctx.GetView().SetRenderSearchStatus(ctx.SearchTrait.RenderSearchStatus)
|
||||
ctx.GetView().SetOnSelectItem(ctx.OnSearchSelect)
|
||||
|
||||
return ctx
|
||||
}
|
||||
|
||||
@@ -117,10 +117,9 @@ func (self *ListContextTrait) HandleRender() {
|
||||
self.setFooter()
|
||||
}
|
||||
|
||||
func (self *ListContextTrait) OnSearchSelect(selectedLineIdx int) error {
|
||||
func (self *ListContextTrait) OnSearchSelect(selectedLineIdx int) {
|
||||
self.GetList().SetSelection(self.ViewIndexToModelIndex(selectedLineIdx))
|
||||
self.HandleFocus(types.OnFocusOpts{})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *ListContextTrait) IsItemVisible(item types.HasUrn) bool {
|
||||
|
||||
@@ -134,7 +134,8 @@ func NewLocalCommitsContext(c *ContextCommon) *LocalCommitsContext {
|
||||
},
|
||||
}
|
||||
|
||||
ctx.GetView().SetOnSelectItem(ctx.SearchTrait.onSelectItemWrapper(ctx.OnSearchSelect))
|
||||
ctx.GetView().SetRenderSearchStatus(ctx.SearchTrait.RenderSearchStatus)
|
||||
ctx.GetView().SetOnSelectItem(ctx.OnSearchSelect)
|
||||
|
||||
return ctx
|
||||
}
|
||||
|
||||
@@ -31,7 +31,8 @@ func NewMainContext(
|
||||
SearchTrait: NewSearchTrait(c),
|
||||
}
|
||||
|
||||
ctx.GetView().SetOnSelectItem(ctx.SearchTrait.onSelectItemWrapper(func(int) error { return nil }))
|
||||
ctx.GetView().SetRenderSearchStatus(ctx.SearchTrait.RenderSearchStatus)
|
||||
ctx.GetView().SetOnSelectItem(func(int) {})
|
||||
|
||||
return ctx
|
||||
}
|
||||
|
||||
@@ -49,14 +49,12 @@ func NewPatchExplorerContext(
|
||||
SearchTrait: NewSearchTrait(c),
|
||||
}
|
||||
|
||||
ctx.GetView().SetOnSelectItem(ctx.SearchTrait.onSelectItemWrapper(
|
||||
func(selectedLineIdx int) error {
|
||||
ctx.GetMutex().Lock()
|
||||
defer ctx.GetMutex().Unlock()
|
||||
ctx.NavigateTo(selectedLineIdx)
|
||||
return nil
|
||||
}),
|
||||
)
|
||||
ctx.GetView().SetRenderSearchStatus(ctx.SearchTrait.RenderSearchStatus)
|
||||
ctx.GetView().SetOnSelectItem(func(selectedLineIdx int) {
|
||||
ctx.GetMutex().Lock()
|
||||
defer ctx.GetMutex().Unlock()
|
||||
ctx.NavigateTo(selectedLineIdx)
|
||||
})
|
||||
|
||||
ctx.SetHandleRenderFunc(ctx.OnViewWidthChanged)
|
||||
|
||||
|
||||
@@ -36,20 +36,6 @@ func (self *SearchTrait) ClearSearchString() {
|
||||
// used for type switch
|
||||
func (self *SearchTrait) IsSearchableContext() {}
|
||||
|
||||
func (self *SearchTrait) onSelectItemWrapper(innerFunc func(int) error) func(int, int, int) error {
|
||||
return func(selectedLineIdx int, index int, total int) error {
|
||||
self.RenderSearchStatus(index, total)
|
||||
|
||||
if total != 0 {
|
||||
if err := innerFunc(selectedLineIdx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SearchTrait) RenderSearchStatus(index int, total int) {
|
||||
keybindingConfig := self.c.UserConfig().Keybinding
|
||||
|
||||
|
||||
@@ -134,7 +134,8 @@ func NewSubCommitsContext(
|
||||
},
|
||||
}
|
||||
|
||||
ctx.GetView().SetOnSelectItem(ctx.SearchTrait.onSelectItemWrapper(ctx.OnSearchSelect))
|
||||
ctx.GetView().SetRenderSearchStatus(ctx.SearchTrait.RenderSearchStatus)
|
||||
ctx.GetView().SetOnSelectItem(ctx.OnSearchSelect)
|
||||
|
||||
return ctx
|
||||
}
|
||||
|
||||
@@ -56,7 +56,8 @@ func NewWorkingTreeContext(c *ContextCommon) *WorkingTreeContext {
|
||||
},
|
||||
}
|
||||
|
||||
ctx.GetView().SetOnSelectItem(ctx.SearchTrait.onSelectItemWrapper(ctx.OnSearchSelect))
|
||||
ctx.GetView().SetRenderSearchStatus(ctx.SearchTrait.RenderSearchStatus)
|
||||
ctx.GetView().SetOnSelectItem(ctx.OnSearchSelect)
|
||||
|
||||
return ctx
|
||||
}
|
||||
|
||||
@@ -108,20 +108,15 @@ func (self *SearchHelper) Confirm() error {
|
||||
return self.CancelPrompt()
|
||||
}
|
||||
|
||||
var err error
|
||||
switch state.SearchType() {
|
||||
case types.SearchTypeFilter:
|
||||
self.ConfirmFilter()
|
||||
case types.SearchTypeSearch:
|
||||
err = self.ConfirmSearch()
|
||||
self.ConfirmSearch()
|
||||
case types.SearchTypeNone:
|
||||
self.c.Context().Pop()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return self.c.ResetKeybindings()
|
||||
}
|
||||
|
||||
@@ -144,13 +139,13 @@ func (self *SearchHelper) ConfirmFilter() {
|
||||
self.c.Context().Pop()
|
||||
}
|
||||
|
||||
func (self *SearchHelper) ConfirmSearch() error {
|
||||
func (self *SearchHelper) ConfirmSearch() {
|
||||
state := self.searchState()
|
||||
|
||||
context, ok := state.Context.(types.ISearchableContext)
|
||||
if !ok {
|
||||
self.c.Log.Warnf("Context %s is searchable", state.Context.GetKey())
|
||||
return nil
|
||||
return
|
||||
}
|
||||
|
||||
searchString := self.promptContent()
|
||||
@@ -161,7 +156,7 @@ func (self *SearchHelper) ConfirmSearch() error {
|
||||
|
||||
self.c.Context().Pop()
|
||||
|
||||
return context.GetView().Search(searchString, modelSearchResults(context))
|
||||
context.GetView().Search(searchString, modelSearchResults(context))
|
||||
}
|
||||
|
||||
func modelSearchResults(context types.ISearchableContext) []gocui.SearchPosition {
|
||||
|
||||
143
vendor/github.com/jesseduffield/gocui/view.go
generated
vendored
143
vendor/github.com/jesseduffield/gocui/view.go
generated
vendored
@@ -217,29 +217,53 @@ type searcher struct {
|
||||
searchPositions []SearchPosition
|
||||
modelSearchResults []SearchPosition
|
||||
currentSearchIndex int
|
||||
onSelectItem func(int, int, int) error
|
||||
onSelectItem func(int)
|
||||
renderSearchStatus func(int, int)
|
||||
}
|
||||
|
||||
func (v *View) SetOnSelectItem(onSelectItem func(int, int, int) error) {
|
||||
func (v *View) SetRenderSearchStatus(renderSearchStatus func(int, int)) {
|
||||
v.searcher.renderSearchStatus = renderSearchStatus
|
||||
}
|
||||
|
||||
func (v *View) SetOnSelectItem(onSelectItem func(int)) {
|
||||
v.searcher.onSelectItem = onSelectItem
|
||||
}
|
||||
|
||||
func (v *View) renderSearchStatus(index int, itemCount int) {
|
||||
if v.searcher.renderSearchStatus != nil {
|
||||
v.searcher.renderSearchStatus(index, itemCount)
|
||||
}
|
||||
}
|
||||
|
||||
func (v *View) gotoNextMatch() error {
|
||||
if len(v.searcher.searchPositions) == 0 {
|
||||
return nil
|
||||
}
|
||||
if v.Highlight && v.oy+v.cy < v.searcher.searchPositions[v.searcher.currentSearchIndex].Y {
|
||||
// If the selection is before the current match, just jump to the current match and return.
|
||||
// This can only happen if the user has moved the cursor to before the first match.
|
||||
v.SelectSearchResult(v.searcher.currentSearchIndex)
|
||||
return nil
|
||||
}
|
||||
if v.searcher.currentSearchIndex >= len(v.searcher.searchPositions)-1 {
|
||||
v.searcher.currentSearchIndex = 0
|
||||
} else {
|
||||
v.searcher.currentSearchIndex++
|
||||
}
|
||||
return v.SelectSearchResult(v.searcher.currentSearchIndex)
|
||||
v.SelectSearchResult(v.searcher.currentSearchIndex)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *View) gotoPreviousMatch() error {
|
||||
if len(v.searcher.searchPositions) == 0 {
|
||||
return nil
|
||||
}
|
||||
if v.Highlight && v.oy+v.cy > v.searcher.searchPositions[v.searcher.currentSearchIndex].Y {
|
||||
// If the selection is after the current match, just jump to the current match and return.
|
||||
// This happens if the user has moved the cursor down from the current match.
|
||||
v.SelectSearchResult(v.searcher.currentSearchIndex)
|
||||
return nil
|
||||
}
|
||||
if v.searcher.currentSearchIndex == 0 {
|
||||
if len(v.searcher.searchPositions) > 0 {
|
||||
v.searcher.currentSearchIndex = len(v.searcher.searchPositions) - 1
|
||||
@@ -247,13 +271,14 @@ func (v *View) gotoPreviousMatch() error {
|
||||
} else {
|
||||
v.searcher.currentSearchIndex--
|
||||
}
|
||||
return v.SelectSearchResult(v.searcher.currentSearchIndex)
|
||||
v.SelectSearchResult(v.searcher.currentSearchIndex)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *View) SelectSearchResult(index int) error {
|
||||
func (v *View) SelectSearchResult(index int) {
|
||||
itemCount := len(v.searcher.searchPositions)
|
||||
if itemCount == 0 {
|
||||
return nil
|
||||
return
|
||||
}
|
||||
if index > itemCount-1 {
|
||||
index = itemCount - 1
|
||||
@@ -262,10 +287,10 @@ func (v *View) SelectSearchResult(index int) error {
|
||||
y := v.searcher.searchPositions[index].Y
|
||||
|
||||
v.FocusPoint(v.ox, y, true)
|
||||
v.renderSearchStatus(index, itemCount)
|
||||
if v.searcher.onSelectItem != nil {
|
||||
return v.searcher.onSelectItem(y, index, itemCount)
|
||||
v.searcher.onSelectItem(y)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Returns <current match index>, <total matches>
|
||||
@@ -294,26 +319,29 @@ func (v *View) UpdateSearchResults(str string, modelSearchResults []SearchPositi
|
||||
if len(v.searcher.searchPositions) > 0 {
|
||||
// get the first result past the current cursor
|
||||
currentIndex := 0
|
||||
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.XStart > adjustedX) {
|
||||
currentIndex = i
|
||||
break
|
||||
if v.Highlight {
|
||||
// ...but only if we're showing the highlighted line
|
||||
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.XStart > adjustedX) {
|
||||
currentIndex = i
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
v.searcher.currentSearchIndex = currentIndex
|
||||
}
|
||||
}
|
||||
|
||||
func (v *View) Search(str string, modelSearchResults []SearchPosition) error {
|
||||
func (v *View) Search(str string, modelSearchResults []SearchPosition) {
|
||||
v.UpdateSearchResults(str, modelSearchResults)
|
||||
|
||||
if len(v.searcher.searchPositions) > 0 {
|
||||
return v.SelectSearchResult(v.searcher.currentSearchIndex)
|
||||
v.SelectSearchResult(v.searcher.currentSearchIndex)
|
||||
} else {
|
||||
v.renderSearchStatus(0, 0)
|
||||
}
|
||||
|
||||
return v.searcher.onSelectItem(-1, -1, 0)
|
||||
}
|
||||
|
||||
func (v *View) ClearSearch() {
|
||||
@@ -324,8 +352,37 @@ func (v *View) IsSearching() bool {
|
||||
return v.searcher.searchString != ""
|
||||
}
|
||||
|
||||
func (v *View) nearestSearchPosition() int {
|
||||
currentLineIndex := v.cy + v.oy
|
||||
lastSearchPos := 0
|
||||
for i, pos := range v.searcher.searchPositions {
|
||||
if pos.Y == currentLineIndex {
|
||||
return i
|
||||
}
|
||||
if pos.Y > currentLineIndex {
|
||||
break
|
||||
}
|
||||
lastSearchPos = i
|
||||
}
|
||||
return lastSearchPos
|
||||
}
|
||||
|
||||
func (v *View) SetNearestSearchPosition() {
|
||||
if len(v.searcher.searchPositions) > 0 {
|
||||
newPos := v.nearestSearchPosition()
|
||||
if newPos != v.searcher.currentSearchIndex {
|
||||
v.searcher.currentSearchIndex = newPos
|
||||
v.renderSearchStatus(newPos, len(v.searcher.searchPositions))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (v *View) FocusPoint(cx int, cy int, scrollIntoView bool) {
|
||||
lineCount := len(v.lines)
|
||||
v.writeMutex.Lock()
|
||||
defer v.writeMutex.Unlock()
|
||||
|
||||
v.refreshViewLinesIfNeeded()
|
||||
lineCount := len(v.viewLines)
|
||||
if cy < 0 || cy > lineCount {
|
||||
return
|
||||
}
|
||||
@@ -1757,6 +1814,52 @@ func (v *View) setContentLineCount(lineCount int) {
|
||||
v.lines = v.lines[:lineCount]
|
||||
}
|
||||
|
||||
// If the current search result is no longer visible after a scroll up, select the last search
|
||||
// result that is visible in the view, if any, or the first one that is below the view if none is
|
||||
// visible.
|
||||
func (v *View) selectVisibleSearchResultAfterScrollUp() {
|
||||
if !v.Highlight && len(v.searcher.searchPositions) != 0 {
|
||||
windowBottom := v.oy + v.InnerHeight()
|
||||
if v.searcher.searchPositions[v.searcher.currentSearchIndex].Y >= windowBottom {
|
||||
newSearchIndex := v.searcher.currentSearchIndex
|
||||
for newSearchIndex > 0 &&
|
||||
v.searcher.searchPositions[newSearchIndex-1].Y >= v.oy {
|
||||
newSearchIndex--
|
||||
if v.searcher.searchPositions[newSearchIndex].Y < windowBottom {
|
||||
break
|
||||
}
|
||||
}
|
||||
if v.searcher.currentSearchIndex != newSearchIndex {
|
||||
v.searcher.currentSearchIndex = newSearchIndex
|
||||
v.renderSearchStatus(newSearchIndex, len(v.searcher.searchPositions))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the current search result is no longer visible after a scroll down, select the first search
|
||||
// result that is visible in the view, if any, or the last one that is above the view if none is
|
||||
// visible.
|
||||
func (v *View) selectVisibleSearchResultAfterScrollDown() {
|
||||
if !v.Highlight && len(v.searcher.searchPositions) != 0 {
|
||||
if v.searcher.searchPositions[v.searcher.currentSearchIndex].Y < v.oy {
|
||||
newSearchIndex := v.searcher.currentSearchIndex
|
||||
windowBottom := v.oy + v.InnerHeight()
|
||||
for newSearchIndex+1 < len(v.searcher.searchPositions) &&
|
||||
v.searcher.searchPositions[newSearchIndex+1].Y < windowBottom {
|
||||
newSearchIndex++
|
||||
if v.searcher.searchPositions[newSearchIndex].Y >= v.oy {
|
||||
break
|
||||
}
|
||||
}
|
||||
if v.searcher.currentSearchIndex != newSearchIndex {
|
||||
v.searcher.currentSearchIndex = newSearchIndex
|
||||
v.renderSearchStatus(newSearchIndex, len(v.searcher.searchPositions))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (v *View) ScrollUp(amount int) {
|
||||
if amount > v.oy {
|
||||
amount = v.oy
|
||||
@@ -1767,6 +1870,7 @@ func (v *View) ScrollUp(amount int) {
|
||||
v.cy += amount
|
||||
|
||||
v.clearHover()
|
||||
v.selectVisibleSearchResultAfterScrollUp()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1778,6 +1882,7 @@ func (v *View) ScrollDown(amount int) {
|
||||
v.cy -= adjustedAmount
|
||||
|
||||
v.clearHover()
|
||||
v.selectVisibleSearchResultAfterScrollDown()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
2
vendor/modules.txt
vendored
2
vendor/modules.txt
vendored
@@ -211,7 +211,7 @@ github.com/jesseduffield/go-git/v5/utils/merkletrie/internal/frame
|
||||
github.com/jesseduffield/go-git/v5/utils/merkletrie/noder
|
||||
github.com/jesseduffield/go-git/v5/utils/sync
|
||||
github.com/jesseduffield/go-git/v5/utils/trace
|
||||
# github.com/jesseduffield/gocui v0.3.1-0.20260103133810-b7e030324985
|
||||
# github.com/jesseduffield/gocui v0.3.1-0.20260104174656-7b510338b235
|
||||
## explicit; go 1.25
|
||||
github.com/jesseduffield/gocui
|
||||
# github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5
|
||||
|
||||
Reference in New Issue
Block a user