Add 'track' action

This commit is contained in:
Junegunn Choi 2023-04-22 23:39:35 +09:00
parent 6be855be6a
commit 65dd2bb429
No known key found for this signature in database
GPG Key ID: 254BC280FEF9C627
5 changed files with 96 additions and 14 deletions

View File

@ -4,19 +4,25 @@ CHANGELOG
0.40.0 0.40.0
------ ------
- New actions - New actions
- Added `change-header(...)` - Added `track` action which makes fzf track the current item when the
- Added `transform-header(...)` search result is updated. If the user manually moves the cursor, or the
- Added `toggle-track` action. Temporarily enabling tracking is useful when item is not in the updated search result, tracking is automatically
you want to see the surrounding items by deleting the query string. disabled. Tracking is useful when you want to see the surrounding items
by deleting the query string.
```sh ```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=" export FZF_CTRL_R_OPTS="
--preview 'echo {}' --preview-window up:3:hidden:wrap --preview 'echo {}' --preview-window up:3:hidden:wrap
--bind 'ctrl-/:toggle-preview' --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' --bind 'ctrl-y:execute-silent(echo -n {2..} | pbcopy)+abort'
--color header:italic --color header:italic
--header 'Press CTRL-Y to copy command into clipboard'" --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` - Fixed `--track` behavior when used with `--tac`
- However, using `--track` with `--tac` is not recommended. The resulting - However, using `--track` with `--tac` is not recommended. The resulting
behavior can be very confusing. behavior can be very confusing.

View File

@ -94,7 +94,10 @@ Do not sort the result
.TP .TP
.B "--track" .B "--track"
Make fzf track the current selection when the result list is updated. 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 .RS
e.g. 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-preview-wrap\fR
\fBtoggle-search\fR (toggle search functionality) \fBtoggle-search\fR (toggle search functionality)
\fBtoggle-sort\fR \fBtoggle-sort\fR
\fBtoggle-track\fR
\fBtoggle+up\fR \fIbtab (shift-tab)\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-border-label(...)\fR (transform border label using an external command)
\fBtransform-header(...)\fR (transform header using an external command) \fBtransform-header(...)\fR (transform header using an external command)
\fBtransform-preview-label(...)\fR (transform preview label using an external command) \fBtransform-preview-label(...)\fR (transform preview label using an external command)

View File

@ -165,6 +165,14 @@ func defaultMargin() [4]sizeSpec {
return [4]sizeSpec{} return [4]sizeSpec{}
} }
type trackOption int
const (
trackDisabled trackOption = iota
trackEnabled
trackCurrent
)
type windowPosition int type windowPosition int
const ( const (
@ -267,7 +275,7 @@ type Options struct {
WithNth []Range WithNth []Range
Delimiter Delimiter Delimiter Delimiter
Sort int Sort int
Track bool Track trackOption
Tac bool Tac bool
Criteria []criterion Criteria []criterion
Multi int Multi int
@ -340,7 +348,7 @@ func defaultOptions() *Options {
WithNth: make([]Range, 0), WithNth: make([]Range, 0),
Delimiter: Delimiter{}, Delimiter: Delimiter{},
Sort: 1000, Sort: 1000,
Track: false, Track: trackDisabled,
Tac: false, Tac: false,
Criteria: []criterion{byScore, byLength}, Criteria: []criterion{byScore, byLength},
Multi: 0, Multi: 0,
@ -1085,6 +1093,8 @@ func parseActionList(masked string, original string, prevActions []*action, putA
appendAction(actToggleSearch) appendAction(actToggleSearch)
case "toggle-track": case "toggle-track":
appendAction(actToggleTrack) appendAction(actToggleTrack)
case "track":
appendAction(actTrack)
case "select": case "select":
appendAction(actSelect) appendAction(actSelect)
case "select-all": case "select-all":
@ -1574,9 +1584,9 @@ func parseOptions(opts *Options, allArgs []string) {
case "+s", "--no-sort": case "+s", "--no-sort":
opts.Sort = 0 opts.Sort = 0
case "--track": case "--track":
opts.Track = true opts.Track = trackEnabled
case "--no-track": case "--no-track":
opts.Track = false opts.Track = trackDisabled
case "--tac": case "--tac":
opts.Tac = true opts.Tac = true
case "--no-tac": case "--no-tac":

View File

@ -184,7 +184,7 @@ type Terminal struct {
multi int multi int
sort bool sort bool
toggleSort bool toggleSort bool
track bool track trackOption
delimiter Delimiter delimiter Delimiter
expect map[tui.Event]string expect map[tui.Event]string
keymap map[tui.Event][]*action keymap map[tui.Event][]*action
@ -340,6 +340,7 @@ const (
actToggleIn actToggleIn
actToggleOut actToggleOut
actToggleTrack actToggleTrack
actTrack
actDown actDown
actUp actUp
actPageUp actPageUp
@ -922,7 +923,7 @@ func (t *Terminal) UpdateProgress(progress float32) {
func (t *Terminal) UpdateList(merger *Merger, reset bool) { func (t *Terminal) UpdateList(merger *Merger, reset bool) {
t.mutex.Lock() t.mutex.Lock()
var prevIndex int32 = -1 var prevIndex int32 = -1
if !reset && t.track { if !reset && t.track != trackDisabled {
if t.merger.Length() > 0 { if t.merger.Length() > 0 {
prevIndex = t.merger.Get(t.cy).item.Index() prevIndex = t.merger.Get(t.cy).item.Index()
} else if merger.Length() > 0 { } else if merger.Length() > 0 {
@ -946,6 +947,10 @@ func (t *Terminal) UpdateList(merger *Merger, reset bool) {
if i >= 0 { if i >= 0 {
t.cy = i t.cy = i
t.offset = t.cy - pos t.offset = t.cy - pos
} else if t.track == trackCurrent {
t.track = trackDisabled
t.cy = pos
t.offset = 0
} else if t.cy > count { } else if t.cy > count {
// Try to keep the vertical position when the list shrinks // Try to keep the vertical position when the list shrinks
t.cy = count - util.Min(count, t.maxItems()) + pos t.cy = count - util.Min(count, t.maxItems()) + pos
@ -1479,7 +1484,7 @@ func (t *Terminal) printInfo() {
output += " -S" output += " -S"
} }
} }
if t.track { if t.track != trackDisabled {
output += " +T" output += " +T"
} }
if t.multi > 0 { if t.multi > 0 {
@ -2733,6 +2738,10 @@ func (t *Terminal) Loop() {
currentIndex = currentItem.Index() currentIndex = currentItem.Index()
} }
focusChanged := focusedIndex != currentIndex focusChanged := focusedIndex != currentIndex
if focusChanged && t.track == trackCurrent {
t.track = trackDisabled
t.printInfo()
}
if onFocus != nil && focusChanged { if onFocus != nil && focusChanged {
t.serverChan <- onFocus t.serverChan <- onFocus
} }
@ -3311,7 +3320,17 @@ func (t *Terminal) Loop() {
changed = !t.paused changed = !t.paused
req(reqPrompt) req(reqPrompt)
case actToggleTrack: 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) req(reqInfo)
case actEnableSearch: case actEnableSearch:
t.paused = false t.paused = false

View File

@ -2793,6 +2793,48 @@ class TestGoFZF < TestBase
end end
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 def test_one
tmux.send_keys "seq 10 | #{FZF} --bind 'one:preview:echo {} is the only match'", :Enter tmux.send_keys "seq 10 | #{FZF} --bind 'one:preview:echo {} is the only match'", :Enter
tmux.send_keys '1' tmux.send_keys '1'