diff options
author | Junegunn Choi <junegunn.c@gmail.com> | 2023-04-22 23:39:35 +0900 |
---|---|---|
committer | Junegunn Choi <junegunn.c@gmail.com> | 2023-04-22 23:42:09 +0900 |
commit | 65dd2bb42947d4ede31d160214f3a4c6fdc619e1 (patch) | |
tree | 8f5744ddc7d0ab91983fdf6df28d96d253b2aa54 | |
parent | 6be855be6af102a0f89932e5752ce75aa9713108 (diff) |
Add 'track' action
-rw-r--r-- | CHANGELOG.md | 16 | ||||
-rw-r--r-- | man/man1/fzf.1 | 7 | ||||
-rw-r--r-- | src/options.go | 18 | ||||
-rw-r--r-- | src/terminal.go | 27 | ||||
-rwxr-xr-x | test/test_go.rb | 42 |
5 files changed, 96 insertions, 14 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 594c5a51..4232d688 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,19 +4,25 @@ CHANGELOG 0.40.0 ------ - New actions - - Added `change-header(...)` - - Added `transform-header(...)` - - Added `toggle-track` action. Temporarily enabling tracking is useful when - you want to see the surrounding items by deleting the query string. + - Added `track` action which makes fzf track the current item when the + search result is updated. If the user manually moves the cursor, or the + item is not in the updated search result, tracking is automatically + disabled. Tracking is useful when you want to see the surrounding items + by deleting the query string. ```sh + # Narrow down the list with a query, point to a command, + # and hit CTRL-T to see its surrounding commands. export FZF_CTRL_R_OPTS=" --preview 'echo {}' --preview-window up:3:hidden:wrap --bind 'ctrl-/:toggle-preview' - --bind 'ctrl-t:toggle-track' + --bind 'ctrl-t:track+clear-query' --bind 'ctrl-y:execute-silent(echo -n {2..} | pbcopy)+abort' --color header:italic --header 'Press CTRL-Y to copy command into clipboard'" ``` + - Added `change-header(...)` + - Added `transform-header(...)` + - Added `toggle-track` action - Fixed `--track` behavior when used with `--tac` - However, using `--track` with `--tac` is not recommended. The resulting behavior can be very confusing. diff --git a/man/man1/fzf.1 b/man/man1/fzf.1 index acdde33e..0d706751 100644 --- a/man/man1/fzf.1 +++ b/man/man1/fzf.1 @@ -94,7 +94,10 @@ Do not sort the result .TP .B "--track" Make fzf track the current selection when the result list is updated. -This can be useful when browsing logs using fzf with sorting disabled. +This can be useful when browsing logs using fzf with sorting disabled. It is +not recommended to use this option with \fB--tac\fR as the resulting behavior +can be confusing. Also, consider using \fBtrack\fR action instead of this +option. .RS e.g. @@ -1099,7 +1102,9 @@ A key or an event can be bound to one or more of the following actions. \fBtoggle-preview-wrap\fR \fBtoggle-search\fR (toggle search functionality) \fBtoggle-sort\fR + \fBtoggle-track\fR \fBtoggle+up\fR \fIbtab (shift-tab)\fR + \fBtrack\fR (track the current item; automatically disabled if focus changes) \fBtransform-border-label(...)\fR (transform border label using an external command) \fBtransform-header(...)\fR (transform header using an external command) \fBtransform-preview-label(...)\fR (transform preview label using an external command) diff --git a/src/options.go b/src/options.go index 3718cf5a..e0a5caf6 100644 --- a/src/options.go +++ b/src/options.go @@ -165,6 +165,14 @@ func defaultMargin() [4]sizeSpec { return [4]sizeSpec{} } +type trackOption int + +const ( + trackDisabled trackOption = iota + trackEnabled + trackCurrent +) + type windowPosition int const ( @@ -267,7 +275,7 @@ type Options struct { WithNth []Range Delimiter Delimiter Sort int - Track bool + Track trackOption Tac bool Criteria []criterion Multi int @@ -340,7 +348,7 @@ func defaultOptions() *Options { WithNth: make([]Range, 0), Delimiter: Delimiter{}, Sort: 1000, - Track: false, + Track: trackDisabled, Tac: false, Criteria: []criterion{byScore, byLength}, Multi: 0, @@ -1085,6 +1093,8 @@ func parseActionList(masked string, original string, prevActions []*action, putA appendAction(actToggleSearch) case "toggle-track": appendAction(actToggleTrack) + case "track": + appendAction(actTrack) case "select": appendAction(actSelect) case "select-all": @@ -1574,9 +1584,9 @@ func parseOptions(opts *Options, allArgs []string) { case "+s", "--no-sort": opts.Sort = 0 case "--track": - opts.Track = true + opts.Track = trackEnabled case "--no-track": - opts.Track = false + opts.Track = trackDisabled case "--tac": opts.Tac = true case "--no-tac": diff --git a/src/terminal.go b/src/terminal.go index e3403a40..47991a65 100644 --- a/src/terminal.go +++ b/src/terminal.go @@ -184,7 +184,7 @@ type Terminal struct { multi int sort bool toggleSort bool - track bool + track trackOption delimiter Delimiter expect map[tui.Event]string keymap map[tui.Event][]*action @@ -340,6 +340,7 @@ const ( actToggleIn actToggleOut actToggleTrack + actTrack actDown actUp actPageUp @@ -922,7 +923,7 @@ func (t *Terminal) UpdateProgress(progress float32) { func (t *Terminal) UpdateList(merger *Merger, reset bool) { t.mutex.Lock() var prevIndex int32 = -1 - if !reset && t.track { + if !reset && t.track != trackDisabled { if t.merger.Length() > 0 { prevIndex = t.merger.Get(t.cy).item.Index() } else if merger.Length() > 0 { @@ -946,6 +947,10 @@ func (t *Terminal) UpdateList(merger *Merger, reset bool) { if i >= 0 { t.cy = i t.offset = t.cy - pos + } else if t.track == trackCurrent { + t.track = trackDisabled + t.cy = pos + t.offset = 0 } else if t.cy > count { // Try to keep the vertical position when the list shrinks t.cy = count - util.Min(count, t.maxItems()) + pos @@ -1479,7 +1484,7 @@ func (t *Terminal) printInfo() { output += " -S" } } - if t.track { + if t.track != trackDisabled { output += " +T" } if t.multi > 0 { @@ -2733,6 +2738,10 @@ func (t *Terminal) Loop() { currentIndex = currentItem.Index() } focusChanged := focusedIndex != currentIndex + if focusChanged && t.track == trackCurrent { + t.track = trackDisabled + t.printInfo() + } if onFocus != nil && focusChanged { t.serverChan <- onFocus } @@ -3311,7 +3320,17 @@ func (t *Terminal) Loop() { changed = !t.paused req(reqPrompt) case actToggleTrack: - t.track = !t.track + switch t.track { + case trackEnabled: + t.track = trackDisabled + case trackDisabled: + t.track = trackEnabled + } + req(reqInfo) + case actTrack: + if t.track == trackDisabled { + t.track = trackCurrent + } req(reqInfo) case actEnableSearch: t.paused = false diff --git a/test/test_go.rb b/test/test_go.rb index 34884550..fc0b9e04 100755 --- a/test/test_go.rb +++ b/test/test_go.rb @@ -2793,6 +2793,48 @@ class TestGoFZF < TestBase end end + def test_track_action + tmux.send_keys "seq 1000 | #{FZF} --query 555 --bind t:track", :Enter + tmux.until do |lines| + assert_equal 1, lines.match_count + assert_includes lines, '> 555' + end + tmux.send_keys :BSpace + tmux.until do |lines| + assert_equal 28, lines.match_count + assert_includes lines, '> 55' + end + tmux.send_keys :t + tmux.until do |lines| + assert_includes lines[-2], '+T' + end + tmux.send_keys :BSpace + tmux.until do |lines| + assert_equal 271, lines.match_count + assert_includes lines, '> 55' + end + + # Automatically disabled when the tracking item is no longer visible + tmux.send_keys '4' + tmux.until do |lines| + assert_equal 28, lines.match_count + refute_includes lines[-2], '+T' + end + tmux.send_keys :BSpace + tmux.until do |lines| + assert_equal 271, lines.match_count + assert_includes lines, '> 5' + end + tmux.send_keys :t + tmux.until do |lines| + assert_includes lines[-2], '+T' + end + tmux.send_keys :Up + tmux.until do |lines| + refute_includes lines[-2], '+T' + end + end + def test_one tmux.send_keys "seq 10 | #{FZF} --bind 'one:preview:echo {} is the only match'", :Enter tmux.send_keys '1' |