Skip to content

Commit cbeca72

Browse files
committed
Press enter in main view of files/commitFiles to enter staging/patch-building
This was already possible, but only when a file was selected, and it woudln't always land on the right line when a pager was used. Now it's also possible to do this for directories, and it jumps to the right line. At the moment this is a hack that relies on delta's hyperlinks, so it only works on lines that have hyperlinks (added and context). The implementation is very hacky for other reasons too (e.g. the addition of the weirdly named ClickedViewRealLineIdx to OnFocusOpts).
1 parent f827945 commit cbeca72

File tree

10 files changed

+154
-19
lines changed

10 files changed

+154
-19
lines changed

pkg/commands/patch/patch.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,38 @@ func (self *Patch) LineNumberOfLine(idx int) int {
104104
return hunk.newStart + offset
105105
}
106106

107+
// Takes a line number in the new file and returns the line index in the patch.
108+
// This is the opposite of LineNumberOfLine.
109+
// If the line number is not contained in any of the hunks, it returns the
110+
// closest position.
111+
func (self *Patch) PatchLineForLineNumber(lineNumber int) int {
112+
if len(self.hunks) == 0 {
113+
return len(self.header)
114+
}
115+
116+
for hunkIdx, hunk := range self.hunks {
117+
if lineNumber <= hunk.newStart {
118+
return self.HunkStartIdx(hunkIdx)
119+
}
120+
121+
if lineNumber < hunk.newStart+hunk.newLength() {
122+
lines := hunk.bodyLines
123+
offset := lineNumber - hunk.newStart
124+
for i, line := range lines {
125+
if offset == 0 {
126+
return self.HunkStartIdx(hunkIdx) + i + 1
127+
}
128+
129+
if line.Kind == ADDITION || line.Kind == CONTEXT {
130+
offset--
131+
}
132+
}
133+
}
134+
}
135+
136+
return self.LineCount() - 1
137+
}
138+
107139
// Returns hunk index containing the line at the given patch line index
108140
func (self *Patch) HunkContainingLine(idx int) int {
109141
for hunkIdx, hunk := range self.hunks {

pkg/gui/controllers.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,9 @@ func (gui *Gui) resetHelpersAndControllers() {
5454

5555
gpgHelper := helpers.NewGpgHelper(helperCommon)
5656
viewHelper := helpers.NewViewHelper(helperCommon, gui.State.Contexts)
57+
windowHelper := helpers.NewWindowHelper(helperCommon, viewHelper)
5758
patchBuildingHelper := helpers.NewPatchBuildingHelper(helperCommon)
58-
stagingHelper := helpers.NewStagingHelper(helperCommon)
59+
stagingHelper := helpers.NewStagingHelper(helperCommon, windowHelper)
5960
mergeConflictsHelper := helpers.NewMergeConflictsHelper(helperCommon)
6061
searchHelper := helpers.NewSearchHelper(helperCommon)
6162

@@ -75,7 +76,6 @@ func (gui *Gui) resetHelpersAndControllers() {
7576
rebaseHelper,
7677
)
7778
bisectHelper := helpers.NewBisectHelper(helperCommon)
78-
windowHelper := helpers.NewWindowHelper(helperCommon, viewHelper)
7979
modeHelper := helpers.NewModeHelper(
8080
helperCommon,
8181
diffHelper,

pkg/gui/controllers/commits_files_controller.go

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -470,7 +470,7 @@ func (self *CommitFilesController) currentFromToReverseForPatchBuilding() (strin
470470
}
471471

472472
func (self *CommitFilesController) enter(node *filetree.CommitFileNode) error {
473-
return self.enterCommitFile(node, types.OnFocusOpts{ClickedWindowName: "", ClickedViewLineIdx: -1})
473+
return self.enterCommitFile(node, types.OnFocusOpts{ClickedWindowName: "", ClickedViewLineIdx: -1, ClickedViewRealLineIdx: -1})
474474
}
475475

476476
func (self *CommitFilesController) enterCommitFile(node *filetree.CommitFileNode, opts types.OnFocusOpts) error {
@@ -545,11 +545,35 @@ func (self *CommitFilesController) expandAll() error {
545545

546546
func (self *CommitFilesController) GetOnClickFocusedMainView() func(mainViewName string, clickedLineIdx int) error {
547547
return func(mainViewName string, clickedLineIdx int) error {
548+
clickedFile, line, ok := self.c.Helpers().Staging.GetFileAndLineForClickedDiffLine(mainViewName, clickedLineIdx)
549+
if !ok {
550+
line = -1
551+
}
552+
548553
node := self.getSelectedItem()
549-
if node != nil && node.File != nil {
550-
return self.enterCommitFile(node, types.OnFocusOpts{ClickedWindowName: mainViewName, ClickedViewLineIdx: clickedLineIdx})
554+
if node == nil {
555+
return nil
551556
}
552-
return nil
557+
558+
if !node.IsFile() && ok {
559+
relativePath, err := filepath.Rel(self.c.Git().RepoPaths.RepoPath(), clickedFile)
560+
if err != nil {
561+
return err
562+
}
563+
relativePath = "./" + relativePath
564+
self.context().CommitFileTreeViewModel.ExpandToPath(relativePath)
565+
self.c.PostRefreshUpdate(self.context())
566+
567+
idx, ok := self.context().CommitFileTreeViewModel.GetIndexForPath(relativePath)
568+
if ok {
569+
self.context().SetSelectedLineIdx(idx)
570+
self.context().GetViewTrait().FocusPoint(
571+
self.context().ModelIndexToViewIndex(idx))
572+
node = self.context().GetSelected()
573+
}
574+
}
575+
576+
return self.enterCommitFile(node, types.OnFocusOpts{ClickedWindowName: "main", ClickedViewLineIdx: line, ClickedViewRealLineIdx: line})
553577
}
554578
}
555579

pkg/gui/controllers/files_controller.go

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -325,11 +325,34 @@ func (self *FilesController) GetOnClick() func() error {
325325

326326
func (self *FilesController) GetOnClickFocusedMainView() func(mainViewName string, clickedLineIdx int) error {
327327
return func(mainViewName string, clickedLineIdx int) error {
328-
node := self.getSelectedItem()
329-
if node != nil && node.File != nil {
330-
return self.EnterFile(types.OnFocusOpts{ClickedWindowName: mainViewName, ClickedViewLineIdx: clickedLineIdx})
328+
clickedFile, line, ok := self.c.Helpers().Staging.GetFileAndLineForClickedDiffLine(mainViewName, clickedLineIdx)
329+
if !ok {
330+
line = -1
331331
}
332-
return nil
332+
333+
node := self.context().GetSelected()
334+
if node == nil {
335+
return nil
336+
}
337+
338+
if !node.IsFile() && ok {
339+
relativePath, err := filepath.Rel(self.c.Git().RepoPaths.RepoPath(), clickedFile)
340+
if err != nil {
341+
return err
342+
}
343+
relativePath = "./" + relativePath
344+
self.context().FileTreeViewModel.ExpandToPath(relativePath)
345+
self.c.PostRefreshUpdate(self.context())
346+
347+
idx, ok := self.context().FileTreeViewModel.GetIndexForPath(relativePath)
348+
if ok {
349+
self.context().SetSelectedLineIdx(idx)
350+
self.context().GetViewTrait().FocusPoint(
351+
self.context().ModelIndexToViewIndex(idx))
352+
}
353+
}
354+
355+
return self.EnterFile(types.OnFocusOpts{ClickedWindowName: mainViewName, ClickedViewLineIdx: line, ClickedViewRealLineIdx: line})
333356
}
334357
}
335358

@@ -511,7 +534,7 @@ func (self *FilesController) getSelectedFile() *models.File {
511534
}
512535

513536
func (self *FilesController) enter() error {
514-
return self.EnterFile(types.OnFocusOpts{ClickedWindowName: "", ClickedViewLineIdx: -1})
537+
return self.EnterFile(types.OnFocusOpts{ClickedWindowName: "", ClickedViewLineIdx: -1, ClickedViewRealLineIdx: -1})
515538
}
516539

517540
func (self *FilesController) collapseAll() error {

pkg/gui/controllers/helpers/patch_building_helper.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,10 @@ func (self *PatchBuildingHelper) Reset() error {
5353

5454
func (self *PatchBuildingHelper) RefreshPatchBuildingPanel(opts types.OnFocusOpts) {
5555
selectedLineIdx := -1
56+
selectedRealLineIdx := -1
5657
if opts.ClickedWindowName == "main" {
5758
selectedLineIdx = opts.ClickedViewLineIdx
59+
selectedRealLineIdx = opts.ClickedViewRealLineIdx
5860
}
5961

6062
if !self.c.Git().Patch.PatchBuilder.Active() {
@@ -86,7 +88,7 @@ func (self *PatchBuildingHelper) RefreshPatchBuildingPanel(opts types.OnFocusOpt
8688

8789
oldState := context.GetState()
8890

89-
state := patch_exploring.NewState(diff, selectedLineIdx, context.GetView(), oldState)
91+
state := patch_exploring.NewState(diff, selectedLineIdx, selectedRealLineIdx, context.GetView(), oldState)
9092
context.SetState(state)
9193
if state == nil {
9294
self.Escape()

pkg/gui/controllers/helpers/staging_helper.go

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,26 @@
11
package helpers
22

33
import (
4+
"regexp"
5+
46
"github.com/jesseduffield/lazygit/pkg/commands/models"
57
"github.com/jesseduffield/lazygit/pkg/gui/patch_exploring"
68
"github.com/jesseduffield/lazygit/pkg/gui/types"
9+
"github.com/jesseduffield/lazygit/pkg/utils"
710
)
811

912
type StagingHelper struct {
10-
c *HelperCommon
13+
c *HelperCommon
14+
windowHelper *WindowHelper
1115
}
1216

1317
func NewStagingHelper(
1418
c *HelperCommon,
19+
windowHelper *WindowHelper,
1520
) *StagingHelper {
1621
return &StagingHelper{
17-
c: c,
22+
c: c,
23+
windowHelper: windowHelper,
1824
}
1925
}
2026

@@ -30,12 +36,16 @@ func (self *StagingHelper) RefreshStagingPanel(focusOpts types.OnFocusOpts) {
3036
}
3137

3238
mainSelectedLineIdx := -1
39+
mainSelectedRealLineIdx := -1
3340
secondarySelectedLineIdx := -1
41+
secondarySelectedRealLineIdx := -1
3442
if focusOpts.ClickedViewLineIdx > 0 {
3543
if secondaryFocused {
3644
secondarySelectedLineIdx = focusOpts.ClickedViewLineIdx
45+
secondarySelectedRealLineIdx = focusOpts.ClickedViewRealLineIdx
3746
} else {
3847
mainSelectedLineIdx = focusOpts.ClickedViewLineIdx
48+
mainSelectedRealLineIdx = focusOpts.ClickedViewRealLineIdx
3949
}
4050
}
4151

@@ -63,11 +73,11 @@ func (self *StagingHelper) RefreshStagingPanel(focusOpts types.OnFocusOpts) {
6373
secondaryContext.GetMutex().Lock()
6474

6575
mainContext.SetState(
66-
patch_exploring.NewState(mainDiff, mainSelectedLineIdx, mainContext.GetView(), mainContext.GetState()),
76+
patch_exploring.NewState(mainDiff, mainSelectedLineIdx, mainSelectedRealLineIdx, mainContext.GetView(), mainContext.GetState()),
6777
)
6878

6979
secondaryContext.SetState(
70-
patch_exploring.NewState(secondaryDiff, secondarySelectedLineIdx, secondaryContext.GetView(), secondaryContext.GetState()),
80+
patch_exploring.NewState(secondaryDiff, secondarySelectedLineIdx, secondarySelectedRealLineIdx, secondaryContext.GetView(), secondaryContext.GetState()),
7181
)
7282

7383
mainState := mainContext.GetState()
@@ -124,3 +134,20 @@ func (self *StagingHelper) secondaryStagingFocused() bool {
124134
func (self *StagingHelper) mainStagingFocused() bool {
125135
return self.c.Context().CurrentStatic().GetKey() == self.c.Contexts().Staging.GetKey()
126136
}
137+
138+
func (self *StagingHelper) GetFileAndLineForClickedDiffLine(windowName string, lineIdx int) (string, int, bool) {
139+
v, _ := self.c.GocuiGui().View(self.windowHelper.GetViewNameForWindow(windowName))
140+
hyperlink, ok := v.HyperLinkInLine(lineIdx, "lazygit-edit:")
141+
if !ok {
142+
return "", 0, false
143+
}
144+
145+
re := regexp.MustCompile(`^lazygit-edit://(.+?):(\d+)$`)
146+
matches := re.FindStringSubmatch(hyperlink)
147+
if matches == nil {
148+
return "", 0, false
149+
}
150+
filepath := matches[1]
151+
lineNumber := utils.MustConvertToInt(matches[2])
152+
return filepath, lineNumber, true
153+
}

pkg/gui/controllers/patch_explorer_controller.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,9 +163,15 @@ func (self *PatchExplorerController) GetMouseKeybindings(opts types.KeybindingsO
163163
return self.withRenderAndFocus(self.HandleMouseDown)()
164164
}
165165

166+
_, line, ok := self.c.Helpers().Staging.GetFileAndLineForClickedDiffLine(self.context.GetWindowName(), opts.Y)
167+
if !ok {
168+
line = -1
169+
}
170+
166171
self.c.Context().Push(self.context, types.OnFocusOpts{
167-
ClickedWindowName: self.context.GetWindowName(),
168-
ClickedViewLineIdx: opts.Y,
172+
ClickedWindowName: self.context.GetWindowName(),
173+
ClickedViewLineIdx: opts.Y,
174+
ClickedViewRealLineIdx: line,
169175
})
170176

171177
return nil

pkg/gui/patch_exploring/state.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ const (
3939
HUNK
4040
)
4141

42-
func NewState(diff string, selectedLineIdx int, view *gocui.View, oldState *State) *State {
42+
func NewState(diff string, selectedLineIdx int, selectedRealLineIdx int, view *gocui.View, oldState *State) *State {
4343
if oldState != nil && diff == oldState.diff && selectedLineIdx == -1 {
4444
// if we're here then we can return the old state. If selectedLineIdx was not -1
4545
// then that would mean we were trying to click and potentially drag a range, which
@@ -55,6 +55,10 @@ func NewState(diff string, selectedLineIdx int, view *gocui.View, oldState *Stat
5555

5656
viewLineIndices, patchLineIndices := wrapPatchLines(diff, view)
5757

58+
if selectedRealLineIdx != -1 {
59+
selectedLineIdx = patch.PatchLineForLineNumber(selectedRealLineIdx)
60+
}
61+
5862
rangeStartLineIdx := 0
5963
if oldState != nil {
6064
rangeStartLineIdx = oldState.rangeStartLineIdx

pkg/gui/types/context.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,9 @@ type IViewTrait interface {
222222
type OnFocusOpts struct {
223223
ClickedWindowName string
224224
ClickedViewLineIdx int
225+
226+
// If not -1, takes precedence over ClickedViewLineIdx.
227+
ClickedViewRealLineIdx int
225228
}
226229

227230
type OnFocusLostOpts struct {

vendor/github.com/jesseduffield/gocui/view.go

Lines changed: 14 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)