mirror of
https://github.com/Llewellynvdm/fzf.git
synced 2025-02-02 20:18:31 +00:00
Add 'track' action
This commit is contained in:
parent
6be855be6a
commit
65dd2bb429
16
CHANGELOG.md
16
CHANGELOG.md
@ -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.
|
||||||
|
@ -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)
|
||||||
|
@ -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":
|
||||||
|
@ -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
|
||||||
|
@ -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'
|
||||||
|
Loading…
x
Reference in New Issue
Block a user