Add 'track' action

pull/3261/head
Junegunn Choi 1 year ago
parent 6be855be6a
commit 65dd2bb429
No known key found for this signature in database
GPG Key ID: 254BC280FEF9C627

@ -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.

@ -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)

@ -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":

@ -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

@ -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'

Loading…
Cancel
Save