@@ -6,6 +6,50 @@ import (
66 "github.com/zyedidia/micro/v2/internal/util"
77)
88
9+ const (
10+ padStart = 1 << iota
11+ padEnd
12+ )
13+
14+ // We want "^" and "$" to match only the beginning/end of a line, not the
15+ // beginning/end of the search region if it is in the middle of a line.
16+ // In that case we use padded regexps to require a rune before or after
17+ // the match. (This also affects other empty-string patters like "\\b".)
18+ // The function padRegexp creates these padded regexps.
19+ func padRegexp (r * regexp.Regexp ) [4 ]* regexp.Regexp {
20+ rPadStart := regexp .MustCompile (".(?:" + r .String () + ")" )
21+ rPadEnd := regexp .MustCompile ("(?:" + r .String () + ")." )
22+ rPadBoth := regexp .MustCompile (".(?:" + r .String () + ")." )
23+ return [4 ]* regexp.Regexp {r , rPadStart , rPadEnd , rPadBoth }
24+ }
25+
26+ func findLineParams (b * Buffer , start , end Loc , i int ) ([]byte , int , int ) {
27+ l := b .LineBytes (i )
28+ charpos := 0
29+ padMode := 0
30+
31+ if i == end .Y {
32+ nchars := util .CharacterCount (l )
33+ end .X = util .Clamp (end .X , 0 , nchars )
34+ if end .X < nchars {
35+ l = util .SliceStart (l , end .X + 1 )
36+ padMode |= padEnd
37+ }
38+ }
39+
40+ if i == start .Y {
41+ nchars := util .CharacterCount (l )
42+ start .X = util .Clamp (start .X , 0 , nchars )
43+ if start .X > 0 {
44+ charpos = start .X - 1
45+ l = util .SliceEnd (l , charpos )
46+ padMode |= padStart
47+ }
48+ }
49+
50+ return l , charpos , padMode
51+ }
52+
953func (b * Buffer ) findDown (r * regexp.Regexp , start , end Loc ) ([2 ]Loc , bool ) {
1054 lastcn := util .CharacterCount (b .LineBytes (b .LinesNum () - 1 ))
1155 if start .Y > b .LinesNum ()- 1 {
@@ -21,33 +65,22 @@ func (b *Buffer) findDown(r *regexp.Regexp, start, end Loc) ([2]Loc, bool) {
2165 start , end = end , start
2266 }
2367
24- for i := start .Y ; i <= end .Y ; i ++ {
25- l := b .LineBytes (i )
26- charpos := 0
68+ rPadded := padRegexp (r )
2769
28- if i == start .Y && start .Y == end .Y {
29- nchars := util .CharacterCount (l )
30- start .X = util .Clamp (start .X , 0 , nchars )
31- end .X = util .Clamp (end .X , 0 , nchars )
32- l = util .SliceStart (l , end .X )
33- l = util .SliceEnd (l , start .X )
34- charpos = start .X
35- } else if i == start .Y {
36- nchars := util .CharacterCount (l )
37- start .X = util .Clamp (start .X , 0 , nchars )
38- l = util .SliceEnd (l , start .X )
39- charpos = start .X
40- } else if i == end .Y {
41- nchars := util .CharacterCount (l )
42- end .X = util .Clamp (end .X , 0 , nchars )
43- l = util .SliceStart (l , end .X )
44- }
70+ for i := start .Y ; i <= end .Y ; i ++ {
71+ l , charpos , padMode := findLineParams (b , start , end , i )
4572
46- match := r .FindIndex (l )
73+ match := rPadded [ padMode ] .FindIndex (l )
4774
4875 if match != nil {
4976 start := Loc {charpos + util .RunePos (l , match [0 ]), i }
77+ if padMode & padStart != 0 {
78+ start = start .Move (1 , b )
79+ }
5080 end := Loc {charpos + util .RunePos (l , match [1 ]), i }
81+ if padMode & padEnd != 0 {
82+ end = end .Move (- 1 , b )
83+ }
5184 return [2 ]Loc {start , end }, true
5285 }
5386 }
@@ -69,34 +102,23 @@ func (b *Buffer) findUp(r *regexp.Regexp, start, end Loc) ([2]Loc, bool) {
69102 start , end = end , start
70103 }
71104
72- for i := end .Y ; i >= start .Y ; i -- {
73- l := b .LineBytes (i )
74- charpos := 0
105+ rPadded := padRegexp (r )
75106
76- if i == start .Y && start .Y == end .Y {
77- nchars := util .CharacterCount (l )
78- start .X = util .Clamp (start .X , 0 , nchars )
79- end .X = util .Clamp (end .X , 0 , nchars )
80- l = util .SliceStart (l , end .X )
81- l = util .SliceEnd (l , start .X )
82- charpos = start .X
83- } else if i == start .Y {
84- nchars := util .CharacterCount (l )
85- start .X = util .Clamp (start .X , 0 , nchars )
86- l = util .SliceEnd (l , start .X )
87- charpos = start .X
88- } else if i == end .Y {
89- nchars := util .CharacterCount (l )
90- end .X = util .Clamp (end .X , 0 , nchars )
91- l = util .SliceStart (l , end .X )
92- }
107+ for i := end .Y ; i >= start .Y ; i -- {
108+ l , charpos , padMode := findLineParams (b , start , end , i )
93109
94- allMatches := r .FindAllIndex (l , - 1 )
110+ allMatches := rPadded [ padMode ] .FindAllIndex (l , - 1 )
95111
96112 if allMatches != nil {
97113 match := allMatches [len (allMatches )- 1 ]
98114 start := Loc {charpos + util .RunePos (l , match [0 ]), i }
115+ if padMode & padStart != 0 {
116+ start = start .Move (1 , b )
117+ }
99118 end := Loc {charpos + util .RunePos (l , match [1 ]), i }
119+ if padMode & padEnd != 0 {
120+ end = end .Move (- 1 , b )
121+ }
100122 return [2 ]Loc {start , end }, true
101123 }
102124 }
0 commit comments