@@ -21,15 +21,15 @@ const (
21
21
22
22
// NewRegexpGroup creates a RegexpGroup from a string
23
23
func NewRegexpGroup (s string ) (RegexpGroup , error ) {
24
- var r RegexpGroup
24
+ var rgrp RegexpGroup
25
25
var err error
26
- r [0 ], err = regexp .Compile (s )
26
+ rgrp [0 ], err = regexp .Compile (s )
27
27
if err == nil {
28
- r [padStart ] = regexp .MustCompile (".(?:" + s + ")" )
29
- r [padEnd ] = regexp .MustCompile ("(?:" + s + ")." )
30
- r [padStart | padEnd ] = regexp .MustCompile (".(?:" + s + ")." )
28
+ rgrp [padStart ] = regexp .MustCompile (".(?:" + s + ")" )
29
+ rgrp [padEnd ] = regexp .MustCompile ("(?:" + s + ")." )
30
+ rgrp [padStart | padEnd ] = regexp .MustCompile (".(?:" + s + ")." )
31
31
}
32
- return r , err
32
+ return rgrp , err
33
33
}
34
34
35
35
func findLineParams (b * Buffer , start , end Loc , i int ) ([]byte , int , int ) {
@@ -59,7 +59,9 @@ func findLineParams(b *Buffer, start, end Loc, i int) ([]byte, int, int) {
59
59
return l , charpos , padMode
60
60
}
61
61
62
- func (b * Buffer ) findDown (r RegexpGroup , start , end Loc ) ([2 ]Loc , bool ) {
62
+ type bytesFind func (* regexp.Regexp , []byte ) []int
63
+
64
+ func (b * Buffer ) findDownFunc (rgrp RegexpGroup , start , end Loc , find bytesFind ) []Loc {
63
65
lastcn := util .CharacterCount (b .LineBytes (b .LinesNum () - 1 ))
64
66
if start .Y > b .LinesNum ()- 1 {
65
67
start .X = lastcn - 1
@@ -77,7 +79,7 @@ func (b *Buffer) findDown(r RegexpGroup, start, end Loc) ([2]Loc, bool) {
77
79
for i := start .Y ; i <= end .Y ; i ++ {
78
80
l , charpos , padMode := findLineParams (b , start , end , i )
79
81
80
- match := r [padMode ]. FindIndex ( l )
82
+ match := find ( rgrp [padMode ], l )
81
83
82
84
if match != nil {
83
85
if padMode & padStart != 0 {
@@ -88,15 +90,31 @@ func (b *Buffer) findDown(r RegexpGroup, start, end Loc) ([2]Loc, bool) {
88
90
_ , size := utf8 .DecodeLastRune (l [:match [1 ]])
89
91
match [1 ] -= size
90
92
}
91
- start := Loc { charpos + util .RunePos ( l , match [ 0 ]), i }
92
- end := Loc {charpos + util .RunePos (l , match [ 1 ] ), i }
93
- return [ 2 ] Loc { start , end }, true
93
+ return util .SliceMap ( match , func ( pos int ) Loc {
94
+ return Loc {charpos + util .RunePos (l , pos ), i }
95
+ })
94
96
}
95
97
}
96
- return [2 ]Loc {}, false
98
+ return nil
99
+ }
100
+
101
+ type bufferFind func (* Buffer , RegexpGroup , Loc , Loc ) []Loc
102
+
103
+ // FindDown returns a slice containing the start and end positions
104
+ // of the first match of `rgrp` between `start` and `end`, or nil
105
+ // if no match exists.
106
+ func (b * Buffer ) FindDown (rgrp RegexpGroup , start , end Loc ) []Loc {
107
+ return b .findDownFunc (rgrp , start , end , (* regexp .Regexp ).FindIndex )
108
+ }
109
+
110
+ // FindDownSubmatch returns a slice containing the start and end positions
111
+ // of the first match of `rgrp` between `start` and `end` plus those
112
+ // of all submatches (capturing groups), or nil if no match exists.
113
+ func (b * Buffer ) FindDownSubmatch (rgrp RegexpGroup , start , end Loc ) []Loc {
114
+ return b .findDownFunc (rgrp , start , end , (* regexp .Regexp ).FindSubmatchIndex )
97
115
}
98
116
99
- func (b * Buffer ) findUp ( r RegexpGroup , start , end Loc ) ([ 2 ]Loc , bool ) {
117
+ func (b * Buffer ) findUpFunc ( rgrp RegexpGroup , start , end Loc , find bytesFind ) [ ]Loc {
100
118
lastcn := util .CharacterCount (b .LineBytes (b .LinesNum () - 1 ))
101
119
if start .Y > b .LinesNum ()- 1 {
102
120
start .X = lastcn - 1
@@ -111,33 +129,63 @@ func (b *Buffer) findUp(r RegexpGroup, start, end Loc) ([2]Loc, bool) {
111
129
start , end = end , start
112
130
}
113
131
114
- var match [ 2 ]Loc
132
+ var locs [ ]Loc
115
133
for i := end .Y ; i >= start .Y ; i -- {
116
134
charCount := util .CharacterCount (b .LineBytes (i ))
117
135
from := Loc {0 , i }.Clamp (start , end )
118
136
to := Loc {charCount , i }.Clamp (start , end )
119
137
120
- n := b .findAllFunc (r , from , to , func (from , to Loc ) {
121
- match = [2 ]Loc {from , to }
138
+ b .findAllFuncFunc (rgrp , from , to , func (b * Buffer , rgrp RegexpGroup , start , end Loc ) []Loc {
139
+ return b .findDownFunc (rgrp , start , end , find )
140
+ }, func (match []Loc ) {
141
+ locs = match
122
142
})
123
143
124
- if n != 0 {
125
- return match , true
144
+ if locs != nil {
145
+ return locs
126
146
}
127
147
}
128
- return match , false
148
+ return nil
129
149
}
130
150
131
- func (b * Buffer ) findAllFunc (r RegexpGroup , start , end Loc , f func (from , to Loc )) int {
151
+ // FindUp returns a slice containing the start and end positions
152
+ // of the last match of `rgrp` between `start` and `end`, or nil
153
+ // if no match exists.
154
+ func (b * Buffer ) FindUp (rgrp RegexpGroup , start , end Loc ) []Loc {
155
+ return b .findUpFunc (rgrp , start , end , func (re * regexp.Regexp , l []byte ) []int {
156
+ allMatches := re .FindAllIndex (l , - 1 )
157
+ if allMatches != nil {
158
+ return allMatches [len (allMatches )- 1 ]
159
+ } else {
160
+ return nil
161
+ }
162
+ })
163
+ }
164
+
165
+ // FindUpSubmatch returns a slice containing the start and end positions
166
+ // of the last match of `rgrp` between `start` and `end` plus those
167
+ // of all submatches (capturing groups), or nil if no match exists.
168
+ func (b * Buffer ) FindUpSubmatch (rgrp RegexpGroup , start , end Loc ) []Loc {
169
+ return b .findUpFunc (rgrp , start , end , func (re * regexp.Regexp , l []byte ) []int {
170
+ allMatches := re .FindAllSubmatchIndex (l , - 1 )
171
+ if allMatches != nil {
172
+ return allMatches [len (allMatches )- 1 ]
173
+ } else {
174
+ return nil
175
+ }
176
+ })
177
+ }
178
+
179
+ func (b * Buffer ) findAllFuncFunc (r RegexpGroup , start , end Loc , find bufferFind , f func ([]Loc )) int {
180
+ n := 0
132
181
loc := start
133
- nfound := 0
134
182
for {
135
- match , found := b . findDown ( r , loc , end )
136
- if ! found {
183
+ match := find ( b , r , loc , end )
184
+ if match == nil {
137
185
break
138
186
}
139
- nfound ++
140
- f (match [ 0 ], match [ 1 ] )
187
+ n ++
188
+ f (match )
141
189
if match [0 ] != match [1 ] {
142
190
loc = match [1 ]
143
191
} else if match [1 ] != end {
@@ -146,7 +194,58 @@ func (b *Buffer) findAllFunc(r RegexpGroup, start, end Loc, f func(from, to Loc)
146
194
break
147
195
}
148
196
}
149
- return nfound
197
+ return n
198
+ }
199
+
200
+ // FindAllFunc calls the function `f` once for each match between `start`
201
+ // and `end` of the regexp given by `s`. The argument of `f` is the slice
202
+ // containing the start and end positions of the match. FindAllFunc returns
203
+ // the number of matches plus any error that occured when compiling the regexp.
204
+ func (b * Buffer ) FindAllFunc (s string , start , end Loc , f func ([]Loc )) (int , error ) {
205
+ rgrp , err := NewRegexpGroup (s )
206
+ if err == nil {
207
+ return b .findAllFuncFunc (rgrp , start , end , (* Buffer ).FindDown , f ), nil
208
+ } else {
209
+ return - 1 , err
210
+ }
211
+ }
212
+
213
+ // FindAll returns a slice containing the start and end positions of all
214
+ // matches between `start` and `end` of the regexp given by `s`, plus any
215
+ // error that occured when compiling the regexp. If no match is found, the
216
+ // slice returned is nil.
217
+ func (b * Buffer ) FindAll (s string , start , end Loc ) ([][]Loc , error ) {
218
+ var matches [][]Loc
219
+ _ , err := b .FindAllFunc (s , start , end , func (match []Loc ) {
220
+ matches = append (matches , match )
221
+ })
222
+ return matches , err
223
+ }
224
+
225
+ // FindAllSubmatchFunc calls the function `f` once for each match between
226
+ // `start` and `end` of the regexp given by `s`. The argument of `f` is the
227
+ // slice containing the start and end positions of the match and all submatches
228
+ // (capturing groups). FindAllSubmatch Func returns the number of matches plus
229
+ // any error that occured when compiling the regexp.
230
+ func (b * Buffer ) FindAllSubmatchFunc (s string , start , end Loc , f func ([]Loc )) (int , error ) {
231
+ rgrp , err := NewRegexpGroup (s )
232
+ if err == nil {
233
+ return b .findAllFuncFunc (rgrp , start , end , (* Buffer ).FindDownSubmatch , f ), nil
234
+ } else {
235
+ return - 1 , err
236
+ }
237
+ }
238
+
239
+ // FindAllSubmatch returns a slice containing the start and end positions of
240
+ // all matches and all submatches (capturing groups) between `start` and `end`
241
+ // of the regexp given by `s`, plus any error that occured when compiling
242
+ // the regexp. If no match is found, the slice returned is nil.
243
+ func (b * Buffer ) FindAllSubmatch (s string , start , end Loc ) ([][]Loc , error ) {
244
+ var matches [][]Loc
245
+ _ , err := b .FindAllSubmatchFunc (s , start , end , func (match []Loc ) {
246
+ matches = append (matches , match )
247
+ })
248
+ return matches , err
150
249
}
151
250
152
251
// FindNext finds the next occurrence of a given string in the buffer
@@ -166,49 +265,65 @@ func (b *Buffer) FindNext(s string, start, end, from Loc, down bool, useRegex bo
166
265
s = "(?i)" + s
167
266
}
168
267
169
- r , err := NewRegexpGroup (s )
268
+ rgrp , err := NewRegexpGroup (s )
170
269
if err != nil {
171
270
return [2 ]Loc {}, false , err
172
271
}
173
272
174
- var found bool
175
- var l [2 ]Loc
273
+ var match []Loc
176
274
if down {
177
- l , found = b .findDown ( r , from , end )
178
- if ! found {
179
- l , found = b .findDown ( r , start , end )
275
+ match = b .FindDown ( rgrp , from , end )
276
+ if match == nil {
277
+ match = b .FindDown ( rgrp , start , end )
180
278
}
181
279
} else {
182
- l , found = b .findUp ( r , from , start )
183
- if ! found {
184
- l , found = b .findUp ( r , end , start )
280
+ match = b .FindUp ( rgrp , from , start )
281
+ if match == nil {
282
+ match = b .FindUp ( rgrp , end , start )
185
283
}
186
284
}
187
- return l , found , nil
285
+ if match != nil {
286
+ return [2 ]Loc {match [0 ], match [1 ]}, true , nil
287
+ } else {
288
+ return [2 ]Loc {}, false , nil
289
+ }
188
290
}
189
291
190
- // ReplaceRegex replaces all occurrences of 'search' with 'replace' in the given area
191
- // and returns the number of replacements made and the number of characters
192
- // added or removed on the last line of the range
193
- func (b * Buffer ) ReplaceRegex (start , end Loc , search RegexpGroup , replace []byte , captureGroups bool ) (int , int ) {
292
+ // ReplaceAll replaces all matches of 's' with 'template' in the given area
293
+ // and returns the number of replacements made, the new end position and any
294
+ // error that occured during regexp compilation
295
+ func (b * Buffer ) ReplaceAll (s string , start , end Loc , template string ) (int , Loc , error ) {
296
+ rgrp , err := NewRegexpGroup (s )
297
+ if err != nil {
298
+ return - 1 , Loc {- 1 , - 1 }, err
299
+ }
300
+
194
301
if start .GreaterThan (end ) {
195
302
start , end = end , start
196
303
}
197
304
305
+ templateBytes := []byte (template )
198
306
charsEnd := util .CharacterCount (b .LineBytes (end .Y ))
199
307
200
308
var deltas []Delta
201
- nfound := b .findAllFunc (search , start , end , func (from , to Loc ) {
202
- var newText []byte
203
- if captureGroups {
204
- newText = search [0 ].ReplaceAll (b .Substr (from , to ), replace )
205
- } else {
206
- newText = replace
207
- }
208
- deltas = append (deltas , Delta {newText , from , to })
209
- })
309
+ var replace []byte
310
+
311
+ f := func (match []Loc ) {
312
+ deltas = append (deltas , Delta {replace , match [0 ], match [1 ]})
313
+ }
314
+
315
+ n := b .findAllFuncFunc (rgrp , start , end , func (b * Buffer , r RegexpGroup , start , end Loc ) []Loc {
316
+ return b .findDownFunc (r , start , end , func (re * regexp.Regexp , l []byte ) []int {
317
+ match := re .FindSubmatchIndex (l )
318
+ if match == nil {
319
+ return nil
320
+ }
321
+ replace = re .Expand (nil , templateBytes , l , match )
322
+ return match [:2 ] // this way match[2:] is not transformed to Loc's
323
+ })
324
+ }, f )
210
325
b .MultipleReplace (deltas )
211
326
212
327
deltaX := util .CharacterCount (b .LineBytes (end .Y )) - charsEnd
213
- return nfound , deltaX
328
+ return n , Loc { end . X + deltaX , end . Y }, nil
214
329
}
0 commit comments