Fix track-current unset after a combined movement action

Fix #4649
Close #4663
This commit is contained in:
Junegunn Choi
2026-01-26 11:16:59 +09:00
parent 25b2248f11
commit b389616030
3 changed files with 57 additions and 20 deletions
+23 -5
View File
@@ -292,14 +292,32 @@ func defaultMargin() [4]sizeSpec {
return [4]sizeSpec{} return [4]sizeSpec{}
} }
type trackOption int type trackOption struct {
enabled bool
index int32
}
const ( var (
trackDisabled trackOption = iota trackDisabled = trackOption{false, minItem.Index()}
trackEnabled trackEnabled = trackOption{true, minItem.Index()}
trackCurrent
) )
func (t trackOption) Disabled() bool {
return !t.enabled
}
func (t trackOption) Global() bool {
return t.enabled && t.index == minItem.Index()
}
func (t trackOption) Current() bool {
return t.enabled && t.index != minItem.Index()
}
func trackCurrent(index int32) trackOption {
return trackOption{true, index}
}
type windowPosition int type windowPosition int
const ( const (
+12 -13
View File
@@ -1816,7 +1816,7 @@ func (t *Terminal) UpdateList(result MatchResult) {
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 { } else if t.track.Current() {
t.track = trackDisabled t.track = trackDisabled
t.cy = pos t.cy = pos
t.offset = 0 t.offset = 0
@@ -2886,10 +2886,9 @@ func (t *Terminal) printInfoImpl() {
output += " -S" output += " -S"
} }
} }
switch t.track { if t.track.Global() {
case trackEnabled:
output += " +T" output += " +T"
case trackCurrent: } else if t.track.Current() {
output += " +t" output += " +t"
} }
if t.multi > 0 { if t.multi > 0 {
@@ -5471,11 +5470,11 @@ func (t *Terminal) Loop() error {
case reqList: case reqList:
t.printList() t.printList()
currentIndex := t.currentIndex() currentIndex := t.currentIndex()
focusChanged := focusedIndex != currentIndex if t.track.Current() && t.track.index != currentIndex {
if focusChanged && focusedIndex >= 0 && t.track == trackCurrent {
t.track = trackDisabled t.track = trackDisabled
info = true info = true
} }
focusChanged := focusedIndex != currentIndex
if (t.hasFocusActions || t.infoCommand != "") && focusChanged && currentIndex != t.lastFocus { if (t.hasFocusActions || t.infoCommand != "") && focusChanged && currentIndex != t.lastFocus {
t.lastFocus = currentIndex t.lastFocus = currentIndex
t.eventChan <- tui.Focus.AsEvent() t.eventChan <- tui.Focus.AsEvent()
@@ -6550,11 +6549,10 @@ func (t *Terminal) Loop() error {
} }
req(reqInfo) req(reqInfo)
case actToggleTrackCurrent: case actToggleTrackCurrent:
switch t.track { if t.track.Current() {
case trackCurrent:
t.track = trackDisabled t.track = trackDisabled
case trackDisabled: } else if t.track.Disabled() {
t.track = trackCurrent t.track = trackCurrent(t.currentIndex())
} }
req(reqInfo) req(reqInfo)
case actShowHeader: case actShowHeader:
@@ -6602,12 +6600,13 @@ func (t *Terminal) Loop() error {
} }
req(reqList, reqInfo, reqPrompt, reqHeader) req(reqList, reqInfo, reqPrompt, reqHeader)
case actTrackCurrent: case actTrackCurrent:
if t.track == trackDisabled { // Global tracking has higher priority
t.track = trackCurrent if !t.track.Global() {
t.track = trackCurrent(t.currentIndex())
} }
req(reqInfo) req(reqInfo)
case actUntrackCurrent: case actUntrackCurrent:
if t.track == trackCurrent { if t.track.Current() {
t.track = trackDisabled t.track = trackDisabled
} }
req(reqInfo) req(reqInfo)
+22 -2
View File
@@ -1588,14 +1588,16 @@ class TestCore < TestInteractive
end end
def test_track_action def test_track_action
tmux.send_keys "seq 1000 | #{FZF} --query 555 --bind t:track", :Enter tmux.send_keys "seq 1000 | #{FZF} --pointer x --query 555 --bind t:track,T:up+track", :Enter
tmux.until do |lines| tmux.until do |lines|
assert_equal 1, lines.match_count assert_equal 1, lines.match_count
assert_includes lines, 'x 555'
assert_includes lines, '> 555' assert_includes lines, '> 555'
end end
tmux.send_keys :BSpace tmux.send_keys :BSpace
tmux.until do |lines| tmux.until do |lines|
assert_equal 28, lines.match_count assert_equal 28, lines.match_count
assert_includes lines, 'x 55'
assert_includes lines, '> 55' assert_includes lines, '> 55'
end end
tmux.send_keys :t tmux.send_keys :t
@@ -1605,7 +1607,8 @@ class TestCore < TestInteractive
tmux.send_keys :BSpace tmux.send_keys :BSpace
tmux.until do |lines| tmux.until do |lines|
assert_equal 271, lines.match_count assert_equal 271, lines.match_count
assert_includes lines, '> 55' assert_includes lines, 'x 55'
assert_includes lines, '> 5'
end end
# Automatically disabled when the tracking item is no longer visible # Automatically disabled when the tracking item is no longer visible
@@ -1617,16 +1620,33 @@ class TestCore < TestInteractive
tmux.send_keys :BSpace tmux.send_keys :BSpace
tmux.until do |lines| tmux.until do |lines|
assert_equal 271, lines.match_count assert_equal 271, lines.match_count
assert_includes lines, 'x 52'
assert_includes lines, '> 5' assert_includes lines, '> 5'
end end
tmux.send_keys :t tmux.send_keys :t
tmux.until do |lines| tmux.until do |lines|
assert_includes lines[-2], '+t' assert_includes lines[-2], '+t'
end end
# Automatically disabled when the focus has moved
tmux.send_keys :Up tmux.send_keys :Up
tmux.until do |lines| tmux.until do |lines|
assert_includes lines, 'x 53'
refute_includes lines[-2], '+t' refute_includes lines[-2], '+t'
end end
# Should work even when combined with a focus moving actions
tmux.send_keys 'T'
tmux.until do |lines|
assert_includes lines, 'x 54'
assert_includes lines[-2], '+t'
end
tmux.send_keys 'T'
tmux.until do |lines|
assert_includes lines, 'x 55'
assert_includes lines[-2], '+t'
end
end end
def test_one_and_zero def test_one_and_zero