m/fzf
1
0
mirror of https://github.com/junegunn/fzf.git synced 2025-11-16 07:13:48 -05:00

Fix change-nth

* Proper clean-up of caches
* Force rerender list after the action
This commit is contained in:
Junegunn Choi
2025-01-13 12:45:01 +09:00
parent d83eb2800a
commit ba0935c71f
6 changed files with 36 additions and 9 deletions

View File

@@ -379,7 +379,8 @@ func Run(opts *Options) (int, error) {
// Change nth and clear caches // Change nth and clear caches
nth = *val.nth nth = *val.nth
patternCache = make(map[string]*Pattern) patternCache = make(map[string]*Pattern)
inputRevision.bumpMajor() cache.Clear()
inputRevision.bumpMinor()
} }
if command != nil { if command != nil {
useSnapshot = val.sync useSnapshot = val.sync

View File

@@ -6,10 +6,17 @@ import (
"github.com/junegunn/fzf/src/util" "github.com/junegunn/fzf/src/util"
) )
type transformed struct {
// Because nth can be changed dynamically by change-nth action, we need to
// keep the nth value at the time of transformation.
nth []Range
tokens []Token
}
// Item represents each input line. 56 bytes. // Item represents each input line. 56 bytes.
type Item struct { type Item struct {
text util.Chars // 32 = 24 + 1 + 1 + 2 + 4 text util.Chars // 32 = 24 + 1 + 1 + 2 + 4
transformed *[]Token // 8 transformed *transformed // 8
origText *[]byte // 8 origText *[]byte // 8
colors *[]ansiOffset // 8 colors *[]ansiOffset // 8
} }

View File

@@ -393,12 +393,24 @@ func (p *Pattern) extendedMatch(item *Item, withPos bool, slab *util.Slab) ([]Of
func (p *Pattern) transformInput(item *Item) []Token { func (p *Pattern) transformInput(item *Item) []Token {
if item.transformed != nil { if item.transformed != nil {
return *item.transformed transformed := *item.transformed
if len(transformed.nth) == len(p.nth) {
same := true
for idx, rangeItem := range transformed.nth {
if rangeItem != p.nth[idx] {
same = false
break
}
}
if same {
return transformed.tokens
}
}
} }
tokens := Tokenize(item.text.ToString(), p.delimiter) tokens := Tokenize(item.text.ToString(), p.delimiter)
ret := Transform(tokens, p.nth) ret := Transform(tokens, p.nth)
item.transformed = &ret item.transformed = &transformed{p.nth, ret}
return ret return ret
} }

View File

@@ -135,12 +135,12 @@ func TestOrigTextAndTransformed(t *testing.T) {
chunk.items[0] = Item{ chunk.items[0] = Item{
text: util.ToChars([]byte("junegunn")), text: util.ToChars([]byte("junegunn")),
origText: &origBytes, origText: &origBytes,
transformed: &trans} transformed: &transformed{pattern.nth, trans}}
pattern.extended = extended pattern.extended = extended
matches := pattern.matchChunk(&chunk, nil, slab) // No cache matches := pattern.matchChunk(&chunk, nil, slab) // No cache
if !(matches[0].item.text.ToString() == "junegunn" && if !(matches[0].item.text.ToString() == "junegunn" &&
string(*matches[0].item.origText) == "junegunn.choi" && string(*matches[0].item.origText) == "junegunn.choi" &&
reflect.DeepEqual(*matches[0].item.transformed, trans)) { reflect.DeepEqual((*matches[0].item.transformed).tokens, trans)) {
t.Error("Invalid match result", matches) t.Error("Invalid match result", matches)
} }
@@ -148,7 +148,7 @@ func TestOrigTextAndTransformed(t *testing.T) {
if !(match.item.text.ToString() == "junegunn" && if !(match.item.text.ToString() == "junegunn" &&
string(*match.item.origText) == "junegunn.choi" && string(*match.item.origText) == "junegunn.choi" &&
offsets[0][0] == 0 && offsets[0][1] == 5 && offsets[0][0] == 0 && offsets[0][1] == 5 &&
reflect.DeepEqual(*match.item.transformed, trans)) { reflect.DeepEqual((*match.item.transformed).tokens, trans)) {
t.Error("Invalid match result", match, offsets, extended) t.Error("Invalid match result", match, offsets, extended)
} }
if !((*pos)[0] == 4 && (*pos)[1] == 0) { if !((*pos)[0] == 4 && (*pos)[1] == 0) {

View File

@@ -1626,6 +1626,10 @@ func (t *Terminal) adjustMarginAndPadding() (int, int, [4]int, [4]int) {
return screenWidth, screenHeight, marginInt, paddingInt return screenWidth, screenHeight, marginInt, paddingInt
} }
func (t *Terminal) forceRerenderList() {
t.prevLines = make([]itemLine, len(t.prevLines))
}
func (t *Terminal) resizeWindows(forcePreview bool, redrawBorder bool) { func (t *Terminal) resizeWindows(forcePreview bool, redrawBorder bool) {
t.forcePreview = forcePreview t.forcePreview = forcePreview
screenWidth, screenHeight, marginInt, paddingInt := t.adjustMarginAndPadding() screenWidth, screenHeight, marginInt, paddingInt := t.adjustMarginAndPadding()
@@ -4639,6 +4643,7 @@ func (t *Terminal) Loop() error {
if len(tokens) > 1 { if len(tokens) > 1 {
a.a = strings.Join(append(tokens[1:], tokens[0]), "|") a.a = strings.Join(append(tokens[1:], tokens[0]), "|")
} }
t.forceRerenderList()
case actChangeQuery: case actChangeQuery:
t.input = []rune(a.a) t.input = []rune(a.a)
t.cx = len(t.input) t.cx = len(t.input)
@@ -5101,7 +5106,7 @@ func (t *Terminal) Loop() error {
req(reqList) req(reqList)
case actToggleHscroll: case actToggleHscroll:
// Force re-rendering of the list // Force re-rendering of the list
t.prevLines = make([]itemLine, len(t.prevLines)) t.forceRerenderList()
t.hscroll = !t.hscroll t.hscroll = !t.hscroll
req(reqList) req(reqList)
case actTrackCurrent: case actTrackCurrent:

View File

@@ -3721,10 +3721,12 @@ class TestGoFZF < TestBase
def test_change_nth def test_change_nth
input = [ input = [
*[''] * 1000,
'foo bar bar bar bar', 'foo bar bar bar bar',
'foo foo bar bar bar', 'foo foo bar bar bar',
'foo foo foo bar bar', 'foo foo foo bar bar',
'foo foo foo foo bar' 'foo foo foo foo bar',
*[''] * 1000
] ]
writelines(input) writelines(input)
tmux.send_keys %(#{FZF} -qfoo -n1 --bind 'space:change-nth:2|3|4|5|' < #{tempname}), :Enter tmux.send_keys %(#{FZF} -qfoo -n1 --bind 'space:change-nth:2|3|4|5|' < #{tempname}), :Enter