diff --git a/pkg/gui/controllers/helpers/diff_line_helper.go b/pkg/gui/controllers/helpers/diff_line_helper.go index 0da3f858d..a8a8f5e53 100644 --- a/pkg/gui/controllers/helpers/diff_line_helper.go +++ b/pkg/gui/controllers/helpers/diff_line_helper.go @@ -5,6 +5,7 @@ import ( "github.com/jesseduffield/lazygit/pkg/gocui" "github.com/jesseduffield/lazygit/pkg/gui/types" + "github.com/samber/lo" ) type DiffLineHelper struct { @@ -134,10 +135,13 @@ func (self *DiffLineHelper) resolveDiffLines(contents []gocui.DiffLineContent) [ // side-by-side row leads with the deletion whose addition was what got remembered // under a unified one. func (self *DiffLineHelper) resolveDiffLineIdentities(contents []gocui.DiffLineContent) [][]types.DiffLineInfo { + toDiffLineInfo := self.diffLineInfoConverter() identities := make([][]types.DiffLineInfo, len(contents)) for i, parsed := range parseDiffLineIdentities(contents) { if len(parsed) > 0 { - identities[i] = self.diffLineInfos(parsed) + identities[i] = lo.Map(parsed, func(line parsedDiffLine, _ int) types.DiffLineInfo { + return toDiffLineInfo(line) + }) } } return identities @@ -159,19 +163,40 @@ func (self *DiffLineHelper) diffLineInfos(parsed []parsedDiffLine) []types.DiffL return infos } +// diffLineInfoConverter returns diffLineInfo as a function, for the callers that turn +// every line of a diff into an identity (see diffLineInfoConverterIn). +func (self *DiffLineHelper) diffLineInfoConverter() func(parsedDiffLine) types.DiffLineInfo { + return diffLineInfoConverterIn(self.c.Git().RepoPaths.WorktreePath()) +} + // diffLineInfoIn is diffLineInfo against a given worktree, for the callers that can't // ask which repo we are in where they run: a repo switch replaces it, so only the UI // thread may read it. func diffLineInfoIn(worktreePath string, parsed parsedDiffLine) types.DiffLineInfo { - path := parsed.Path - if !filepath.IsAbs(path) { - path = filepath.Join(worktreePath, path) - } + return diffLineInfoConverterIn(worktreePath)(parsed) +} - return types.DiffLineInfo{ - Path: path, - Type: parsed.Type, - NewLine: parsed.NewLine, - OldLine: parsed.OldLine, +// diffLineInfoConverterIn returns diffLineInfoIn for the given worktree as a function, +// for the callers that turn every line of a diff into an identity. The lines of a diff +// come file by file, so the path of a line is nearly always the path of the line +// before it. The function makes a path absolute only when it differs from the one +// before. +func diffLineInfoConverterIn(worktreePath string) func(parsedDiffLine) types.DiffLineInfo { + path, absolutePath := "", "" + return func(parsed parsedDiffLine) types.DiffLineInfo { + if absolutePath == "" || parsed.Path != path { + path = parsed.Path + absolutePath = parsed.Path + if !filepath.IsAbs(absolutePath) { + absolutePath = filepath.Join(worktreePath, absolutePath) + } + } + + return types.DiffLineInfo{ + Path: absolutePath, + Type: parsed.Type, + NewLine: parsed.NewLine, + OldLine: parsed.OldLine, + } } } diff --git a/pkg/gui/controllers/helpers/diff_line_helper_test.go b/pkg/gui/controllers/helpers/diff_line_helper_test.go new file mode 100644 index 000000000..057173845 --- /dev/null +++ b/pkg/gui/controllers/helpers/diff_line_helper_test.go @@ -0,0 +1,34 @@ +package helpers + +import ( + "path/filepath" + "testing" + + "github.com/jesseduffield/lazygit/pkg/gui/types" + "github.com/stretchr/testify/assert" +) + +func TestDiffLineInfoConverterIn(t *testing.T) { + worktreePath := t.TempDir() + absolutePath := filepath.Join(t.TempDir(), "d.txt") + toDiffLineInfo := diffLineInfoConverterIn(worktreePath) + + lines := []parsedDiffLine{ + {Path: "a.txt", Type: types.DiffLineAdded, NewLine: 1}, + {Path: "a.txt", Type: types.DiffLineDeleted, NewLine: 2, OldLine: 1}, + {Path: "dir/b.txt", Type: types.DiffLineContext, NewLine: 3}, + {Path: absolutePath, Type: types.DiffLineAdded, NewLine: 4}, + {Path: "a.txt", Type: types.DiffLineAdded, NewLine: 5}, + } + expected := []types.DiffLineInfo{ + {Path: filepath.Join(worktreePath, "a.txt"), Type: types.DiffLineAdded, NewLine: 1}, + {Path: filepath.Join(worktreePath, "a.txt"), Type: types.DiffLineDeleted, NewLine: 2, OldLine: 1}, + {Path: filepath.Join(worktreePath, "dir", "b.txt"), Type: types.DiffLineContext, NewLine: 3}, + {Path: absolutePath, Type: types.DiffLineAdded, NewLine: 4}, + {Path: filepath.Join(worktreePath, "a.txt"), Type: types.DiffLineAdded, NewLine: 5}, + } + + for i, line := range lines { + assert.Equal(t, expected[i], toDiffLineInfo(line), "line %d", i) + } +} diff --git a/pkg/gui/controllers/helpers/diff_line_plain_text.go b/pkg/gui/controllers/helpers/diff_line_plain_text.go index 6b53d94af..f62144ec1 100644 --- a/pkg/gui/controllers/helpers/diff_line_plain_text.go +++ b/pkg/gui/controllers/helpers/diff_line_plain_text.go @@ -72,12 +72,13 @@ func (self *DiffLineHelper) PlainDiffOfSelection( } diffLines := strings.Split(strings.TrimSuffix(plainDiff(relPaths), "\n"), "\n") + toDiffLineInfo := diffLineInfoConverterIn(worktreePath) runs := map[string][2]int{} for i, parsed := range parseAllDiffLinesFromBuffer(diffLines) { if !parsed.ok { continue } - info := diffLineInfoIn(worktreePath, parsed.parsed) + info := toDiffLineInfo(parsed.parsed) selected := selection[info.Path] if selected == nil || !selected.covers(info) { continue diff --git a/pkg/gui/controllers/helpers/diff_line_queries.go b/pkg/gui/controllers/helpers/diff_line_queries.go index ce6fba60a..c8e59bbb4 100644 --- a/pkg/gui/controllers/helpers/diff_line_queries.go +++ b/pkg/gui/controllers/helpers/diff_line_queries.go @@ -47,13 +47,14 @@ func (self *DiffLineHelper) DiffLinesInBufferRange(view *gocui.View, first int, func (self *DiffLineHelper) ChangeLineOrdinals( diff string, infos []types.DiffLineInfo, ) map[string][]int { + toDiffLineInfo := self.diffLineInfoConverter() ordinals := map[patchLine]int{} counts := map[string]int{} for _, parsed := range parseAllDiffLinesFromBuffer(strings.Split(diff, "\n")) { if !parsed.ok { continue } - info := self.diffLineInfo(parsed.parsed) + info := toDiffLineInfo(parsed.parsed) if !info.IsChange() { continue }