mirror of
https://github.com/junegunn/fzf
synced 2026-07-28 17:51:42 +00:00
Fix nondeterministic highlight positions in FuzzyMatchV2 backtrace
Phase 3 writes C rows only from column F[r], but tie-breaking in the backtrace could read row i+1 at column j+1 left of F[i+1]. With reused slab, that cell holds data from previously processed item, so highlight positions in equal-score ties depended on processing order.
This commit is contained in:
+5
-1
@@ -630,6 +630,7 @@ func FuzzyMatchV2(caseSensitive bool, normalize bool, forward bool, input *util.
|
||||
s2 = H[I+j0-1]
|
||||
}
|
||||
|
||||
row := i
|
||||
if s > s1 && (s > s2 || s == s2 && preferMatch) {
|
||||
*pos = append(*pos, j+minIdx)
|
||||
if i == 0 {
|
||||
@@ -637,7 +638,10 @@ func FuzzyMatchV2(caseSensitive bool, normalize bool, forward bool, input *util.
|
||||
}
|
||||
i--
|
||||
}
|
||||
preferMatch = C[I+j0] > 1 || I+width+j0+1 < len(C) && C[I+width+j0+1] > 0
|
||||
// Row below is only written from column F[row+1]; don't read
|
||||
// stale slab data left of it
|
||||
preferMatch = C[I+j0] > 1 ||
|
||||
row+1 < M && j < lastIdx && int32(j+1) >= F[row+1] && C[I+width+j0+1] > 0
|
||||
j--
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,3 +218,26 @@ func TestLongStringWithNormalize(t *testing.T) {
|
||||
unicodeString := string(bytes) + " Minímal example"
|
||||
assertMatch2(t, FuzzyMatchV1, false, true, false, unicodeString, "minim", 30001, 30006, 140)
|
||||
}
|
||||
|
||||
func TestResultPositionsWithReusedSlab(t *testing.T) {
|
||||
// Backtrace positions in equal-score ties must not depend on data
|
||||
// a previous match left in the slab
|
||||
pattern := []rune("co/")
|
||||
target := util.ToChars([]byte("core_color/view/server.txt"))
|
||||
_, freshPos := FuzzyMatchV2(false, false, true, &target, pattern, true, util.MakeSlab(100*1024, 2048))
|
||||
|
||||
slab := util.MakeSlab(100*1024, 2048)
|
||||
dirty := util.ToChars([]byte("completion/keybinding/client/handler/writer_index.txt"))
|
||||
FuzzyMatchV2(false, false, true, &dirty, pattern, true, slab)
|
||||
_, reusedPos := FuzzyMatchV2(false, false, true, &target, pattern, true, slab)
|
||||
|
||||
if len(*freshPos) != len(*reusedPos) {
|
||||
t.Fatalf("position count mismatch: %v vs %v", *freshPos, *reusedPos)
|
||||
}
|
||||
for i := range *freshPos {
|
||||
if (*freshPos)[i] != (*reusedPos)[i] {
|
||||
t.Errorf("positions differ with reused slab: %v vs %v", *freshPos, *reusedPos)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user