mirror of
https://github.com/Llewellynvdm/fzf.git
synced 2025-01-23 07:08:27 +00:00
Provide an option to reverse items only (#1267)
This commit is contained in:
parent
2c26f02f5c
commit
daa1958f86
@ -223,8 +223,8 @@ cursor with `--height` option.
|
||||
vim $(fzf --height 40%)
|
||||
```
|
||||
|
||||
Also check out `--reverse` option if you prefer "top-down" layout instead of
|
||||
the default "bottom-up" layout.
|
||||
Also check out `--reverse` and `--layout` options if you prefer
|
||||
"top-down" layout instead of the default "bottom-up" layout.
|
||||
|
||||
```sh
|
||||
vim $(fzf --height 40% --reverse)
|
||||
@ -234,7 +234,7 @@ You can add these options to `$FZF_DEFAULT_OPTS` so that they're applied by
|
||||
default. For example,
|
||||
|
||||
```sh
|
||||
export FZF_DEFAULT_OPTS='--height 40% --reverse --border'
|
||||
export FZF_DEFAULT_OPTS='--height 40% --layout=reverse --border'
|
||||
```
|
||||
|
||||
#### Search syntax
|
||||
@ -272,7 +272,7 @@ or `py`.
|
||||
- e.g. `export FZF_DEFAULT_COMMAND='fd --type f'`
|
||||
- `FZF_DEFAULT_OPTS`
|
||||
- Default options
|
||||
- e.g. `export FZF_DEFAULT_OPTS="--reverse --inline-info"`
|
||||
- e.g. `export FZF_DEFAULT_OPTS="--layout=reverse --inline-info"`
|
||||
|
||||
#### Options
|
||||
|
||||
|
@ -155,9 +155,22 @@ the full screen.
|
||||
.BI "--min-height=" "HEIGHT"
|
||||
Minimum height when \fB--height\fR is given in percent (default: 10).
|
||||
Ignored when \fB--height\fR is not specified.
|
||||
.TP
|
||||
.BI "--layout=" "LAYOUT"
|
||||
Choose the layout (default: default)
|
||||
|
||||
.br
|
||||
.BR default " Display from the bottom of the screen"
|
||||
.br
|
||||
.BR reverse " Display from the top of the screen"
|
||||
.br
|
||||
.BR reverse-list " Display from the top of the screen, prompt at the bottom"
|
||||
.br
|
||||
|
||||
.TP
|
||||
.B "--reverse"
|
||||
Reverse orientation
|
||||
A synonym for \fB--layout=reverse\fB
|
||||
|
||||
.TP
|
||||
.B "--border"
|
||||
Draw border above and below the finder
|
||||
@ -195,7 +208,7 @@ Input prompt (default: '> ')
|
||||
.TP
|
||||
.BI "--header=" "STR"
|
||||
The given string will be printed as the sticky header. The lines are displayed
|
||||
in the given order from top to bottom regardless of \fB--reverse\fR option, and
|
||||
in the given order from top to bottom regardless of \fB--layout\fR option, and
|
||||
are not affected by \fB--with-nth\fR. ANSI color codes are processed even when
|
||||
\fB--ansi\fR is not set.
|
||||
.TP
|
||||
@ -543,8 +556,8 @@ triggered whenever the query string is changed.
|
||||
\fBtoggle\fR (\fIright-click\fR)
|
||||
\fBtoggle-all\fR
|
||||
\fBtoggle+down\fR \fIctrl-i (tab)\fR
|
||||
\fBtoggle-in\fR (\fB--reverse\fR ? \fBtoggle+up\fR : \fBtoggle+down\fR)
|
||||
\fBtoggle-out\fR (\fB--reverse\fR ? \fBtoggle+down\fR : \fBtoggle+up\fR)
|
||||
\fBtoggle-in\fR (\fB--layout=reverse*\fR ? \fBtoggle+up\fR : \fBtoggle+down\fR)
|
||||
\fBtoggle-out\fR (\fB--layout=reverse*\fR ? \fBtoggle+down\fR : \fBtoggle+up\fR)
|
||||
\fBtoggle-preview\fR
|
||||
\fBtoggle-preview-wrap\fR
|
||||
\fBtoggle-sort\fR
|
||||
|
@ -53,7 +53,7 @@ const usage = `usage: fzf [options]
|
||||
height instead of using fullscreen
|
||||
--min-height=HEIGHT Minimum height when --height is given in percent
|
||||
(default: 10)
|
||||
--reverse Reverse orientation
|
||||
--layout=LAYOUT Choose layout: [default|reverse|reverse-list]
|
||||
--border Draw border above and below the finder
|
||||
--margin=MARGIN Screen margin (TRBL / TB,RL / T,RL,B / T,R,B,L)
|
||||
--inline-info Display finder info inline with the query
|
||||
@ -90,7 +90,8 @@ const usage = `usage: fzf [options]
|
||||
|
||||
Environment variables
|
||||
FZF_DEFAULT_COMMAND Default command to use when input is tty
|
||||
FZF_DEFAULT_OPTS Default options (e.g. '--reverse --inline-info')
|
||||
FZF_DEFAULT_OPTS Default options
|
||||
(e.g. '--layout=reverse --inline-info')
|
||||
|
||||
`
|
||||
|
||||
@ -132,6 +133,14 @@ const (
|
||||
posRight
|
||||
)
|
||||
|
||||
type layoutType int
|
||||
|
||||
const (
|
||||
layoutDefault layoutType = iota
|
||||
layoutReverse
|
||||
layoutReverseList
|
||||
)
|
||||
|
||||
type previewOpts struct {
|
||||
command string
|
||||
position windowPosition
|
||||
@ -161,7 +170,7 @@ type Options struct {
|
||||
Bold bool
|
||||
Height sizeSpec
|
||||
MinHeight int
|
||||
Reverse bool
|
||||
Layout layoutType
|
||||
Cycle bool
|
||||
Hscroll bool
|
||||
HscrollOff int
|
||||
@ -211,7 +220,7 @@ func defaultOptions() *Options {
|
||||
Black: false,
|
||||
Bold: true,
|
||||
MinHeight: 10,
|
||||
Reverse: false,
|
||||
Layout: layoutDefault,
|
||||
Cycle: false,
|
||||
Hscroll: true,
|
||||
HscrollOff: 10,
|
||||
@ -857,6 +866,20 @@ func parseHeight(str string) sizeSpec {
|
||||
return size
|
||||
}
|
||||
|
||||
func parseLayout(str string) layoutType {
|
||||
switch str {
|
||||
case "default":
|
||||
return layoutDefault
|
||||
case "reverse":
|
||||
return layoutReverse
|
||||
case "reverse-list":
|
||||
return layoutReverseList
|
||||
default:
|
||||
errorExit("invalid layout (expected: default / reverse / reverse-list)")
|
||||
}
|
||||
return layoutDefault
|
||||
}
|
||||
|
||||
func parsePreviewWindow(opts *previewOpts, input string) {
|
||||
// Default
|
||||
opts.position = posRight
|
||||
@ -1037,10 +1060,13 @@ func parseOptions(opts *Options, allArgs []string) {
|
||||
opts.Bold = true
|
||||
case "--no-bold":
|
||||
opts.Bold = false
|
||||
case "--layout":
|
||||
opts.Layout = parseLayout(
|
||||
nextString(allArgs, &i, "layout required (default / reverse / reverse-list)"))
|
||||
case "--reverse":
|
||||
opts.Reverse = true
|
||||
opts.Layout = layoutReverse
|
||||
case "--no-reverse":
|
||||
opts.Reverse = false
|
||||
opts.Layout = layoutDefault
|
||||
case "--cycle":
|
||||
opts.Cycle = true
|
||||
case "--no-cycle":
|
||||
@ -1156,6 +1182,8 @@ func parseOptions(opts *Options, allArgs []string) {
|
||||
opts.Height = parseHeight(value)
|
||||
} else if match, value := optString(arg, "--min-height="); match {
|
||||
opts.MinHeight = atoi(value)
|
||||
} else if match, value := optString(arg, "--layout="); match {
|
||||
opts.Layout = parseLayout(value)
|
||||
} else if match, value := optString(arg, "--toggle-sort="); match {
|
||||
parseToggleSort(opts.Keymap, value)
|
||||
} else if match, value := optString(arg, "--expect="); match {
|
||||
|
@ -59,7 +59,7 @@ type Terminal struct {
|
||||
inlineInfo bool
|
||||
prompt string
|
||||
promptLen int
|
||||
reverse bool
|
||||
layout layoutType
|
||||
fullscreen bool
|
||||
hscroll bool
|
||||
hscrollOff int
|
||||
@ -302,10 +302,11 @@ func trimQuery(query string) []rune {
|
||||
func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal {
|
||||
input := trimQuery(opts.Query)
|
||||
var header []string
|
||||
if opts.Reverse {
|
||||
header = opts.Header
|
||||
} else {
|
||||
switch opts.Layout {
|
||||
case layoutDefault, layoutReverseList:
|
||||
header = reverseStringArray(opts.Header)
|
||||
default:
|
||||
header = opts.Header
|
||||
}
|
||||
var delay time.Duration
|
||||
if opts.Tac {
|
||||
@ -363,7 +364,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal {
|
||||
t := Terminal{
|
||||
initDelay: delay,
|
||||
inlineInfo: opts.InlineInfo,
|
||||
reverse: opts.Reverse,
|
||||
layout: opts.Layout,
|
||||
fullscreen: fullscreen,
|
||||
hscroll: opts.Hscroll,
|
||||
hscrollOff: opts.HscrollOff,
|
||||
@ -643,8 +644,21 @@ func (t *Terminal) resizeWindows() {
|
||||
}
|
||||
|
||||
func (t *Terminal) move(y int, x int, clear bool) {
|
||||
if !t.reverse {
|
||||
y = t.window.Height() - y - 1
|
||||
h := t.window.Height()
|
||||
|
||||
switch t.layout {
|
||||
case layoutDefault:
|
||||
y = h - y - 1
|
||||
case layoutReverseList:
|
||||
n := 2 + len(t.header)
|
||||
if t.inlineInfo {
|
||||
n--
|
||||
}
|
||||
if y < n {
|
||||
y = h - y - 1
|
||||
} else {
|
||||
y -= n
|
||||
}
|
||||
}
|
||||
|
||||
if clear {
|
||||
@ -748,7 +762,7 @@ func (t *Terminal) printList() {
|
||||
count := t.merger.Length() - t.offset
|
||||
for j := 0; j < maxy; j++ {
|
||||
i := j
|
||||
if !t.reverse {
|
||||
if t.layout == layoutDefault {
|
||||
i = maxy - 1 - j
|
||||
}
|
||||
line := i + 2 + len(t.header)
|
||||
@ -1680,12 +1694,12 @@ func (t *Terminal) Loop() {
|
||||
req(reqList, reqInfo)
|
||||
}
|
||||
case actToggleIn:
|
||||
if t.reverse {
|
||||
if t.layout != layoutDefault {
|
||||
return doAction(action{t: actToggleUp}, mapkey)
|
||||
}
|
||||
return doAction(action{t: actToggleDown}, mapkey)
|
||||
case actToggleOut:
|
||||
if t.reverse {
|
||||
if t.layout != layoutDefault {
|
||||
return doAction(action{t: actToggleDown}, mapkey)
|
||||
}
|
||||
return doAction(action{t: actToggleUp}, mapkey)
|
||||
@ -1813,13 +1827,21 @@ func (t *Terminal) Loop() {
|
||||
mx -= t.window.Left()
|
||||
my -= t.window.Top()
|
||||
mx = util.Constrain(mx-t.promptLen, 0, len(t.input))
|
||||
if !t.reverse {
|
||||
my = t.window.Height() - my - 1
|
||||
}
|
||||
min := 2 + len(t.header)
|
||||
if t.inlineInfo {
|
||||
min--
|
||||
}
|
||||
h := t.window.Height()
|
||||
switch t.layout {
|
||||
case layoutDefault:
|
||||
my = h - my - 1
|
||||
case layoutReverseList:
|
||||
if my < h-min {
|
||||
my += min
|
||||
} else {
|
||||
my = h - my - 1
|
||||
}
|
||||
}
|
||||
if me.Double {
|
||||
// Double-click
|
||||
if my >= min {
|
||||
@ -1912,7 +1934,7 @@ func (t *Terminal) constrain() {
|
||||
}
|
||||
|
||||
func (t *Terminal) vmove(o int, allowCycle bool) {
|
||||
if t.reverse {
|
||||
if t.layout != layoutDefault {
|
||||
o *= -1
|
||||
}
|
||||
dest := t.cy + o
|
||||
|
47
test/test_go.rb
Normal file → Executable file
47
test/test_go.rb
Normal file → Executable file
@ -1060,6 +1060,21 @@ class TestGoFZF < TestBase
|
||||
assert_equal '50', readonce.chomp
|
||||
end
|
||||
|
||||
def test_header_lines_reverse_list
|
||||
tmux.send_keys "seq 100 | #{fzf '--header-lines=10 -q 5 --layout=reverse-list'}", :Enter
|
||||
2.times do
|
||||
tmux.until do |lines|
|
||||
lines[0] == '> 50' &&
|
||||
lines[-4] == ' 2' &&
|
||||
lines[-3] == ' 1' &&
|
||||
lines[-2].include?('/90')
|
||||
end
|
||||
tmux.send_keys :Up
|
||||
end
|
||||
tmux.send_keys :Enter
|
||||
assert_equal '50', readonce.chomp
|
||||
end
|
||||
|
||||
def test_header_lines_overflow
|
||||
tmux.send_keys "seq 100 | #{fzf '--header-lines=200'}", :Enter
|
||||
tmux.until do |lines|
|
||||
@ -1087,7 +1102,8 @@ class TestGoFZF < TestBase
|
||||
header = File.readlines(FILE).take(5).map(&:strip)
|
||||
tmux.until do |lines|
|
||||
lines[-2].include?('100/100') &&
|
||||
lines[-7..-3].map(&:strip) == header
|
||||
lines[-7..-3].map(&:strip) == header &&
|
||||
lines[-8] == '> 1'
|
||||
end
|
||||
end
|
||||
|
||||
@ -1096,7 +1112,18 @@ class TestGoFZF < TestBase
|
||||
header = File.readlines(FILE).take(5).map(&:strip)
|
||||
tmux.until do |lines|
|
||||
lines[1].include?('100/100') &&
|
||||
lines[2..6].map(&:strip) == header
|
||||
lines[2..6].map(&:strip) == header &&
|
||||
lines[7] == '> 1'
|
||||
end
|
||||
end
|
||||
|
||||
def test_header_reverse_list
|
||||
tmux.send_keys "seq 100 | #{fzf "--header=\\\"\\$(head -5 #{FILE})\\\" --layout=reverse-list"}", :Enter
|
||||
header = File.readlines(FILE).take(5).map(&:strip)
|
||||
tmux.until do |lines|
|
||||
lines[-2].include?('100/100') &&
|
||||
lines[-7..-3].map(&:strip) == header &&
|
||||
lines[0] == '> 1'
|
||||
end
|
||||
end
|
||||
|
||||
@ -1120,6 +1147,16 @@ class TestGoFZF < TestBase
|
||||
end
|
||||
end
|
||||
|
||||
def test_header_and_header_lines_reverse_list
|
||||
tmux.send_keys "seq 100 | #{fzf "--layout=reverse-list --header-lines 10 --header \\\"\\$(head -5 #{FILE})\\\""}", :Enter
|
||||
header = File.readlines(FILE).take(5).map(&:strip)
|
||||
tmux.until do |lines|
|
||||
lines[-2].include?('90/90') &&
|
||||
lines[-7...-2].map(&:strip) == header &&
|
||||
lines[-17...-7].map(&:strip) == (1..10).map(&:to_s).reverse
|
||||
end
|
||||
end
|
||||
|
||||
def test_cancel
|
||||
tmux.send_keys "seq 10 | #{fzf '--bind 2:cancel'}", :Enter
|
||||
tmux.until { |lines| lines[-2].include?('10/10') }
|
||||
@ -1145,6 +1182,12 @@ class TestGoFZF < TestBase
|
||||
tmux.send_keys :Enter
|
||||
end
|
||||
|
||||
def test_margin_reverse_list
|
||||
tmux.send_keys "yes | head -1000 | #{fzf '--margin 5,3 --layout=reverse-list'}", :Enter
|
||||
tmux.until { |lines| lines[4] == '' && lines[5] == ' > y' }
|
||||
tmux.send_keys :Enter
|
||||
end
|
||||
|
||||
def test_tabstop
|
||||
writelines tempname, ["f\too\tba\tr\tbaz\tbarfooq\tux"]
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user