mirror of
https://github.com/jesseduffield/lazygit.git
synced 2026-09-25 08:50:21 -04:00
Reserve the width that all commits need for a commit list's columns
During an interactive rebase, scrolling down far enough that the pending todos leave the screen makes the author and subject of every commit jump to the left; scrolling back up makes them jump back. During a bisect the column that holds "<-- current" and "?" comes and goes the same way, and in the expanded commits panel the date column is only as wide as gui.shortTimeFormat while nothing but today's commits is on screen. A column is as wide as the widest string in it, and a column whose strings are all empty is dropped altogether. The commits and sub-commits panels render only the lines that are on screen, so those widths come from the visible lines alone and follow the scroll position. Pad the hash, bisect, action and date cell of every line to the width that all the commits in the list need. A padded cell is no longer empty, so its column is never dropped, and the column is already as wide as the whole list needs, so its width no longer depends on what is visible. The date column is the exception. Formatting the date of every commit on every render costs too much, so it measures the oldest commit only. That covers the conventional time formats; getReservedColumnWidths says what it misses, and why it can never reserve width that no commit asks for. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
101424322a
commit
410d7209b1
@@ -177,6 +177,10 @@ func GetCommitListDisplayStrings(
|
||||
(hasRebaseUpdateRefsConfig || b.CommitHash != commits[0].Hash())
|
||||
}))
|
||||
|
||||
reservedWidths := getReservedColumnWidths(
|
||||
commits, common.UserConfig().Gui.CommitHashLength, fullDescription,
|
||||
timeFormat, shortTimeFormat, now, bisectInfo, bisectBounds)
|
||||
|
||||
lines := make([][]string, 0, len(filteredCommits))
|
||||
var bisectStatus BisectStatus
|
||||
willBeRebased := markedBaseCommit == ""
|
||||
@@ -204,11 +208,64 @@ func GetCommitListDisplayStrings(
|
||||
fullDescription,
|
||||
bisectStatus,
|
||||
bisectInfo,
|
||||
reservedWidths,
|
||||
))
|
||||
}
|
||||
return lines
|
||||
}
|
||||
|
||||
// The width of a column is the width of the widest string in it, and a column
|
||||
// whose strings are all empty is left out entirely. The panels that show a
|
||||
// commit list hand over only the lines that are on screen, so several columns
|
||||
// would change their width, or come and go, as the user scrolls. These are the
|
||||
// widths those columns need for all the commits in the list.
|
||||
type reservedColumnWidths struct {
|
||||
hash int
|
||||
bisect int
|
||||
description int
|
||||
action int
|
||||
}
|
||||
|
||||
// precondition: commits is not empty
|
||||
func getReservedColumnWidths(
|
||||
commits []*models.Commit,
|
||||
hashLength int,
|
||||
fullDescription bool,
|
||||
timeFormat string,
|
||||
shortTimeFormat string,
|
||||
now time.Time,
|
||||
bisectInfo *git_commands.BisectInfo,
|
||||
bisectBounds *bisectBounds,
|
||||
) reservedColumnWidths {
|
||||
result := reservedColumnWidths{}
|
||||
|
||||
for i, commit := range commits {
|
||||
result.hash = max(result.hash, utils.StringWidth(getHashText(commit, hashLength)))
|
||||
if commit.IsTODO() {
|
||||
result.action = max(result.action, utils.StringWidth(getActionText(commit)))
|
||||
}
|
||||
bisectStatus := getBisectStatus(i, commit.Hash(), bisectInfo, bisectBounds)
|
||||
result.bisect = max(result.bisect,
|
||||
utils.StringWidth(getBisectStatusText(bisectStatus, bisectInfo)))
|
||||
}
|
||||
|
||||
if fullDescription {
|
||||
// Formatting the date of every commit on every render would be too
|
||||
// expensive, so measure the oldest one only. It is the one least likely
|
||||
// to be from today, and so the one most likely to be shown in the long
|
||||
// time format; with a conventional time format that one is both wider
|
||||
// than the short format and the same width for every date, which makes
|
||||
// it the width the whole column needs. An unconventional format can
|
||||
// break either of those assumptions, and then some of the column's
|
||||
// width still comes and goes; it can never reserve more width than one
|
||||
// of the commits asks for, though.
|
||||
result.description = utils.StringWidth(utils.UnixToDateSmart(
|
||||
now, commits[len(commits)-1].UnixTimestamp, timeFormat, shortTimeFormat))
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func getbisectBounds(commits []*models.Commit, bisectInfo *git_commands.BisectInfo) *bisectBounds {
|
||||
if !bisectInfo.Bisecting() {
|
||||
return nil
|
||||
@@ -376,6 +433,7 @@ func displayCommit(
|
||||
fullDescription bool,
|
||||
bisectStatus BisectStatus,
|
||||
bisectInfo *git_commands.BisectInfo,
|
||||
reservedWidths reservedColumnWidths,
|
||||
) []string {
|
||||
bisectString := ""
|
||||
if bisectText := getBisectStatusText(bisectStatus, bisectInfo); bisectText != "" {
|
||||
@@ -457,10 +515,10 @@ func displayCommit(
|
||||
cols = append(
|
||||
cols,
|
||||
divergenceString,
|
||||
hashString,
|
||||
bisectString,
|
||||
descriptionString,
|
||||
actionString,
|
||||
utils.WithPadding(hashString, reservedWidths.hash, utils.AlignLeft),
|
||||
utils.WithPadding(bisectString, reservedWidths.bisect, utils.AlignLeft),
|
||||
utils.WithPadding(descriptionString, reservedWidths.description, utils.AlignLeft),
|
||||
utils.WithPadding(actionString, reservedWidths.action, utils.AlignLeft),
|
||||
author,
|
||||
graphLine+mark+tagString+theme.DefaultTextColor.Sprint(name),
|
||||
)
|
||||
|
||||
@@ -274,16 +274,10 @@ func TestGetCommitListDisplayStrings(t *testing.T) {
|
||||
bisectInfo: git_commands.NewNullBisectInfo(),
|
||||
cherryPickedCommitHashSet: set.New[string](),
|
||||
now: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC),
|
||||
/* EXPECTED:
|
||||
expected: formatExpected(`
|
||||
hash4 ○ commit4
|
||||
hash5 ○ commit5
|
||||
`),
|
||||
ACTUAL: */
|
||||
expected: formatExpected(`
|
||||
hash4 ○ commit4
|
||||
hash5 ○ commit5
|
||||
`),
|
||||
},
|
||||
{
|
||||
testName: "only showing TODO commits",
|
||||
@@ -358,16 +352,10 @@ func TestGetCommitListDisplayStrings(t *testing.T) {
|
||||
bisectInfo: git_commands.NewNullBisectInfo(),
|
||||
cherryPickedCommitHashSet: set.New[string](),
|
||||
now: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC),
|
||||
/* EXPECTED:
|
||||
expected: formatExpected(`
|
||||
update-ref branch1
|
||||
update-ref branch2
|
||||
`),
|
||||
ACTUAL: */
|
||||
expected: formatExpected(`
|
||||
update-ref branch1
|
||||
update-ref branch2
|
||||
`),
|
||||
},
|
||||
{
|
||||
testName: "graph in divergence view - all commits visible",
|
||||
@@ -576,14 +564,9 @@ func TestGetCommitListDisplayStrings(t *testing.T) {
|
||||
bisectInfo: git_commands.NewNullBisectInfo(),
|
||||
cherryPickedCommitHashSet: set.New[string](),
|
||||
now: time.Date(2020, 1, 1, 5, 3, 4, 0, time.UTC),
|
||||
/* EXPECTED:
|
||||
expected: formatExpected(`
|
||||
hash1 2:03AM Jesse Duffield commit1
|
||||
`),
|
||||
ACTUAL: */
|
||||
expected: formatExpected(`
|
||||
hash1 2:03AM Jesse Duffield commit1
|
||||
`),
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user