summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJunegunn Choi <junegunn.c@gmail.com>2023-04-22 23:39:35 +0900
committerJunegunn Choi <junegunn.c@gmail.com>2023-04-22 23:42:09 +0900
commit65dd2bb42947d4ede31d160214f3a4c6fdc619e1 (patch)
tree8f5744ddc7d0ab91983fdf6df28d96d253b2aa54
parent6be855be6af102a0f89932e5752ce75aa9713108 (diff)
Add 'track' action
-rw-r--r--CHANGELOG.md16
-rw-r--r--man/man1/fzf.17
-rw-r--r--src/options.go18
-rw-r--r--src/terminal.go27
-rwxr-xr-xtest/test_go.rb42
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'