diff --git a/src/options.go b/src/options.go index d8b2bd8..17df221 100644 --- a/src/options.go +++ b/src/options.go @@ -784,6 +784,10 @@ func parseOptions(opts *Options, allArgs []string) { } } + if opts.HeaderLines < 0 { + errorExit("header lines must be a non-negative integer") + } + // Change default actions for CTRL-N / CTRL-P when --history is used if opts.History != nil { if _, prs := keymap[curses.CtrlP]; !prs { diff --git a/src/terminal.go b/src/terminal.go index 844574a..52c36cf 100644 --- a/src/terminal.go +++ b/src/terminal.go @@ -377,10 +377,18 @@ func (t *Terminal) printHeader() { if len(t.header) == 0 { return } + max := C.MaxY() for idx, lineStr := range t.header { if !t.reverse { idx = len(t.header) - idx - 1 } + line := idx + 2 + if t.inlineInfo { + line -= 1 + } + if line >= max { + break + } trimmed, colors := extractColor(&lineStr) item := &Item{ text: trimmed, @@ -388,10 +396,6 @@ func (t *Terminal) printHeader() { colors: colors, rank: Rank{0, 0, 0}} - line := idx + 2 - if t.inlineInfo { - line -= 1 - } t.move(line, 2, true) t.printHighlighted(item, false, C.ColHeader, 0, false) } @@ -993,6 +997,7 @@ func (t *Terminal) constrain() { t.offset = util.Max(0, count-height) t.cy = util.Constrain(t.offset+diffpos, 0, count-1) } + t.offset = util.Max(0, t.offset) } func (t *Terminal) vmove(o int) { @@ -1021,8 +1026,9 @@ func (t *Terminal) vset(o int) bool { } func (t *Terminal) maxItems() int { + max := C.MaxY() - 2 - len(t.header) if t.inlineInfo { - return C.MaxY() - 1 - len(t.header) + max += 1 } - return C.MaxY() - 2 - len(t.header) + return util.Max(max, 0) } diff --git a/test/test_go.rb b/test/test_go.rb index 88dff86..7effb5f 100644 --- a/test/test_go.rb +++ b/test/test_go.rb @@ -648,6 +648,61 @@ class TestGoFZF < TestBase tmux.until { |lines| lines[-10].start_with? '>' } end + def test_header_lines + tmux.send_keys "seq 100 | #{fzf '--header-lines=10 -q 5'}", :Enter + 2.times do + tmux.until do |lines| + lines[-2].include?('/90') && + lines[-3] == ' 1' && + lines[-4] == ' 2' && + lines[-13] == '> 15' + end + tmux.send_keys :Down + end + tmux.send_keys :Enter + assert_equal '15', readonce.chomp + end + + def test_header_lines_reverse + tmux.send_keys "seq 100 | #{fzf '--header-lines=10 -q 5 --reverse'}", :Enter + 2.times do + tmux.until do |lines| + lines[1].include?('/90') && + lines[2] == ' 1' && + lines[3] == ' 2' && + lines[12] == '> 15' + end + tmux.send_keys :Up + end + tmux.send_keys :Enter + assert_equal '15', readonce.chomp + end + + def test_header_lines_overflow + tmux.send_keys "seq 100 | #{fzf '--header-lines=200'}", :Enter + tmux.until { |lines| lines[-2].include?('0/0') } + tmux.send_keys :Enter + assert_equal '', readonce.chomp + end + + def test_header_file + tmux.send_keys "seq 100 | #{fzf "--header-file <(head -5 #{__FILE__})"}", :Enter + header = File.readlines(__FILE__).take(5).map(&:strip) + tmux.until do |lines| + lines[-2].include?('100/100') && + lines[-7..-3].map(&:strip) == header + end + end + + def test_header_file_reverse + tmux.send_keys "seq 100 | #{fzf "--header-file <(head -5 #{__FILE__}) --reverse"}", :Enter + header = File.readlines(__FILE__).take(5).map(&:strip) + tmux.until do |lines| + lines[1].include?('100/100') && + lines[2..6].map(&:strip) == header + end + end + private def writelines path, lines File.unlink path while File.exists? path