From 76bbf57b3dad4bd29e2f51337de11732a2146e5f Mon Sep 17 00:00:00 2001 From: Junegunn Choi Date: Thu, 25 Feb 2021 21:14:15 +0900 Subject: [PATCH] Add select and deselect actions Close #2358 --- CHANGELOG.md | 6 ++++++ man/man1/fzf.1 | 2 ++ src/options.go | 4 ++++ src/terminal.go | 27 +++++++++++++++++++++++++++ test/test_go.rb | 21 +++++++++++++++++++++ 5 files changed, 60 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d15600..86e530e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ CHANGELOG ========= +0.25.2 +------ +- Added `select` and `deselect` action for unconditinoally selecting or + deselecting a single item in `--multi` mode. Complements `toggle` action. +- Built with Go 1.16 + 0.25.1 ------ - Added `close` action diff --git a/man/man1/fzf.1 b/man/man1/fzf.1 index d29ed54..486a0ad 100644 --- a/man/man1/fzf.1 +++ b/man/man1/fzf.1 @@ -784,6 +784,7 @@ A key or an event can be bound to one or more of the following actions. \fBclear-query\fR (clear query string) \fBdelete-char\fR \fIdel\fR \fBdelete-char/eof\fR \fIctrl-d\fR (same as \fBdelete-char\fR except aborts fzf if query is empty) + \fBdeselect\fR \fBdeselect-all\fR (deselect all matches) \fBdisable-search\fR (disable search functionality) \fBdown\fR \fIctrl-j ctrl-n down\fR @@ -819,6 +820,7 @@ A key or an event can be bound to one or more of the following actions. \fBrefresh-preview\fR \fBreload(...)\fR (see below for the details) \fBreplace-query\fR (replace query string with the current selection) + \fBselect\fR \fBselect-all\fR (select all matches) \fBtoggle\fR (\fIright-click\fR) \fBtoggle-all\fR (toggle all matches) diff --git a/src/options.go b/src/options.go index a55dc34..0e61255 100644 --- a/src/options.go +++ b/src/options.go @@ -839,6 +839,8 @@ func parseKeymap(keymap map[tui.Event][]action, str string) { appendAction(actDeleteChar) case "delete-char/eof": appendAction(actDeleteCharEOF) + case "deselect": + appendAction(actDeselect) case "end-of-line": appendAction(actEndOfLine) case "cancel": @@ -879,6 +881,8 @@ func parseKeymap(keymap map[tui.Event][]action, str string) { appendAction(actToggleAll) case "toggle-search": appendAction(actToggleSearch) + case "select": + appendAction(actSelect) case "select-all": appendAction(actSelectAll) case "deselect-all": diff --git a/src/terminal.go b/src/terminal.go index fa9adb8..2fcaa69 100644 --- a/src/terminal.go +++ b/src/terminal.go @@ -276,6 +276,8 @@ const ( actReload actDisableSearch actEnableSearch + actSelect + actDeselect ) type placeholderFlags struct { @@ -1785,11 +1787,26 @@ func (t *Terminal) selectItem(item *Item) bool { return true } +func (t *Terminal) selectItemChanged(item *Item) bool { + if _, found := t.selected[item.Index()]; found { + return false + } + return t.selectItem(item) +} + func (t *Terminal) deselectItem(item *Item) { delete(t.selected, item.Index()) t.version++ } +func (t *Terminal) deselectItemChanged(item *Item) bool { + if _, found := t.selected[item.Index()]; found { + t.deselectItem(item) + return true + } + return false +} + func (t *Terminal) toggleItem(item *Item) bool { if _, found := t.selected[item.Index()]; !found { return t.selectItem(item) @@ -2341,6 +2358,16 @@ func (t *Terminal) Loop() { } else { req(reqQuit) } + case actSelect: + current := t.currentItem() + if t.multi > 0 && current != nil && t.selectItemChanged(current) { + req(reqList, reqInfo) + } + case actDeselect: + current := t.currentItem() + if t.multi > 0 && current != nil && t.deselectItemChanged(current) { + req(reqList, reqInfo) + } case actToggle: if t.multi > 0 && t.merger.Length() > 0 && toggle() { req(reqList) diff --git a/test/test_go.rb b/test/test_go.rb index a6651c2..a39cb5f 100755 --- a/test/test_go.rb +++ b/test/test_go.rb @@ -1890,6 +1890,27 @@ class TestGoFZF < TestBase tmux.send_keys 'C-l', 'closed' tmux.until { |lines| assert_includes lines[0], 'closed' } end + + def test_select_deselect + tmux.send_keys "seq 3 | #{FZF} --multi --bind up:deselect+up,down:select+down", :Enter + tmux.until { |lines| assert_equal 3, lines.match_count } + tmux.send_keys :Tab + tmux.until { |lines| assert_equal 1, lines.select_count } + tmux.send_keys :Up + tmux.until { |lines| assert_equal 0, lines.select_count } + tmux.send_keys :Down, :Down + tmux.until { |lines| assert_equal 2, lines.select_count } + tmux.send_keys :Tab + tmux.until { |lines| assert_equal 1, lines.select_count } + tmux.send_keys :Down, :Down + tmux.until { |lines| assert_equal 2, lines.select_count } + tmux.send_keys :Up + tmux.until { |lines| assert_equal 1, lines.select_count } + tmux.send_keys :Down + tmux.until { |lines| assert_equal 1, lines.select_count } + tmux.send_keys :Down + tmux.until { |lines| assert_equal 2, lines.select_count } + end end module TestShell