@ 261102.1

260831.1 · b395cfbd91a9e24cbcfca6ecbc8d7e39bbe54101

Fix --tiebreak=pathname with non-ASCII text

Fix #4902

reading declarations

CHANGELOG.md

@@ -3,6 +3,7 @@ CHANGELOG  0.74.4 ------+- Fixed `--tiebreak=pathname` not detecting the last path separator when the line contains a non-ASCII character before it (#4902) - Vim plugin     - fzf no longer blocks the editor, so live previews keep working while fzf is open         - `fzf#run` returns an empty list when it runs fzf asynchronously. Use `sink`, `sinklist`, or `exit` to get the result

src/result.go

@@ -82,10 +82,10 @@ func buildResultFromBounds(item *Item, score int, minBegin, minEnd, maxEnd int, 			val = item.TrimLength() 		case byPathname: 			if validOffsetFound {+				// Rune index, to be comparable with minBegin 				lastDelim := -1-				s := item.text.ToString()-				for i := len(s) - 1; i >= 0; i-- {-					if s[i] == '/' || s[i] == '\\' {+				for i := numChars - 1; i >= 0; i-- {+					if r := item.text.Get(i); r == '/' || r == '\\' { 						lastDelim = i 						break 					}

src/result_test.go

@@ -272,3 +272,28 @@ func TestRadixSortResults(t *testing.T) { 		} 	} }++func TestPathnameTiebreak(t *testing.T) {+	// FIXME global+	sortCriteria = []criterion{byScore, byPathname}++	score := 100+	test := func(input string, offset Offset, expected uint16) {+		for _, chars := range []util.Chars{util.ToChars([]byte(input)), util.RunesToChars([]rune(input))} {+			item := buildResult(withIndex(&Item{text: chars}, 1), []Offset{offset}, score)+			if item.points[3] != math.MaxUint16-uint16(score) || item.points[2] != expected {+				t.Error(input, item.points, expected)+			}+		}+	}++	// Match in the file name+	test("x/foo/foo.txt", Offset{6, 9}, 1)+	// Match in the directory path+	test("x/foo/aa.txt", Offset{2, 5}, math.MaxUint16)++	// Offsets are rune indexes, so a multi-byte character before the last+	// delimiter must not shift the delimiter position+	test("一x/foo/foo.txt", Offset{7, 10}, 1)+	test("一x/foo/aa.txt", Offset{3, 6}, math.MaxUint16)+}