1
1
mirror of https://github.com/walles/moar.git synced 2024-10-05 16:07:54 +03:00

Fix toRunePositions()

So it has no corner cases any more.
This commit is contained in:
Johan Walles 2022-09-25 21:07:27 +02:00
parent d32eb6af27
commit 3401d95140
3 changed files with 29 additions and 29 deletions

View File

@ -20,44 +20,29 @@ func getMatchRanges(String *string, Pattern *regexp.Regexp) *MatchRanges {
// Convert byte indices to rune indices
func toRunePositions(byteIndices [][]int, matchedString *string) [][2]int {
// FIXME: Will this function need to handle overlapping ranges?
var returnMe [][2]int
if len(byteIndices) == 0 {
// Nothing to see here, move along
return returnMe
}
fromByte := byteIndices[len(returnMe)][0]
toByte := byteIndices[len(returnMe)][1]
fromRune := -1
runePosition := 0
for bytePosition := range *matchedString {
if fromByte == bytePosition {
fromRune = runePosition
}
if toByte == bytePosition {
toRune := runePosition
returnMe = append(returnMe, [2]int{fromRune, toRune})
runeIndex := 0
byteIndicesToRuneIndices := make(map[int]int, 0)
for byteIndex := range *matchedString {
byteIndicesToRuneIndices[byteIndex] = runeIndex
fromRune = -1
if len(returnMe) >= len(byteIndices) {
// No more byte indices
break
}
fromByte = byteIndices[len(returnMe)][0]
toByte = byteIndices[len(returnMe)][1]
}
runePosition++
runeIndex++
}
if fromRune != -1 {
toRune := runePosition
returnMe = append(returnMe, [2]int{fromRune, toRune})
// If a match touches the end of the string, that will be encoded as one
// byte past the end of the string. Therefore we must add a mapping for
// first-index-after-the-end.
byteIndicesToRuneIndices[len(*matchedString)] = runeIndex
for _, bytePair := range byteIndices {
fromRuneIndex := byteIndicesToRuneIndices[bytePair[0]]
toRuneIndex := byteIndicesToRuneIndices[bytePair[1]]
returnMe = append(returnMe, [2]int{fromRuneIndex, toRuneIndex})
}
return returnMe

View File

@ -73,3 +73,17 @@ func TestEndMatch(t *testing.T) {
assert.Assert(t, matchRanges.InRange(1)) // ä
assert.Assert(t, !matchRanges.InRange(2)) // Past the end
}
func TestRealWorldBug(t *testing.T) {
// Verify a real world bug found in v1.9.8
testString := "anna"
matchRanges := getMatchRanges(&testString, regexp.MustCompile("n"))
assert.Equal(t, len(matchRanges.Matches), 2) // Two matches
assert.DeepEqual(t, matchRanges.Matches[0][0], 1) // First match starts at 1
assert.DeepEqual(t, matchRanges.Matches[0][1], 2) // And ends on 2 exclusive
assert.DeepEqual(t, matchRanges.Matches[1][0], 2) // Second match starts at 2
assert.DeepEqual(t, matchRanges.Matches[1][1], 3) // And ends on 3 exclusive
}

View File

@ -63,6 +63,7 @@ func TestEmpty(t *testing.T) {
assert.Equal(t, pager.lineNumberOneBased(), 0)
}
// Repro case for a search bug discovered in v1.9.8.
func TestSearchHighlight(t *testing.T) {
line := Line{
raw: "x\"\"x",