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 <noreply@anthropic.com>
This commit is contained in:
Stefan Haller
2026-10-31 11:27:58 +01:00
co-authored by Claude Opus 5.5
parent 0d41e696ac
commit ee07abe508
5 changed files with 38 additions and 7 deletions
+12
View File
@@ -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
}
+13 -2
View File
@@ -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()
@@ -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)
})
@@ -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()
@@ -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}})
}