From f214ba90cc631889dffdf31fccc579379605e251 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Tue, 1 Sep 2026 19:01:23 +0200 Subject: [PATCH] Ask a parsed patch which of its lines a selection covers Staging a selection walks the file's diff to find the lines the user pointed at, by where each of them sits in the file. The next commit needs the same answer for a single row, so pull the walk out of the staging path before there are two copies of it. Co-authored-by: Claude Opus 5 (1M context) --- .../controllers/working_tree_diff_actions.go | 65 +++++++++++-------- 1 file changed, 37 insertions(+), 28 deletions(-) diff --git a/pkg/gui/controllers/working_tree_diff_actions.go b/pkg/gui/controllers/working_tree_diff_actions.go index 75b5f97fc..233ecec13 100644 --- a/pkg/gui/controllers/working_tree_diff_actions.go +++ b/pkg/gui/controllers/working_tree_diff_actions.go @@ -198,34 +198,7 @@ func (self *WorkingTreeDiffActions) applyDiffLines( ) (bool, error) { parsedPatch := patch.Parse(self.c.Git().WorkingTree.WorktreeFileDiff(file, git_commands.DiffModePlain, sourceCached)) - type changeLine struct { - lineNumber int - isDeletion bool - } - selected := set.New[changeLine]() - for _, info := range infos { - if info.Type == types.DiffLineDeleted { - selected.Add(changeLine{info.OldLine, true}) - } else { - selected.Add(changeLine{info.NewLine, false}) - } - } - - var patchLineIndices []int - for idx, line := range parsedPatch.Lines() { - var key changeLine - switch { - case line.IsAddition(): - key = changeLine{parsedPatch.LineNumberOfLine(idx), false} - case line.IsDeletion(): - key = changeLine{parsedPatch.OldLineNumberOfLine(idx), true} - default: - continue - } - if selected.Includes(key) { - patchLineIndices = append(patchLineIndices, idx) - } - } + patchLineIndices := changeLineIndices(parsedPatch, infos) changesLeft := len(patchLineIndices) < changeLineCount(parsedPatch) @@ -256,6 +229,42 @@ func (self *WorkingTreeDiffActions) applyDiffLines( return changesLeft, self.c.Git().Patch.ApplyPatch(patchToApply, opts) } +// changeLineIndices says which lines of a parsed patch the given diff rows are, as the +// indices a patch is built in terms of. Each row is looked for by where it sits in the +// file: an addition by its place in the new version, a deletion by its place in the +// old one, which is what tells the two halves of a changed line apart. +func changeLineIndices(parsedPatch *patch.Patch, infos []types.DiffLineInfo) []int { + type changeLine struct { + lineNumber int + isDeletion bool + } + selected := set.New[changeLine]() + for _, info := range infos { + if info.Type == types.DiffLineDeleted { + selected.Add(changeLine{info.OldLine, true}) + } else { + selected.Add(changeLine{info.NewLine, false}) + } + } + + var indices []int + for idx, line := range parsedPatch.Lines() { + var key changeLine + switch { + case line.IsAddition(): + key = changeLine{parsedPatch.LineNumberOfLine(idx), false} + case line.IsDeletion(): + key = changeLine{parsedPatch.OldLineNumberOfLine(idx), true} + default: + continue + } + if selected.Includes(key) { + indices = append(indices, idx) + } + } + return indices +} + // changeLineCount returns how many of a patch's lines are changes rather than context // or header. A selection of the whole diff covers exactly that many. func changeLineCount(p *patch.Patch) int {