@@ -33,18 +33,19 @@ const (
3333
3434// DiffView represents a view for displaying differences between two files.
3535type DiffView struct {
36− layout layout
37− before file
38− after file
39− contextLines int
40− lineNumbers bool
41− height int
42− width int
43− xOffset int
44− yOffset int
45− style Style
46− tabWidth int
47− chromaStyle *chroma.Style
36+ layout layout
37+ before file
38+ after file
39+ contextLines int
40+ lineNumbers bool
41+ height int
42+ width int
43+ xOffset int
44+ yOffset int
45+ infiniteYScroll bool
46+ style Style
47+ tabWidth int
48+ chromaStyle *chroma.Style
4849
4950 isComputed bool
5051 err error
@@ -53,6 +54,7 @@ type DiffView struct {
5354
5455 splitHunks []splitHunk
5556
57+ totalLines int
5658 codeWidth int
5759 fullCodeWidth int // with leading symbols
5860 extraColOnAfter bool // add extra column on after panel
@@ -138,6 +140,12 @@ func (dv *DiffView) YOffset(yOffset int) *DiffView {
138140 return dv
139141}
140142
143+// InfiniteYScroll allows the YOffset to scroll beyond the last line.
144+func (dv *DiffView) InfiniteYScroll(infiniteYScroll bool) *DiffView {
145+ dv.infiniteYScroll = infiniteYScroll
146+ return dv
147+}
148+
141149// TabWidth sets the tab width. Only relevant for code that contains tabs, like
142150// Go code.
143151func (dv *DiffView) TabWidth(tabWidth int) *DiffView {
@@ -161,6 +169,8 @@ func (dv *DiffView) String() string {
161169 dv.convertDiffToSplit()
162170 dv.adjustStyles()
163171 dv.detectNumDigits()
172+ dv.detectTotalLines()
173+ dv.preventInfiniteYScroll()
164174
165175 if dv.width <= 0 {
166176 dv.detectCodeWidth()
@@ -251,6 +261,37 @@ func (dv *DiffView) detectNumDigits() {
251261 }
252262}
253263
264+func (dv *DiffView) detectTotalLines() {
265+ dv.totalLines = 0
266+
267+ switch dv.layout {
268+ case layoutUnified:
269+ for _, h := range dv.unified.Hunks {
270+ dv.totalLines += 1 + len(h.Lines)
271+ }
272+ case layoutSplit:
273+ for _, h := range dv.splitHunks {
274+ dv.totalLines += 1 + len(h.lines)
275+ }
276+ }
277+}
278+
279+func (dv *DiffView) preventInfiniteYScroll() {
280+ if dv.infiniteYScroll {
281+ return
282+ }
283+
284+ // clamp yOffset to prevent scrolling beyond the last line
285+ if dv.height > 0 {
286+ maxYOffset := max(0, dv.totalLines-dv.height)
287+ dv.yOffset = min(dv.yOffset, maxYOffset)
288+ } else {
289+ // if no height limit, ensure yOffset doesn't exceed total lines
290+ dv.yOffset = min(dv.yOffset, max(0, dv.totalLines-1))
291+ }
292+ dv.yOffset = max(0, dv.yOffset) // ensure yOffset is not negative
293+}
294+
254295// detectCodeWidth calculates the maximum width of code lines in the diff view.
255296func (dv *DiffView) detectCodeWidth() {
256297 switch dv.layout {