Skip to content

Commit d84c108

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 905d763 commit d84c108

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
@@ -55,8 +55,9 @@ func (gui *Gui) resetHelpersAndControllers() {
5555

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

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

pkg/gui/controllers/commits_files_controller.go

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

465465
func (self *CommitFilesController) enter(node *filetree.CommitFileNode) error {
466-
return self.enterCommitFile(node, types.OnFocusOpts{ClickedWindowName: "", ClickedViewLineIdx: -1})
466+
return self.enterCommitFile(node, types.OnFocusOpts{ClickedWindowName: "", ClickedViewLineIdx: -1, ClickedViewRealLineIdx: -1})
467467
}
468468

469469
func (self *CommitFilesController) enterCommitFile(node *filetree.CommitFileNode, opts types.OnFocusOpts) error {
@@ -533,11 +533,35 @@ func (self *CommitFilesController) expandAll() error {
533533

534534
func (self *CommitFilesController) GetOnClickFocusedMainView() func(mainViewName string, clickedLineIdx int) error {
535535
return func(mainViewName string, clickedLineIdx int) error {
536+
clickedFile, line, ok := self.c.Helpers().Staging.GetFileAndLineForClickedDiffLine(mainViewName, clickedLineIdx)
537+
if !ok {
538+
line = -1
539+
}
540+
536541
node := self.getSelectedItem()
537-
if node != nil && node.File != nil {
538-
return self.enterCommitFile(node, types.OnFocusOpts{ClickedWindowName: mainViewName, ClickedViewLineIdx: clickedLineIdx})
542+
if node == nil {
543+
return nil
539544
}
540-
return nil
545+
546+
if !node.IsFile() && ok {
547+
relativePath, err := filepath.Rel(self.c.Git().RepoPaths.RepoPath(), clickedFile)
548+
if err != nil {
549+
return err
550+
}
551+
relativePath = "./" + relativePath
552+
self.context().CommitFileTreeViewModel.ExpandToPath(relativePath)
553+
self.c.PostRefreshUpdate(self.context())
554+
555+
idx, ok := self.context().CommitFileTreeViewModel.GetIndexForPath(relativePath)
556+
if ok {
557+
self.context().SetSelectedLineIdx(idx)
558+
self.context().GetViewTrait().FocusPoint(
559+
self.context().ModelIndexToViewIndex(idx))
560+
node = self.context().GetSelected()
561+
}
562+
}
563+
564+
return self.enterCommitFile(node, types.OnFocusOpts{ClickedWindowName: "main", ClickedViewLineIdx: line, ClickedViewRealLineIdx: line})
541565
}
542566
}
543567

pkg/gui/controllers/files_controller.go

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

293293
func (self *FilesController) GetOnClickFocusedMainView() func(mainViewName string, clickedLineIdx int) error {
294294
return func(mainViewName string, clickedLineIdx int) error {
295-
node := self.getSelectedItem()
296-
if node != nil && node.File != nil {
297-
return self.EnterFile(types.OnFocusOpts{ClickedWindowName: mainViewName, ClickedViewLineIdx: clickedLineIdx})
295+
clickedFile, line, ok := self.c.Helpers().Staging.GetFileAndLineForClickedDiffLine(mainViewName, clickedLineIdx)
296+
if !ok {
297+
line = -1
298298
}
299-
return nil
299+
300+
node := self.context().GetSelected()
301+
if node == nil {
302+
return nil
303+
}
304+
305+
if !node.IsFile() && ok {
306+
relativePath, err := filepath.Rel(self.c.Git().RepoPaths.RepoPath(), clickedFile)
307+
if err != nil {
308+
return err
309+
}
310+
relativePath = "./" + relativePath
311+
self.context().FileTreeViewModel.ExpandToPath(relativePath)
312+
self.c.PostRefreshUpdate(self.context())
313+
314+
idx, ok := self.context().FileTreeViewModel.GetIndexForPath(relativePath)
315+
if ok {
316+
self.context().SetSelectedLineIdx(idx)
317+
self.context().GetViewTrait().FocusPoint(
318+
self.context().ModelIndexToViewIndex(idx))
319+
}
320+
}
321+
322+
return self.EnterFile(types.OnFocusOpts{ClickedWindowName: mainViewName, ClickedViewLineIdx: line, ClickedViewRealLineIdx: line})
300323
}
301324
}
302325

@@ -478,7 +501,7 @@ func (self *FilesController) getSelectedFile() *models.File {
478501
}
479502

480503
func (self *FilesController) enter() error {
481-
return self.EnterFile(types.OnFocusOpts{ClickedWindowName: "", ClickedViewLineIdx: -1})
504+
return self.EnterFile(types.OnFocusOpts{ClickedWindowName: "", ClickedViewLineIdx: -1, ClickedViewRealLineIdx: -1})
482505
}
483506

484507
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
@@ -54,8 +54,10 @@ func (self *PatchBuildingHelper) Reset() error {
5454

5555
func (self *PatchBuildingHelper) RefreshPatchBuildingPanel(opts types.OnFocusOpts) {
5656
selectedLineIdx := -1
57+
selectedRealLineIdx := -1
5758
if opts.ClickedWindowName == "main" {
5859
selectedLineIdx = opts.ClickedViewLineIdx
60+
selectedRealLineIdx = opts.ClickedViewRealLineIdx
5961
}
6062

6163
if !self.c.Git().Patch.PatchBuilder.Active() {
@@ -87,7 +89,7 @@ func (self *PatchBuildingHelper) RefreshPatchBuildingPanel(opts types.OnFocusOpt
8789

8890
oldState := context.GetState()
8991

90-
state := patch_exploring.NewState(diff, selectedLineIdx, context.GetView(), oldState)
92+
state := patch_exploring.NewState(diff, selectedLineIdx, selectedRealLineIdx, context.GetView(), oldState)
9193
context.SetState(state)
9294
if state == nil {
9395
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
@@ -160,9 +160,15 @@ func (self *PatchExplorerController) GetMouseKeybindings(opts types.KeybindingsO
160160
return self.withRenderAndFocus(self.HandleMouseDown)()
161161
}
162162

163+
_, line, ok := self.c.Helpers().Staging.GetFileAndLineForClickedDiffLine(self.context.GetWindowName(), opts.Y)
164+
if !ok {
165+
line = -1
166+
}
167+
163168
self.c.Context().Push(self.context, types.OnFocusOpts{
164-
ClickedWindowName: self.context.GetWindowName(),
165-
ClickedViewLineIdx: opts.Y,
169+
ClickedWindowName: self.context.GetWindowName(),
170+
ClickedViewLineIdx: opts.Y,
171+
ClickedViewRealLineIdx: line,
166172
})
167173

168174
return nil

pkg/gui/patch_exploring/state.go

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

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

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

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

pkg/gui/types/context.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,9 @@ type IViewTrait interface {
220220
type OnFocusOpts struct {
221221
ClickedWindowName string
222222
ClickedViewLineIdx int
223+
224+
// If not -1, takes precedence over ClickedViewLineIdx.
225+
ClickedViewRealLineIdx int
223226
}
224227

225228
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)