summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJunegunn Choi <junegunn.c@gmail.com>2023-03-29 20:36:09 +0900
committerJunegunn Choi <junegunn.c@gmail.com>2023-04-01 12:59:44 +0900
commit1c7534f00966edca7c44054af199ca27aca0a80c (patch)
tree58ec99c05fc552f69ce05dc8160d70324254e6fd
parentae745d9397bdc8b91f3c1834def3b8ecb0ae57b1 (diff)
Add --track option to track the current selection
Close #3186 Related #1890
-rw-r--r--CHANGELOG.md7
-rw-r--r--man/man1/fzf.110
-rw-r--r--src/merger.go17
-rw-r--r--src/options.go7
-rw-r--r--src/terminal.go18
-rwxr-xr-xtest/test_go.rb23
6 files changed, 81 insertions, 1 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index fe1bf3e0..c776f413 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,13 @@ CHANGELOG
0.39.0
------
+- Added `--track` option that makes fzf track the current selection when the
+ result list is updated. This can be useful when browsing logs using fzf with
+ sorting disabled.
+ ```sh
+ git log --oneline --graph --color=always | nl |
+ fzf --ansi --track --no-sort --layout=reverse-list
+ ```
- If you use `--listen` option without a port number fzf will automatically
allocate an available port and export it as `$FZF_PORT` environment
variable.
diff --git a/man/man1/fzf.1 b/man/man1/fzf.1
index a538a91c..7d5ea73e 100644
--- a/man/man1/fzf.1
+++ b/man/man1/fzf.1
@@ -92,6 +92,16 @@ interface rather than a "fuzzy finder". You can later enable the search using
.B "+s, --no-sort"
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.
+
+.RS
+e.g.
+ \fBgit log --oneline --graph --color=always | nl |
+ fzf --ansi --track --no-sort --layout=reverse-list\fR
+.RE
+.TP
.B "--tac"
Reverse the order of the input
diff --git a/src/merger.go b/src/merger.go
index 8e6a884c..cdf00acc 100644
--- a/src/merger.go
+++ b/src/merger.go
@@ -17,6 +17,7 @@ type Merger struct {
tac bool
final bool
count int
+ pass bool
}
// PassMerger returns a new Merger that simply returns the items in the
@@ -26,7 +27,8 @@ func PassMerger(chunks *[]*Chunk, tac bool) *Merger {
pattern: nil,
chunks: chunks,
tac: tac,
- count: 0}
+ count: 0,
+ pass: true}
for _, chunk := range *mg.chunks {
mg.count += chunk.count
@@ -58,6 +60,19 @@ func (mg *Merger) Length() int {
return mg.count
}
+// FindIndex returns the index of the item with the given item index
+func (mg *Merger) FindIndex(itemIndex int32) int {
+ if mg.pass {
+ return int(itemIndex)
+ }
+ for i := 0; i < mg.count; i++ {
+ if mg.Get(i).item.Index() == itemIndex {
+ return i
+ }
+ }
+ return -1
+}
+
// Get returns the pointer to the Result object indexed by the given integer
func (mg *Merger) Get(idx int) Result {
if mg.chunks != nil {
diff --git a/src/options.go b/src/options.go
index 9f953bda..36ca7710 100644
--- a/src/options.go
+++ b/src/options.go
@@ -33,6 +33,7 @@ const usage = `usage: fzf [options]
field index expressions
-d, --delimiter=STR Field delimiter regex (default: AWK-style)
+s, --no-sort Do not sort the result
+ --track Track the current selection when the result is updated
--tac Reverse the order of the input
--disabled Do not perform search
--tiebreak=CRI[,..] Comma-separated list of sort criteria to apply
@@ -266,6 +267,7 @@ type Options struct {
WithNth []Range
Delimiter Delimiter
Sort int
+ Track bool
Tac bool
Criteria []criterion
Multi int
@@ -338,6 +340,7 @@ func defaultOptions() *Options {
WithNth: make([]Range, 0),
Delimiter: Delimiter{},
Sort: 1000,
+ Track: false,
Tac: false,
Criteria: []criterion{byScore, byLength},
Multi: 0,
@@ -1562,6 +1565,10 @@ func parseOptions(opts *Options, allArgs []string) {
opts.Sort = optionalNumeric(allArgs, &i, 1)
case "+s", "--no-sort":
opts.Sort = 0
+ case "--track":
+ opts.Track = true
+ case "--no-track":
+ opts.Track = false
case "--tac":
opts.Tac = true
case "--no-tac":
diff --git a/src/terminal.go b/src/terminal.go
index 468b90f8..57ff4f54 100644
--- a/src/terminal.go
+++ b/src/terminal.go
@@ -183,6 +183,7 @@ type Terminal struct {
multi int
sort bool
toggleSort bool
+ track bool
delimiter Delimiter
expect map[tui.Event]string
keymap map[tui.Event][]*action
@@ -599,6 +600,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal {
multi: opts.Multi,
sort: opts.Sort > 0,
toggleSort: opts.ToggleSort,
+ track: opts.Track,
delimiter: opts.Delimiter,
expect: opts.Expect,
keymap: opts.Keymap,
@@ -904,6 +906,10 @@ func (t *Terminal) UpdateProgress(progress float32) {
// UpdateList updates Merger to display the list
func (t *Terminal) UpdateList(merger *Merger, reset bool) {
t.mutex.Lock()
+ var prevIndex int32 = -1
+ if !reset && t.track && t.merger.Length() > 0 {
+ prevIndex = t.merger.Get(t.cy).item.Index()
+ }
t.progress = 100
t.merger = merger
if reset {
@@ -914,6 +920,18 @@ func (t *Terminal) UpdateList(merger *Merger, reset bool) {
t.triggerLoad = false
t.eventChan <- tui.Load.AsEvent()
}
+ if prevIndex >= 0 {
+ pos := t.cy - t.offset
+ count := t.merger.Length()
+ i := t.merger.FindIndex(prevIndex)
+ if i >= 0 {
+ t.cy = i
+ t.offset = t.cy - pos
+ } else if t.cy > count {
+ // Try to keep the vertical position when the list shrinks
+ t.cy = count - util.Min(count, t.maxItems()) + pos
+ }
+ }
t.mutex.Unlock()
t.reqBox.Set(reqInfo, nil)
t.reqBox.Set(reqList, nil)
diff --git a/test/test_go.rb b/test/test_go.rb
index 8da6cb5e..1556c73b 100755
--- a/test/test_go.rb
+++ b/test/test_go.rb
@@ -2679,6 +2679,29 @@ class TestGoFZF < TestBase
OUTPUT
tmux.until { assert_block(expected, _1) }
end
+
+ def test_track
+ tmux.send_keys "seq 1000 | #{FZF} --query 555 --track", :Enter
+ tmux.until do |lines|
+ assert_equal 1, lines.match_count
+ assert_includes lines, '> 555'
+ end
+ tmux.send_keys :BSpace
+ index = tmux.until do |lines|
+ assert_equal 28, lines.match_count
+ assert_includes lines, '> 555'
+ end.index('> 555')
+ tmux.send_keys :BSpace
+ tmux.until do |lines|
+ assert_equal 271, lines.match_count
+ assert_equal '> 555', lines[index]
+ end
+ tmux.send_keys :BSpace
+ tmux.until do |lines|
+ assert_equal 1000, lines.match_count
+ assert_equal '> 555', lines[index]
+ end
+ end
end
module TestShell