diff --git a/man/man1/fzf.1 b/man/man1/fzf.1 index 3adf7f1..9f17177 100644 --- a/man/man1/fzf.1 +++ b/man/man1/fzf.1 @@ -635,12 +635,23 @@ e.g. or any single character .SS AVAILABLE EVENTS: -\fIchange\fR (triggered whenever the query string is changed) -.br +\fIchange\fR +.RS +Triggered whenever the query string is changed - e.g. - \fB# Moves cursor to the top (or bottom depending on --layout) whenever the query is changed - fzf --bind change:top\fR +e.g. + \fB# Moves cursor to the top (or bottom depending on --layout) whenever the query is changed + fzf --bind change:top\fR +.RE + +\fIbackward-eof\fR +.RS +Triggered when the query string is already empty and you try to delete it +backward. + +e.g. + \fBfzf --bind backward-eof:abort\fR +.RE .SS AVAILABLE ACTIONS: A key or an event can be bound to one or more of the following actions. diff --git a/src/options.go b/src/options.go index 32c50af..2979da6 100644 --- a/src/options.go +++ b/src/options.go @@ -464,6 +464,8 @@ func parseKeyChords(str string, message string) map[int]string { chord = tui.CtrlRightBracket case "change": chord = tui.Change + case "backward-eof": + chord = tui.BackwardEOF case "alt-enter", "alt-return": chord = tui.CtrlAltM case "alt-space": diff --git a/src/terminal.go b/src/terminal.go index 7bc7939..a5dfe49 100644 --- a/src/terminal.go +++ b/src/terminal.go @@ -1738,6 +1738,7 @@ func (t *Terminal) Loop() { for looping { var newCommand *string changed := false + beof := false queryChanged := false event := t.tui.GetChar() @@ -1881,6 +1882,7 @@ func (t *Terminal) Loop() { t.cx++ } case actBackwardDeleteChar: + beof = len(t.input) == 0 if t.cx > 0 { t.input = append(t.input[:t.cx-1], t.input[t.cx:]...) t.cx-- @@ -1973,16 +1975,19 @@ func (t *Terminal) Loop() { t.vset(0) req(reqList) case actUnixLineDiscard: + beof = len(t.input) == 0 if t.cx > 0 { t.yanked = copySlice(t.input[:t.cx]) t.input = t.input[t.cx:] t.cx = 0 } case actUnixWordRubout: + beof = len(t.input) == 0 if t.cx > 0 { t.rubout("\\s\\S") } case actBackwardKillWord: + beof = len(t.input) == 0 if t.cx > 0 { t.rubout(t.wordRubout) } @@ -2145,6 +2150,11 @@ func (t *Terminal) Loop() { continue } } + if onEOFs, prs := t.keymap[tui.BackwardEOF]; beof && prs { + if !doActions(onEOFs, tui.BackwardEOF) { + continue + } + } } else { if mapkey == tui.Rune { if idx := strings.IndexRune(t.jumpLabels, event.Char); idx >= 0 && idx < t.maxItems() && idx < t.merger.Length() { diff --git a/src/tui/tui.go b/src/tui/tui.go index f5ebb16..3ed794f 100644 --- a/src/tui/tui.go +++ b/src/tui/tui.go @@ -87,6 +87,7 @@ const ( F12 Change + BackwardEOF AltSpace AltSlash diff --git a/test/test_go.rb b/test/test_go.rb index e7a7dd6..2b865ea 100755 --- a/test/test_go.rb +++ b/test/test_go.rb @@ -1746,6 +1746,17 @@ class TestGoFZF < TestBase tmux.send_keys "seq 10000 | #{FZF} --read0 --keep-right", :Enter tmux.until { |lines| assert lines.any_include?('9999 10000') } end + + def test_backward_eof + tmux.send_keys "echo foo | #{FZF} --bind 'backward-eof:reload(seq 100)'", :Enter + tmux.until { |lines| lines.item_count == 1 && lines.match_count == 1 } + tmux.send_keys 'x' + tmux.until { |lines| lines.item_count == 1 && lines.match_count == 0 } + tmux.send_keys :BSpace + tmux.until { |lines| lines.item_count == 1 && lines.match_count == 1 } + tmux.send_keys :BSpace + tmux.until { |lines| lines.item_count == 100 && lines.match_count == 100 } + end end module TestShell