From ee07abe5083e0a1c5b0f4251b5fbcbf7efc018bc Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Fri, 30 Oct 2026 21:07:49 +0100 Subject: [PATCH] Load all commits when the selection is near the end of the loaded ones The commits and sub-commits views load the first 300 commits, and load all of them once the user selects a commit beyond the 200th. A later commit loads more than 300 commits while bisecting, so that the commit to test is among them. If it is beyond the 200th, it would cause all commits to be loaded as soon as it gets selected. Remember how many commits the views were loaded with, and load all of them only when the selection gets within 100 commits of that number. For the views loaded with 300 commits, nothing changes. Co-Authored-By: Claude Opus 5.5 --- pkg/gui/context/local_commits_context.go | 12 ++++++++++++ pkg/gui/context/sub_commits_context.go | 15 +++++++++++++-- pkg/gui/controllers/helpers/refresh_helper.go | 8 ++++++-- pkg/gui/controllers/helpers/sub_commits_helper.go | 1 + pkg/gui/controllers/local_commits_controller.go | 9 ++++++--- 5 files changed, 38 insertions(+), 7 deletions(-) diff --git a/pkg/gui/context/local_commits_context.go b/pkg/gui/context/local_commits_context.go index 0f09c859c..e9faf3911 100644 --- a/pkg/gui/context/local_commits_context.go +++ b/pkg/gui/context/local_commits_context.go @@ -343,6 +343,10 @@ type LocalCommitsViewModel struct { // commits refresh reads it on the UI thread to decide how many commits to load. limitCommits atomic.Bool + // The limit that the commits in the model were loaded with, or 0 if they + // were loaded without one. + loadedCommitLimit int + // If this is true we'll use git log --all when fetching the commits. showWholeGitGraph bool } @@ -431,6 +435,14 @@ func (self *LocalCommitsViewModel) GetLimitCommits() bool { return self.limitCommits.Load() } +func (self *LocalCommitsViewModel) SetLoadedCommitLimit(value int) { + self.loadedCommitLimit = value +} + +func (self *LocalCommitsViewModel) GetLoadedCommitLimit() int { + return self.loadedCommitLimit +} + func (self *LocalCommitsViewModel) SetShowWholeGitGraph(value bool) { self.showWholeGitGraph = value } diff --git a/pkg/gui/context/sub_commits_context.go b/pkg/gui/context/sub_commits_context.go index e99b5d281..73d3022b5 100644 --- a/pkg/gui/context/sub_commits_context.go +++ b/pkg/gui/context/sub_commits_context.go @@ -174,8 +174,11 @@ type SubCommitsViewModel struct { refToShowDivergenceFrom string *ListViewModel[*models.Commit] - limitCommits bool - showBranchHeads bool + limitCommits bool + // The limit that the commits in the model were loaded with, or 0 if they + // were loaded without one. + loadedCommitLimit int + showBranchHeads bool } func (self *SubCommitsViewModel) SetRef(ref models.Ref) { @@ -239,6 +242,14 @@ func (self *SubCommitsContext) GetLimitCommits() bool { return self.limitCommits } +func (self *SubCommitsContext) SetLoadedCommitLimit(value int) { + self.loadedCommitLimit = value +} + +func (self *SubCommitsContext) GetLoadedCommitLimit() int { + return self.loadedCommitLimit +} + func (self *SubCommitsContext) GetDiffTerminals() []string { itemId := self.GetSelectedItemId() diff --git a/pkg/gui/controllers/helpers/refresh_helper.go b/pkg/gui/controllers/helpers/refresh_helper.go index f6fc539b2..c67e79f0c 100644 --- a/pkg/gui/controllers/helpers/refresh_helper.go +++ b/pkg/gui/controllers/helpers/refresh_helper.go @@ -854,9 +854,10 @@ func (self *RefreshHelper) determineCheckedOutRef(env refreshEnv) models.Ref { func (self *RefreshHelper) refreshCommitsWithLimit(captured capturedCommitState, commitSelection types.CommitSelectionBehavior, env refreshEnv) error { checkedOutRef := self.determineCheckedOutRef(env) refName, bisectInfo := self.refForLog(env) + limit := lo.Ternary(captured.limitCommits, commitLimit, 0) commits, err := env.git.Loaders.CommitLoader.GetCommits( git_commands.GetCommitsOptions{ - Limit: lo.Ternary(captured.limitCommits, commitLimit, 0), + Limit: limit, FilterPath: captured.filterPath, FilterAuthor: captured.filterAuthor, IncludeRebaseCommits: true, @@ -886,6 +887,7 @@ func (self *RefreshHelper) refreshCommitsWithLimit(captured capturedCommitState, self.c.Model().BisectInfo = bisectInfo self.c.Model().Commits = commits + self.c.Contexts().LocalCommits.SetLoadedCommitLimit(limit) self.c.Model().CommitsWereFilteredAtLastRefresh = captured.filterPath != "" || captured.filterAuthor != "" self.RefreshAuthors(commits) self.c.Model().WorkingTreeStateAtLastCommitRefresh = workingTreeState @@ -1075,9 +1077,10 @@ func (self *RefreshHelper) refreshSubCommitsWithLimit(captured capturedSubCommit return nil } + limit := lo.Ternary(captured.limitCommits, commitLimit, 0) commits, err := env.git.Loaders.CommitLoader.GetCommits( git_commands.GetCommitsOptions{ - Limit: lo.Ternary(captured.limitCommits, commitLimit, 0), + Limit: limit, FilterPath: captured.filterPath, FilterAuthor: captured.filterAuthor, IncludeRebaseCommits: false, @@ -1093,6 +1096,7 @@ func (self *RefreshHelper) refreshSubCommitsWithLimit(captured capturedSubCommit } self.onUIThreadUnlessRepoChanged(env, func() { self.c.Model().SubCommits = commits + self.c.Contexts().SubCommits.SetLoadedCommitLimit(limit) self.RefreshAuthors(commits) }) diff --git a/pkg/gui/controllers/helpers/sub_commits_helper.go b/pkg/gui/controllers/helpers/sub_commits_helper.go index e3d02dd8c..23bb03f55 100644 --- a/pkg/gui/controllers/helpers/sub_commits_helper.go +++ b/pkg/gui/controllers/helpers/sub_commits_helper.go @@ -60,6 +60,7 @@ func (self *SubCommitsHelper) ViewSubCommits(opts ViewSubCommitsOpts) error { subCommitsContext.SetRef(opts.Ref) subCommitsContext.SetRefToShowDivergenceFrom(opts.RefToShowDivergenceFrom) subCommitsContext.SetLimitCommits(true) + subCommitsContext.SetLoadedCommitLimit(commitLimit) subCommitsContext.SetShowBranchHeads(opts.ShowBranchHeads) subCommitsContext.ClearSearchString() subCommitsContext.GetView().ClearSearch() diff --git a/pkg/gui/controllers/local_commits_controller.go b/pkg/gui/controllers/local_commits_controller.go index bfd54decb..1489e5e71 100644 --- a/pkg/gui/controllers/local_commits_controller.go +++ b/pkg/gui/controllers/local_commits_controller.go @@ -18,19 +18,22 @@ import ( "github.com/stefanhaller/git-todo-parser/todo" ) -// after selecting the 200th commit, we'll load in all the rest -const COMMIT_THRESHOLD = 200 +// If the selection gets this close to the end of the commits that we loaded, +// we load all the rest +const loadAllCommitsMargin = 100 type canLoadAllCommits interface { GetSelectedLineIdx() int GetLimitCommits() bool SetLimitCommits(value bool) + GetLoadedCommitLimit() int } // If we loaded only the first commits of a list, and the selection gets close to // the end of them, load all of them. func loadAllCommitsIfSelectionIsNearEnd(c *ControllerCommon, context canLoadAllCommits, scope types.RefreshableView) { - if context.GetSelectedLineIdx() > COMMIT_THRESHOLD && context.GetLimitCommits() { + limit := context.GetLoadedCommitLimit() + if context.GetLimitCommits() && limit > 0 && context.GetSelectedLineIdx() > limit-loadAllCommitsMargin { context.SetLimitCommits(false) c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{scope}}) }