mirror of
https://github.com/jesseduffield/lazygit.git
synced 2026-11-06 13:00:59 -04:00
Leave out the text of the rows of a rendering that states its lines
Under a diff renderer that states which diff line each row shows, such as delta, the queries about the lines of the main view read the rows by those records alone. Still, they took the text of every row as well, and for a diff of 300,000 lines this was most of the time each of them took. Moving the selection by change block runs two of them for every key press. Take the records of the rows first, and their text only if no row states a diff line. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
3f64902a11
commit
dc4fee296c
@@ -2158,6 +2158,20 @@ func (v *View) DiffLineContents() []DiffLineContent {
|
||||
return diffLineContentsFrom(v.buf, 0)
|
||||
}
|
||||
|
||||
// DiffLineMetadata is DiffLineContents without the text of the lines, for a reader
|
||||
// that only needs the records. Taking the text is most of the cost of
|
||||
// DiffLineContents.
|
||||
func (v *View) DiffLineMetadata() [][]string {
|
||||
v.writeMutex.Lock()
|
||||
defer v.writeMutex.Unlock()
|
||||
|
||||
metadata := make([][]string, len(v.buf.lines))
|
||||
for i := range v.buf.lines {
|
||||
metadata[i] = v.buf.lines[i].diffLineMetadata()
|
||||
}
|
||||
return metadata
|
||||
}
|
||||
|
||||
// OffscreenDiffLineContents is DiffLineContents for the content of a re-render in
|
||||
// progress (see BeginOffscreenRender). A reader deciding where the new content
|
||||
// should be shown has to work from this: it has to answer before the swap, since
|
||||
|
||||
@@ -354,6 +354,21 @@ func TestDiffLineContentsOfARewrittenLine(t *testing.T) {
|
||||
}, v.DiffLineContents())
|
||||
}
|
||||
|
||||
func TestDiffLineMetadata(t *testing.T) {
|
||||
v := NewView("name", 0, 0, 80, 10, OutputNormal)
|
||||
v.writeString(strings.Join([]string{
|
||||
osc1717("1;d;2;2;foo.txt") + "old2 " + osc1717("1;a;2;;foo.txt") + "new2",
|
||||
"@@ a hunk header, which carries no record @@",
|
||||
osc1717("1;c;3;;foo.txt") + "line3",
|
||||
}, "\n"))
|
||||
|
||||
assert.Equal(t, [][]string{
|
||||
{"1;d;2;2;foo.txt", "1;a;2;;foo.txt"},
|
||||
nil,
|
||||
{"1;c;3;;foo.txt"},
|
||||
}, v.DiffLineMetadata())
|
||||
}
|
||||
|
||||
func TestDiffLineContentsSwallowsHandshake(t *testing.T) {
|
||||
v := NewView("name", 0, 0, 80, 10, OutputNormal)
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ func (self *DiffLineHelper) diffLineIdentitiesAt(
|
||||
return nil, false
|
||||
}
|
||||
|
||||
contents := view.DiffLineContents()
|
||||
contents := diffLineContents(view)
|
||||
if bufferLineIdx >= len(contents) {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/patch"
|
||||
"github.com/jesseduffield/lazygit/pkg/gocui"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
|
||||
// diffFilePrefix marks the start of a file's section in a (possibly multi-file)
|
||||
@@ -125,6 +126,20 @@ func renderingStatesDiffLines(contents []gocui.DiffLineContent) bool {
|
||||
})
|
||||
}
|
||||
|
||||
// diffLineContents returns the contents of view's rows, as the queries about the lines
|
||||
// of a diff read them. A rendering that states which diff line each row shows is read
|
||||
// by those records alone (see renderingStatesDiffLines), so the text of its rows is
|
||||
// left out then. Taking the text is most of the cost of reading a long diff.
|
||||
func diffLineContents(view *gocui.View) []gocui.DiffLineContent {
|
||||
contents := lo.Map(view.DiffLineMetadata(), func(metadata []string, _ int) gocui.DiffLineContent {
|
||||
return gocui.DiffLineContent{Metadata: metadata}
|
||||
})
|
||||
if renderingStatesDiffLines(contents) {
|
||||
return contents
|
||||
}
|
||||
return view.DiffLineContents()
|
||||
}
|
||||
|
||||
// parseDiffLineRecords parses the records a row carries, left to right, leaving out
|
||||
// the ones we don't understand. A row carries more than one when the rendering puts
|
||||
// two diff lines on it, as a side-by-side row does with a deletion and the addition
|
||||
|
||||
@@ -544,3 +544,22 @@ func TestParseDiffLineIdentities(t *testing.T) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestDiffLineContentsLeaveOutTheTextOfARenderingWithRecords(t *testing.T) {
|
||||
record := func(payload string) string { return "\x1b]1717;" + payload + "\x1b\\" }
|
||||
|
||||
rendering := gocui.NewView("rendering", 0, 0, 80, 10, gocui.OutputNormal)
|
||||
rendering.WriteString(record("1;a;1;;foo.txt") + "added\n" + "a divider\n")
|
||||
assert.Equal(t, []gocui.DiffLineContent{
|
||||
{Metadata: []string{"1;a;1;;foo.txt"}},
|
||||
{},
|
||||
}, diffLineContents(rendering))
|
||||
|
||||
// A diff without records is read by its text, so it keeps it.
|
||||
diff := gocui.NewView("diff", 0, 0, 80, 10, gocui.OutputNormal)
|
||||
diff.WriteString("diff --git a/foo.txt b/foo.txt\n+added\n")
|
||||
assert.Equal(t, []gocui.DiffLineContent{
|
||||
{Text: "diff --git a/foo.txt b/foo.txt"},
|
||||
{Text: "+added"},
|
||||
}, diffLineContents(diff))
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ import (
|
||||
// beside the addition replacing it — and all of them are reported: what the user
|
||||
// pointed at is the row, so everything on it is selected.
|
||||
func (self *DiffLineHelper) DiffLinesInBufferRange(view *gocui.View, first int, last int) []types.DiffLineInfo {
|
||||
identities := self.resolveDiffLineIdentities(view.DiffLineContents())
|
||||
identities := self.resolveDiffLineIdentities(diffLineContents(view))
|
||||
|
||||
infos := []types.DiffLineInfo{}
|
||||
for bufferLine := first; bufferLine <= min(last, len(identities)-1); bufferLine++ {
|
||||
@@ -136,7 +136,7 @@ func (self *DiffLineHelper) ChangeLinesInBufferRange(view *gocui.View, first int
|
||||
// header, or a row whose identity couldn't be recovered. Those are the rows a
|
||||
// selection is anchored on and navigation moves between.
|
||||
func (self *DiffLineHelper) changeLines(view *gocui.View) []bool {
|
||||
resolved := self.resolveDiffLines(view.DiffLineContents())
|
||||
resolved := self.resolveDiffLines(diffLineContents(view))
|
||||
isChange := make([]bool, len(resolved))
|
||||
for i, r := range resolved {
|
||||
isChange[i] = r.ok && r.info.IsChange()
|
||||
@@ -244,7 +244,7 @@ func (self *DiffLineHelper) IsSingleHunkForWholeFile(view *gocui.View, changeVie
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
resolved := self.resolveDiffLines(view.DiffLineContents())
|
||||
resolved := self.resolveDiffLines(diffLineContents(view))
|
||||
if anchor >= len(resolved) || !resolved[anchor].ok {
|
||||
return false
|
||||
}
|
||||
@@ -375,7 +375,7 @@ func (self *DiffLineHelper) StartOfFileInDiff(view *gocui.View, path string) (in
|
||||
// was materialized into, so that both halves of a change belong to the same file however
|
||||
// the diff renderer states them.
|
||||
func (self *DiffLineHelper) filePaths(view *gocui.View) []string {
|
||||
resolved := self.resolveDiffLines(view.DiffLineContents())
|
||||
resolved := self.resolveDiffLines(diffLineContents(view))
|
||||
toRepoTerms := self.repoTermsMapper(view)
|
||||
paths := make([]string, len(resolved))
|
||||
for i, row := range resolved {
|
||||
|
||||
@@ -151,7 +151,7 @@ func (self *DiffLineHelper) selectionLine(
|
||||
if len(candidates) == 0 {
|
||||
return anchorViewLine
|
||||
}
|
||||
_, bufferLine := self.nearestSurvivingCandidate(view.DiffLineContents(), candidates)
|
||||
_, bufferLine := self.nearestSurvivingCandidate(diffLineContents(view), candidates)
|
||||
if bufferLine == -1 {
|
||||
return anchorViewLine
|
||||
}
|
||||
@@ -208,7 +208,7 @@ func selectionFarEndViewLine(view *gocui.View) (int, bool, bool) {
|
||||
// findDiffLine returns the view line showing the given diff line in what view is
|
||||
// displaying now, for placing a remembered line once the re-render is on screen.
|
||||
func (self *DiffLineHelper) findDiffLine(view *gocui.View, identity types.DiffLineInfo) (int, bool) {
|
||||
bufferLine, ok := self.patchLineRows(view.DiffLineContents())[patchLineOf(identity)]
|
||||
bufferLine, ok := self.patchLineRows(diffLineContents(view))[patchLineOf(identity)]
|
||||
if !ok {
|
||||
return 0, false
|
||||
}
|
||||
@@ -273,7 +273,7 @@ func (self *DiffLineHelper) restoreDiffLinePositionOnRerender(
|
||||
// place it left behind is the same one that identity used to have.
|
||||
func (self *DiffLineHelper) ChangeLineOrdinal(view *gocui.View, bufferLine int) int {
|
||||
ordinal := 0
|
||||
for i, row := range self.resolveDiffLines(view.DiffLineContents()) {
|
||||
for i, row := range self.resolveDiffLines(diffLineContents(view)) {
|
||||
if i >= bufferLine {
|
||||
break
|
||||
}
|
||||
@@ -421,7 +421,7 @@ func (self *DiffLineHelper) nearbyDiffLines(view *gocui.View, anchorViewLine int
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
resolved := self.resolveDiffLines(view.DiffLineContents())
|
||||
resolved := self.resolveDiffLines(diffLineContents(view))
|
||||
if anchor >= len(resolved) {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -222,7 +222,7 @@ func (self *DiffLineHelper) RefreshInclusionGutter() {
|
||||
return
|
||||
}
|
||||
|
||||
resolved := self.resolveDiffLines(view.DiffLineContents())
|
||||
resolved := self.resolveDiffLines(diffLineContents(view))
|
||||
marks := make([]bool, len(resolved))
|
||||
for i, row := range resolved {
|
||||
if row.ok && row.info.IsChange() {
|
||||
|
||||
Reference in New Issue
Block a user