From 12af069dcad672b1563388c61ec33ba8a86c013e Mon Sep 17 00:00:00 2001 From: Junegunn Choi Date: Tue, 27 Dec 2022 01:01:06 +0900 Subject: [PATCH] Add pos(...) action to move the cursor to the numeric position # Put the cursor on the 10th item seq 100 | fzf --sync --bind 'start:pos(10)' # Put the cursor on the 10th to last item seq 100 | fzf --sync --bind 'start:pos(-10)' Close #3069 Close #395 --- CHANGELOG.md | 9 +++++++++ man/man1/fzf.1 | 5 +++-- src/options.go | 4 +++- src/terminal.go | 11 +++++++++++ test/test_go.rb | 15 +++++++++++++++ 5 files changed, 41 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d1a3816..f4847e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,15 @@ CHANGELOG # Send actions to the server curl -XPOST localhost:6266 -d 'reload(seq 100)+change-prompt(hundred> )' ``` +- Added `pos(...)` action to move the cursor to the numeric position + - `first` and `last` are equivalent to `pos(1)` and `pos(-1)` respectively + ```sh + # Put the cursor on the 10th item + seq 100 | fzf --sync --bind 'start:pos(10)' + + # Put the cursor on the 10th to last item + seq 100 | fzf --sync --bind 'start:pos(-10)' + ``` - Added `next-selected` and `prev-selected` actions to move between selected items ```sh diff --git a/man/man1/fzf.1 b/man/man1/fzf.1 index 6c71f14..17c7dd2 100644 --- a/man/man1/fzf.1 +++ b/man/man1/fzf.1 @@ -979,7 +979,7 @@ A key or an event can be bound to one or more of the following actions. \fBend-of-line\fR \fIctrl-e end\fR \fBexecute(...)\fR (see below for the details) \fBexecute-silent(...)\fR (see below for the details) - \fBfirst\fR (move to the first match) + \fBfirst\fR (move to the first match; same as \fBpos(1)\fR) \fBforward-char\fR \fIctrl-f right\fR \fBforward-word\fR \fIalt-f shift-right\fR \fBignore\fR @@ -987,13 +987,14 @@ A key or an event can be bound to one or more of the following actions. \fBjump-accept\fR (jump and accept) \fBkill-line\fR \fBkill-word\fR \fIalt-d\fR - \fBlast\fR (move to the last match) + \fBlast\fR (move to the last match; same as \fBpos(-1)\fR) \fBnext-history\fR (\fIctrl-n\fR on \fB--history\fR) \fBnext-selected\fR (move to the next selected item) \fBpage-down\fR \fIpgdn\fR \fBpage-up\fR \fIpgup\fR \fBhalf-page-down\fR \fBhalf-page-up\fR + \fBpos(...)\fR (move cursor to the numeric position; negative number to count from the end) \fBprev-history\fR (\fIctrl-p\fR on \fB--history\fR) \fBprev-selected\fR (move to the previous selected item) \fBpreview(...)\fR (see below for the details) diff --git a/src/options.go b/src/options.go index 1fb649f..91ac988 100644 --- a/src/options.go +++ b/src/options.go @@ -890,7 +890,7 @@ const ( func init() { executeRegexp = regexp.MustCompile( - `(?si)[:+](execute(?:-multi|-silent)?|reload|preview|change-query|change-prompt|change-preview-window|change-preview|(?:re|un)bind)`) + `(?si)[:+](execute(?:-multi|-silent)?|reload|preview|change-query|change-prompt|change-preview-window|change-preview|(?:re|un)bind|pos)`) splitRegexp = regexp.MustCompile("[,:]+") actionNameRegexp = regexp.MustCompile("(?i)^[a-z-]+") } @@ -1197,6 +1197,8 @@ func isExecuteAction(str string) actionType { return actChangePrompt case "change-query": return actChangeQuery + case "pos": + return actPosition case "execute": return actExecute case "execute-silent": diff --git a/src/terminal.go b/src/terminal.go index d0c0a9d..90239f7 100644 --- a/src/terminal.go +++ b/src/terminal.go @@ -297,6 +297,7 @@ const ( actUp actPageUp actPageDown + actPosition actHalfPageUp actHalfPageDown actJump @@ -2837,6 +2838,16 @@ func (t *Terminal) Loop() { case actLast: t.vset(t.merger.Length() - 1) req(reqList) + case actPosition: + if n, e := strconv.Atoi(a.a); e == nil { + if n > 0 { + n-- + } else if n < 0 { + n += t.merger.Length() + } + t.vset(n) + req(reqList) + } case actUnixLineDiscard: beof = len(t.input) == 0 if t.cx > 0 { diff --git a/test/test_go.rb b/test/test_go.rb index 4c42439..2956d18 100755 --- a/test/test_go.rb +++ b/test/test_go.rb @@ -1605,6 +1605,21 @@ class TestGoFZF < TestBase tmux.send_keys :Enter end + def test_pos + tmux.send_keys %(seq 1000 | #{FZF} --bind 'a:pos(3),b:pos(-3),c:pos(1),d:pos(-1),e:pos(0)' --preview 'echo {}/{}'), :Enter + tmux.until { |lines| assert_equal 1000, lines.match_count } + tmux.send_keys :a + tmux.until { |lines| assert_includes lines[1], ' 3/3' } + tmux.send_keys :b + tmux.until { |lines| assert_includes lines[1], ' 998/998' } + tmux.send_keys :c + tmux.until { |lines| assert_includes lines[1], ' 1/1' } + tmux.send_keys :d + tmux.until { |lines| assert_includes lines[1], ' 1000/1000' } + tmux.send_keys :e + tmux.until { |lines| assert_includes lines[1], ' 1/1' } + end + def test_accept_non_empty tmux.send_keys %(seq 1000 | #{fzf('--print-query --bind enter:accept-non-empty')}), :Enter tmux.until { |lines| assert_equal 1000, lines.match_count }