mirror of
https://github.com/junegunn/fzf.git
synced 2026-08-14 03:41:07 +08: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]
|
s2 = H[I+j0-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
row := i
|
||||||
if s > s1 && (s > s2 || s == s2 && preferMatch) {
|
if s > s1 && (s > s2 || s == s2 && preferMatch) {
|
||||||
*pos = append(*pos, j+minIdx)
|
*pos = append(*pos, j+minIdx)
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
@@ -637,7 +638,10 @@ func FuzzyMatchV2(caseSensitive bool, normalize bool, forward bool, input *util.
|
|||||||
}
|
}
|
||||||
i--
|
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--
|
j--
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -218,3 +218,26 @@ func TestLongStringWithNormalize(t *testing.T) {
|
|||||||
unicodeString := string(bytes) + " Minímal example"
|
unicodeString := string(bytes) + " Minímal example"
|
||||||
assertMatch2(t, FuzzyMatchV1, false, true, false, unicodeString, "minim", 30001, 30006, 140)
|
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