1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-07-07 01:09:45 +02:00

Toggle only added/deleted lines in patch building view

This improves the experience when selecting a hunk generously with the mouse, by
dragging over it including some context lines above and below. Previously we
would consider the "moving end" of the selection range for whether things need
to be added or removed, but this doesn't make sense if it's a context line. Now
we consider the first actual change line that is included in the range.
This commit is contained in:
Stefan Haller
2025-07-03 18:24:04 +02:00
parent ef1a141347
commit ce9fbe58b2
3 changed files with 30 additions and 18 deletions

View File

@ -124,14 +124,6 @@ func (p *PatchBuilder) RemoveFile(filename string) error {
return nil return nil
} }
func getIndicesForRange(first, last int) []int {
indices := []int{}
for i := first; i <= last; i++ {
indices = append(indices, i)
}
return indices
}
func (p *PatchBuilder) getFileInfo(filename string) (*fileInfo, error) { func (p *PatchBuilder) getFileInfo(filename string) (*fileInfo, error) {
info, ok := p.fileInfoMap[filename] info, ok := p.fileInfoMap[filename]
if ok { if ok {
@ -152,24 +144,24 @@ func (p *PatchBuilder) getFileInfo(filename string) (*fileInfo, error) {
return info, nil return info, nil
} }
func (p *PatchBuilder) AddFileLineRange(filename string, firstLineIdx, lastLineIdx int) error { func (p *PatchBuilder) AddFileLineRange(filename string, lineIndices []int) error {
info, err := p.getFileInfo(filename) info, err := p.getFileInfo(filename)
if err != nil { if err != nil {
return err return err
} }
info.mode = PART info.mode = PART
info.includedLineIndices = lo.Union(info.includedLineIndices, getIndicesForRange(firstLineIdx, lastLineIdx)) info.includedLineIndices = lo.Union(info.includedLineIndices, lineIndices)
return nil return nil
} }
func (p *PatchBuilder) RemoveFileLineRange(filename string, firstLineIdx, lastLineIdx int) error { func (p *PatchBuilder) RemoveFileLineRange(filename string, lineIndices []int) error {
info, err := p.getFileInfo(filename) info, err := p.getFileInfo(filename)
if err != nil { if err != nil {
return err return err
} }
info.mode = PART info.mode = PART
info.includedLineIndices, _ = lo.Difference(info.includedLineIndices, getIndicesForRange(firstLineIdx, lastLineIdx)) info.includedLineIndices, _ = lo.Difference(info.includedLineIndices, lineIndices)
if len(info.includedLineIndices) == 0 { if len(info.includedLineIndices) == 0 {
p.removeFile(info) p.removeFile(info)
} }

View File

@ -126,7 +126,6 @@ func (self *PatchBuildingController) toggleSelection() error {
self.context().GetMutex().Lock() self.context().GetMutex().Lock()
defer self.context().GetMutex().Unlock() defer self.context().GetMutex().Unlock()
toggleFunc := self.c.Git().Patch.PatchBuilder.AddFileLineRange
filename := self.c.Contexts().CommitFiles.GetSelectedPath() filename := self.c.Contexts().CommitFiles.GetSelectedPath()
if filename == "" { if filename == "" {
return nil return nil
@ -134,19 +133,26 @@ func (self *PatchBuildingController) toggleSelection() error {
state := self.context().GetState() state := self.context().GetState()
// Get added/deleted lines in the selected patch range
lineIndicesToToggle := state.ChangeLinesInSelectedPatchRange()
if len(lineIndicesToToggle) == 0 {
// Only context lines or header lines selected, so nothing to do
return nil
}
includedLineIndices, err := self.c.Git().Patch.PatchBuilder.GetFileIncLineIndices(filename) includedLineIndices, err := self.c.Git().Patch.PatchBuilder.GetFileIncLineIndices(filename)
if err != nil { if err != nil {
return err return err
} }
currentLineIsStaged := lo.Contains(includedLineIndices, state.GetSelectedPatchLineIdx())
if currentLineIsStaged { toggleFunc := self.c.Git().Patch.PatchBuilder.AddFileLineRange
firstSelectedChangeLineIsStaged := lo.Contains(includedLineIndices, lineIndicesToToggle[0])
if firstSelectedChangeLineIsStaged {
toggleFunc = self.c.Git().Patch.PatchBuilder.RemoveFileLineRange toggleFunc = self.c.Git().Patch.PatchBuilder.RemoveFileLineRange
} }
// add range of lines to those set for the file // add range of lines to those set for the file
firstLineIdx, lastLineIdx := state.SelectedPatchRange() if err := toggleFunc(filename, lineIndicesToToggle); err != nil {
if err := toggleFunc(filename, firstLineIdx, lastLineIdx); err != nil {
// might actually want to return an error here // might actually want to return an error here
self.c.Log.Error(err) self.c.Log.Error(err)
} }

View File

@ -282,6 +282,20 @@ func (s *State) SelectedPatchRange() (int, int) {
return s.patchLineIndices[start], s.patchLineIndices[end] return s.patchLineIndices[start], s.patchLineIndices[end]
} }
// Returns the line indices of the selected patch range that are changes (i.e. additions or deletions)
func (s *State) ChangeLinesInSelectedPatchRange() []int {
viewStart, viewEnd := s.SelectedViewRange()
patchStart, patchEnd := s.patchLineIndices[viewStart], s.patchLineIndices[viewEnd]
lines := s.patch.Lines()
indices := []int{}
for i := patchStart; i <= patchEnd; i++ {
if lines[i].IsChange() {
indices = append(indices, i)
}
}
return indices
}
func (s *State) CurrentLineNumber() int { func (s *State) CurrentLineNumber() int {
return s.patch.LineNumberOfLine(s.patchLineIndices[s.selectedLineIdx]) return s.patch.LineNumberOfLine(s.patchLineIndices[s.selectedLineIdx])
} }