Skip to content

Commit 64cd7cd

Browse files
committed
Adjust line number for working copy when editing a line
There are two ways to jump to the editor on a specific line: pressing `e` in the staging or patch building panels, or clicking on a hyperlink in a delta diff. In both cases, this works perfectly in the unstaged changes view, but in other views (either staged changes, or an older commit) it can often jump to the wrong line; this happens when there are further changes to the file being viewed in later commits or in unstaged changes. This commit fixes this so that you end up on the right line in these cases.
1 parent eaaf123 commit 64cd7cd

17 files changed

+182
-3
lines changed

pkg/commands/patch/patch.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,3 +154,24 @@ func (self *Patch) LineCount() int {
154154
func (self *Patch) HunkCount() int {
155155
return len(self.hunks)
156156
}
157+
158+
// Adjust the given line number (one-based) according to the current patch. The
159+
// patch is supposed to be a diff of an old file state against the working
160+
// directory; the line number is a line number in that old file, and the
161+
// function returns the corresponding line number in the working directory file.
162+
func (self *Patch) AdjustLineNumber(lineNumber int) int {
163+
adjustedLineNumber := lineNumber
164+
for _, hunk := range self.hunks {
165+
if hunk.oldStart >= lineNumber {
166+
break
167+
}
168+
169+
if hunk.oldStart+hunk.oldLength() > lineNumber {
170+
return hunk.newStart
171+
}
172+
173+
adjustedLineNumber += hunk.newLength() - hunk.oldLength()
174+
}
175+
176+
return adjustedLineNumber
177+
}

pkg/commands/patch/patch_test.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -639,3 +639,59 @@ func TestGetNextStageableLineIndex(t *testing.T) {
639639
})
640640
}
641641
}
642+
643+
func TestAdjustLineNumber(t *testing.T) {
644+
type scenario struct {
645+
oldLineNumbers []int
646+
expectedResults []int
647+
}
648+
scenarios := []scenario{
649+
{
650+
oldLineNumbers: []int{1, 2, 3, 4, 5, 6, 7},
651+
expectedResults: []int{1, 2, 2, 3, 4, 7, 8},
652+
},
653+
}
654+
655+
// The following diff was generated from old.txt:
656+
// 1
657+
// 2a
658+
// 2b
659+
// 3
660+
// 4
661+
// 7
662+
// 8
663+
// against new.txt:
664+
// 1
665+
// 2
666+
// 3
667+
// 4
668+
// 5
669+
// 6
670+
// 7
671+
// 8
672+
673+
// This test setup makes the test easy to understand, because the resulting
674+
// adjusted line numbers are the same as the content of the lines in new.txt.
675+
676+
diff := `--- old.txt 2024-12-16 18:04:29
677+
+++ new.txt 2024-12-16 18:04:27
678+
@@ -2,2 +2 @@
679+
-2a
680+
-2b
681+
+2
682+
@@ -5,0 +5,2 @@
683+
+5
684+
+6
685+
`
686+
687+
patch := Parse(diff)
688+
689+
for _, s := range scenarios {
690+
t.Run("TestAdjustLineNumber", func(t *testing.T) {
691+
for idx, oldLineNumber := range s.oldLineNumbers {
692+
result := patch.AdjustLineNumber(oldLineNumber)
693+
assert.Equal(t, s.expectedResults[idx], result)
694+
}
695+
})
696+
}
697+
}

pkg/gui/context/branches_context.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,14 @@ func (self *BranchesContext) GetDiffTerminals() []string {
8080
return nil
8181
}
8282

83+
func (self *BranchesContext) RefForAdjustingLineNumberInDiff() string {
84+
branch := self.GetSelected()
85+
if branch != nil {
86+
return branch.ID()
87+
}
88+
return ""
89+
}
90+
8391
func (self *BranchesContext) ShowBranchHeadsInSubCommits() bool {
8492
return true
8593
}

pkg/gui/context/commit_files_context.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,13 @@ func (self *CommitFilesContext) GetDiffTerminals() []string {
7777
return []string{self.GetRef().RefName()}
7878
}
7979

80+
func (self *CommitFilesContext) RefForAdjustingLineNumberInDiff() string {
81+
if refs := self.GetRefRange(); refs != nil {
82+
return refs.To.RefName()
83+
}
84+
return self.GetRef().RefName()
85+
}
86+
8087
func (self *CommitFilesContext) GetFromAndToForDiff() (string, string) {
8188
if refs := self.GetRefRange(); refs != nil {
8289
return refs.From.ParentRefName(), refs.To.RefName()

pkg/gui/context/local_commits_context.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,14 @@ func (self *LocalCommitsContext) GetDiffTerminals() []string {
170170
return []string{itemId}
171171
}
172172

173+
func (self *LocalCommitsContext) RefForAdjustingLineNumberInDiff() string {
174+
commits, _, _ := self.GetSelectedItems()
175+
if commits == nil {
176+
return ""
177+
}
178+
return commits[0].Hash
179+
}
180+
173181
func (self *LocalCommitsContext) ModelSearchResults(searchStr string, caseSensitive bool) []gocui.SearchPosition {
174182
return searchModelCommits(caseSensitive, self.GetCommits(), self.ColumnPositions(), searchStr)
175183
}

pkg/gui/context/reflog_commits_context.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,10 @@ func (self *ReflogCommitsContext) GetDiffTerminals() []string {
8686
return []string{itemId}
8787
}
8888

89+
func (self *ReflogCommitsContext) RefForAdjustingLineNumberInDiff() string {
90+
return self.GetSelectedItemId()
91+
}
92+
8993
func (self *ReflogCommitsContext) ShowBranchHeadsInSubCommits() bool {
9094
return false
9195
}

pkg/gui/context/remote_branches_context.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,10 @@ func (self *RemoteBranchesContext) GetDiffTerminals() []string {
7878
return []string{itemId}
7979
}
8080

81+
func (self *RemoteBranchesContext) RefForAdjustingLineNumberInDiff() string {
82+
return self.GetSelectedItemId()
83+
}
84+
8185
func (self *RemoteBranchesContext) ShowBranchHeadsInSubCommits() bool {
8286
return true
8387
}

pkg/gui/context/remotes_context.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,7 @@ func (self *RemotesContext) GetDiffTerminals() []string {
5353

5454
return []string{itemId}
5555
}
56+
57+
func (self *RemotesContext) RefForAdjustingLineNumberInDiff() string {
58+
return ""
59+
}

pkg/gui/context/stash_context.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,3 +71,7 @@ func (self *StashContext) GetDiffTerminals() []string {
7171

7272
return []string{itemId}
7373
}
74+
75+
func (self *StashContext) RefForAdjustingLineNumberInDiff() string {
76+
return self.GetSelectedItemId()
77+
}

pkg/gui/context/sub_commits_context.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,14 @@ func (self *SubCommitsContext) GetDiffTerminals() []string {
217217
return []string{itemId}
218218
}
219219

220+
func (self *SubCommitsContext) RefForAdjustingLineNumberInDiff() string {
221+
commits, _, _ := self.GetSelectedItems()
222+
if commits == nil {
223+
return ""
224+
}
225+
return commits[0].Hash
226+
}
227+
220228
func (self *SubCommitsContext) ModelSearchResults(searchStr string, caseSensitive bool) []gocui.SearchPosition {
221229
return searchModelCommits(caseSensitive, self.GetCommits(), self.ColumnPositions(), searchStr)
222230
}

0 commit comments

Comments
 (0)