Skip to content

Commit 88f3cf5

Browse files
committed
make search region padding only one rune wide
1 parent 7ab16a1 commit 88f3cf5

3 files changed

Lines changed: 65 additions & 46 deletions

File tree

internal/buffer/search.go

Lines changed: 27 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package buffer
22

33
import (
44
"regexp"
5-
"unicode/utf8"
65

76
"github.com/zyedidia/micro/v2/internal/util"
87
)
@@ -32,33 +31,6 @@ func NewRegexpGroup(s string) (RegexpGroup, error) {
3231
return rgrp, err
3332
}
3433

35-
func findLineParams(b *Buffer, start, end Loc, i int) ([]byte, int, int) {
36-
l := b.LineBytes(i)
37-
charpos := 0
38-
padMode := 0
39-
40-
if i == end.Y {
41-
nchars := util.CharacterCount(l)
42-
end.X = util.Clamp(end.X, 0, nchars)
43-
if end.X < nchars {
44-
l = util.SliceStart(l, end.X+1)
45-
padMode |= padEnd
46-
}
47-
}
48-
49-
if i == start.Y {
50-
nchars := util.CharacterCount(l)
51-
start.X = util.Clamp(start.X, 0, nchars)
52-
if start.X > 0 {
53-
charpos = start.X - 1
54-
l = util.SliceEnd(l, charpos)
55-
padMode |= padStart
56-
}
57-
}
58-
59-
return l, charpos, padMode
60-
}
61-
6234
type bytesFind func(*regexp.Regexp, []byte) []int
6335

6436
func (b *Buffer) findDownFunc(rgrp RegexpGroup, start, end Loc, find bytesFind) []Loc {
@@ -77,22 +49,42 @@ func (b *Buffer) findDownFunc(rgrp RegexpGroup, start, end Loc, find bytesFind)
7749
}
7850

7951
for i := start.Y; i <= end.Y; i++ {
80-
l, charpos, padMode := findLineParams(b, start, end, i)
52+
l := b.LineBytes(i)
53+
from, to := 0, len(l)
54+
padMode := 0
55+
56+
if i == end.Y {
57+
nchars := util.CharacterCount(l)
58+
end.X = util.Clamp(end.X, 0, nchars)
59+
if end.X < nchars {
60+
padMode |= padEnd
61+
to = util.NextRunePos(l, util.BytePosFromCharPos(l, end.X))
62+
}
63+
}
64+
65+
if i == start.Y {
66+
nchars := util.CharacterCount(l)
67+
start.X = util.Clamp(start.X, 0, nchars)
68+
if start.X > 0 {
69+
padMode |= padStart
70+
from = util.PreviousRunePos(l, util.BytePosFromCharPos(l, start.X))
71+
}
72+
}
8173

82-
match := find(rgrp[padMode], l)
74+
s := l[from:to]
75+
match := find(rgrp[padMode], s)
8376

8477
if match != nil {
8578
if padMode&padStart != 0 {
86-
_, size := utf8.DecodeRune(l[match[0]:])
87-
match[0] += size
79+
match[0] = util.NextRunePos(s, match[0])
8880
}
8981
if padMode&padEnd != 0 {
90-
_, size := utf8.DecodeLastRune(l[:match[1]])
91-
match[1] -= size
82+
match[1] = util.PreviousRunePos(s, match[1])
9283
}
9384
return util.SliceMap(match, func(pos int) Loc {
9485
if pos >= 0 {
95-
return Loc{charpos + util.RunePos(l, pos), i}
86+
x := util.CharacterCount(l[:from+pos])
87+
return Loc{x, i}
9688
} else { // unused submatches
9789
return Loc{-1, -1}
9890
}

internal/util/unicode.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,28 @@ func isMark(r rune) bool {
2626
return unicode.In(r, unicode.Mark)
2727
}
2828

29+
// PreviousRunePos returns the position of the rune preceding the one starting
30+
// at `i` in the given byte slice, or -1 if there is no valid rune
31+
func PreviousRunePos(b []byte, i int) int {
32+
r, size := utf8.DecodeLastRune(b[:i])
33+
if r == utf8.RuneError {
34+
return -1
35+
} else {
36+
return i - size
37+
}
38+
}
39+
40+
// NextRunePos returns the position of the rune following the one starting
41+
// at `i` in the given byte slice, or -1 if there is no valid rune
42+
func NextRunePos(b []byte, i int) int {
43+
r, size := utf8.DecodeRune(b[i:])
44+
if r == utf8.RuneError {
45+
return -1
46+
} else {
47+
return i + size
48+
}
49+
}
50+
2951
// DecodeCharacter returns the next character from an array of bytes
3052
// A character is a rune along with any accompanying combining runes
3153
func DecodeCharacter(b []byte) (rune, []rune, int) {
@@ -94,3 +116,14 @@ func CharacterCountInString(str string) int {
94116

95117
return s
96118
}
119+
120+
// BytePosFromCharPos returns the position of the byte in `b` that
121+
// starts first rune of the character indexed by `ci`
122+
func BytePosFromCharPos(b []byte, ci int) int {
123+
i := 0
124+
for j := 0; j < ci; j++ {
125+
_, _, size := DecodeCharacter(b[i:])
126+
i += size
127+
}
128+
return i
129+
}

internal/util/util.go

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,11 @@ func SliceMap[T, V any](ts []T, f func(T) V) []V {
6565
if ts == nil {
6666
return nil
6767
}
68-
vs := make([]V, len(ts))
69-
for i, t := range ts {
70-
vs[i] = f(t)
71-
}
72-
return vs
68+
vs := make([]V, len(ts))
69+
for i, t := range ts {
70+
vs[i] = f(t)
71+
}
72+
return vs
7373
}
7474

7575
// SliceEnd returns a byte slice where the index is a rune index
@@ -327,12 +327,6 @@ func IsBytesWhitespace(b []byte) bool {
327327
return true
328328
}
329329

330-
// RunePos returns the rune index of a given byte index
331-
// Make sure the byte index is not between code points
332-
func RunePos(b []byte, i int) int {
333-
return CharacterCount(b[:i])
334-
}
335-
336330
// IndexAnyUnquoted returns the first position in s of a character from chars.
337331
// Escaped (with backslash) and quoted (with single or double quotes) characters
338332
// are ignored. Returns -1 if not successful

0 commit comments

Comments
 (0)