1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-07-07 01:09:45 +02:00
Files
lazygit/pkg/gui/controllers/patch_building_controller.go
Stefan Haller ce9fbe58b2 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.
2025-07-04 10:14:35 +02:00

180 lines
4.7 KiB
Go

package controllers
import (
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/samber/lo"
)
type PatchBuildingController struct {
baseController
c *ControllerCommon
}
var _ types.IController = &PatchBuildingController{}
func NewPatchBuildingController(
c *ControllerCommon,
) *PatchBuildingController {
return &PatchBuildingController{
baseController: baseController{},
c: c,
}
}
func (self *PatchBuildingController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
return []*types.Binding{
{
Key: opts.GetKey(opts.Config.Universal.OpenFile),
Handler: self.OpenFile,
Description: self.c.Tr.OpenFile,
Tooltip: self.c.Tr.OpenFileTooltip,
},
{
Key: opts.GetKey(opts.Config.Universal.Edit),
Handler: self.EditFile,
Description: self.c.Tr.EditFile,
Tooltip: self.c.Tr.EditFileTooltip,
},
{
Key: opts.GetKey(opts.Config.Universal.Select),
Handler: self.ToggleSelectionAndRefresh,
Description: self.c.Tr.ToggleSelectionForPatch,
DisplayOnScreen: true,
},
{
Key: opts.GetKey(opts.Config.Universal.Return),
Handler: self.Escape,
Description: self.c.Tr.ExitCustomPatchBuilder,
},
}
}
func (self *PatchBuildingController) Context() types.Context {
return self.c.Contexts().CustomPatchBuilder
}
func (self *PatchBuildingController) context() types.IPatchExplorerContext {
return self.c.Contexts().CustomPatchBuilder
}
func (self *PatchBuildingController) GetMouseKeybindings(opts types.KeybindingsOpts) []*gocui.ViewMouseBinding {
return []*gocui.ViewMouseBinding{}
}
func (self *PatchBuildingController) GetOnFocus() func(types.OnFocusOpts) {
return func(opts types.OnFocusOpts) {
// no need to change wrap on the secondary view because it can't be interacted with
self.c.Views().PatchBuilding.Wrap = self.c.UserConfig().Gui.WrapLinesInStagingView
self.c.Helpers().PatchBuilding.RefreshPatchBuildingPanel(opts)
}
}
func (self *PatchBuildingController) GetOnFocusLost() func(types.OnFocusLostOpts) {
return func(opts types.OnFocusLostOpts) {
self.context().SetState(nil)
self.c.Views().PatchBuilding.Wrap = true
if self.c.Git().Patch.PatchBuilder.IsEmpty() {
self.c.Git().Patch.PatchBuilder.Reset()
}
}
}
func (self *PatchBuildingController) OpenFile() error {
self.context().GetMutex().Lock()
defer self.context().GetMutex().Unlock()
path := self.c.Contexts().CommitFiles.GetSelectedPath()
if path == "" {
return nil
}
return self.c.Helpers().Files.OpenFile(path)
}
func (self *PatchBuildingController) EditFile() error {
self.context().GetMutex().Lock()
defer self.context().GetMutex().Unlock()
path := self.c.Contexts().CommitFiles.GetSelectedPath()
if path == "" {
return nil
}
lineNumber := self.context().GetState().CurrentLineNumber()
lineNumber = self.c.Helpers().Diff.AdjustLineNumber(path, lineNumber, self.context().GetViewName())
return self.c.Helpers().Files.EditFileAtLine(path, lineNumber)
}
func (self *PatchBuildingController) ToggleSelectionAndRefresh() error {
if err := self.toggleSelection(); err != nil {
return err
}
self.c.Refresh(types.RefreshOptions{
Scope: []types.RefreshableView{types.PATCH_BUILDING, types.COMMIT_FILES},
})
return nil
}
func (self *PatchBuildingController) toggleSelection() error {
self.context().GetMutex().Lock()
defer self.context().GetMutex().Unlock()
filename := self.c.Contexts().CommitFiles.GetSelectedPath()
if filename == "" {
return nil
}
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)
if err != nil {
return err
}
toggleFunc := self.c.Git().Patch.PatchBuilder.AddFileLineRange
firstSelectedChangeLineIsStaged := lo.Contains(includedLineIndices, lineIndicesToToggle[0])
if firstSelectedChangeLineIsStaged {
toggleFunc = self.c.Git().Patch.PatchBuilder.RemoveFileLineRange
}
// add range of lines to those set for the file
if err := toggleFunc(filename, lineIndicesToToggle); err != nil {
// might actually want to return an error here
self.c.Log.Error(err)
}
if state.SelectingRange() {
state.SetLineSelectMode()
}
return nil
}
func (self *PatchBuildingController) Escape() error {
context := self.c.Contexts().CustomPatchBuilder
state := context.GetState()
if state.SelectingRange() || state.SelectingHunk() {
state.SetLineSelectMode()
self.c.PostRefreshUpdate(context)
return nil
}
self.c.Helpers().PatchBuilding.Escape()
return nil
}