Skip to content

Commit 7729e6e

Browse files
committed
kitten diff: add support for sticky header
1 parent 2af98fd commit 7729e6e

3 files changed

Lines changed: 50 additions & 2 deletions

File tree

kittens/diff/main.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,11 @@ def main(args: list[str]) -> None:
8989
'''
9090
)
9191

92+
opt('sticky_header', 'no', option_type='to_bool', long_text='''
93+
When scrolled past the header of a file, keep the file's name and separator
94+
pinned to the top of the screen.
95+
''')
96+
9297
egr() # }}}
9398

9499
# colors {{{

kittens/diff/render.go

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"fmt"
88
"math"
99
"os"
10+
"sort"
1011
"strconv"
1112
"strings"
1213

@@ -318,11 +319,24 @@ func title_lines(left_path, right_path string, columns, margin_size int, ans []*
318319

319320
type LogicalLines struct {
320321
lines []*LogicalLine
322+
title_line_indices []int // sorted indices of TITLE_LINEs in lines -- used for sticky_header
321323
margin_size, columns int
322324
}
323325

324326
func (self *LogicalLines) At(i int) *LogicalLine { return self.lines[i] }
325327

328+
func (self *LogicalLines) TitleLineIdxFor(line_idx int) int {
329+
if len(self.title_line_indices) == 0 || line_idx < 0 {
330+
return -1
331+
}
332+
// first title index > line_idx, so the one before it is our answer
333+
i := sort.SearchInts(self.title_line_indices, line_idx+1)
334+
if i == 0 {
335+
return -1
336+
}
337+
return self.title_line_indices[i-1]
338+
}
339+
326340
func (self *LogicalLines) ScreenLineAt(pos ScrollPos) *ScreenLine {
327341
if pos.logical_line < len(self.lines) && pos.logical_line >= 0 {
328342
line := self.lines[pos.logical_line]
@@ -793,8 +807,13 @@ func rename_lines(path, other_path string, columns, margin_size int, ans []*Logi
793807
func render(collection *Collection, diff_map map[string]*Patch, screen_size screen_size, largest_line_number int, image_size graphics.Size) (result *LogicalLines, err error) {
794808
margin_size := utils.Max(3, len(strconv.Itoa(largest_line_number))+1)
795809
ans := make([]*LogicalLine, 0, 1024)
810+
var title_line_indices []int
811+
track_titles := conf != nil && conf.Sticky_header
796812
columns := screen_size.columns
797813
err = collection.Apply(func(path, item_type, changed_path string) error {
814+
if track_titles {
815+
title_line_indices = append(title_line_indices, len(ans))
816+
}
798817
ans = title_lines(path, changed_path, columns, margin_size, ans)
799818
defer func() {
800819
ans = append(ans, &LogicalLine{line_type: EMPTY_LINE, screen_lines: []*ScreenLine{{}}})
@@ -863,5 +882,5 @@ func render(collection *Collection, diff_map map[string]*Patch, screen_size scre
863882
// Having am empty list of lines causes panics later on
864883
ll = []*LogicalLine{{line_type: EMPTY_LINE, screen_lines: []*ScreenLine{{}}}}
865884
}
866-
return &LogicalLines{lines: ll, margin_size: margin_size, columns: columns}, err
885+
return &LogicalLines{lines: ll, title_line_indices: title_line_indices, margin_size: margin_size, columns: columns}, err
867886
}

kittens/diff/ui.go

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,11 @@ func (self *Handler) draw_screen() {
414414
}
415415
pos := self.scroll_pos
416416
seen_images := utils.NewSet[int]()
417-
for num_written := 0; num_written < self.screen_size.num_lines; num_written++ {
417+
num_written := 0
418+
if conf != nil && conf.Sticky_header {
419+
num_written = self.draw_sticky_header(&pos)
420+
}
421+
for ; num_written < self.screen_size.num_lines; num_written++ {
418422
ll := self.logical_lines.At(pos.logical_line)
419423
if ll == nil || self.logical_lines.ScreenLineAt(pos) == nil {
420424
num_written--
@@ -443,6 +447,26 @@ func (self *Handler) draw_screen() {
443447
self.draw_status_line()
444448
}
445449

450+
func (self *Handler) draw_sticky_header(pos *ScrollPos) int {
451+
title_idx := self.logical_lines.TitleLineIdxFor(pos.logical_line)
452+
if title_idx < 0 {
453+
return 0
454+
}
455+
// file title
456+
self.logical_lines.At(title_idx).render_screen_line(0, self.lp, self.logical_lines.margin_size, self.logical_lines.columns)
457+
self.lp.MoveCursorVertically(1)
458+
self.lp.QueueWriteString("\x1b[m\r")
459+
self.logical_lines.IncrementScrollPosBy(pos, 1)
460+
461+
// separator
462+
self.logical_lines.At(title_idx+1).render_screen_line(0, self.lp, self.logical_lines.margin_size, self.logical_lines.columns)
463+
self.lp.MoveCursorVertically(1)
464+
self.lp.QueueWriteString("\x1b[m\r")
465+
self.logical_lines.IncrementScrollPosBy(pos, 1)
466+
467+
return 2
468+
}
469+
446470
func (self *Handler) draw_status_line() {
447471
if self.logical_lines == nil || self.diff_map == nil {
448472
return

0 commit comments

Comments
 (0)