@@ -122,6 +122,26 @@ func (b *Buffer) findUp(r *regexp.Regexp, start, end Loc) ([2]Loc, bool) {
122
122
return [2 ]Loc {}, false
123
123
}
124
124
125
+ func (b * Buffer ) findAll (r * regexp.Regexp , start , end Loc ) [][2 ]Loc {
126
+ matches := [][2 ]Loc {}
127
+ loc := start
128
+ for {
129
+ match , found := b .findDown (r , loc , end )
130
+ if ! found {
131
+ break
132
+ }
133
+ matches = append (matches , match )
134
+ if match [0 ] != match [1 ] {
135
+ loc = match [1 ]
136
+ } else if match [1 ] != end {
137
+ loc = match [1 ].Move (1 , b )
138
+ } else {
139
+ break
140
+ }
141
+ }
142
+ return matches
143
+ }
144
+
125
145
// FindNext finds the next occurrence of a given string in the buffer
126
146
// It returns the start and end location of the match (if found) and
127
147
// a boolean indicating if it was found
@@ -165,53 +185,59 @@ func (b *Buffer) FindNext(s string, start, end, from Loc, down bool, useRegex bo
165
185
}
166
186
167
187
// ReplaceRegex replaces all occurrences of 'search' with 'replace' in the given area
168
- // and returns the number of replacements made and the number of runes
188
+ // and returns the number of replacements made and the number of characters
169
189
// added or removed on the last line of the range
170
190
func (b * Buffer ) ReplaceRegex (start , end Loc , search * regexp.Regexp , replace []byte , captureGroups bool ) (int , int ) {
171
191
if start .GreaterThan (end ) {
172
192
start , end = end , start
173
193
}
174
194
175
- netrunes := 0
176
-
195
+ charsEnd := util .CharacterCount (b .LineBytes (end .Y ))
177
196
found := 0
197
+ var charCount int
178
198
var deltas []Delta
199
+
179
200
for i := start .Y ; i <= end .Y ; i ++ {
180
- l := b .lines [i ].data
181
- charpos := 0
182
-
183
- if start .Y == end .Y && i == start .Y {
184
- l = util .SliceStart (l , end .X )
185
- l = util .SliceEnd (l , start .X )
186
- charpos = start .X
187
- } else if i == start .Y {
188
- l = util .SliceEnd (l , start .X )
189
- charpos = start .X
190
- } else if i == end .Y {
191
- l = util .SliceStart (l , end .X )
192
- }
193
- newText := search .ReplaceAllFunc (l , func (in []byte ) []byte {
194
- var result []byte
195
- if captureGroups {
196
- for _ , submatches := range search .FindAllSubmatchIndex (in , - 1 ) {
197
- result = search .Expand (result , replace , in , submatches )
201
+ l := b .LineBytes (i )
202
+ charCount = util .CharacterCount (l )
203
+ if i == start .Y || i == end .Y {
204
+ // This replacement code works in general, but it creates a separate
205
+ // modification for each match. We only use it for the first and last
206
+ // lines, which may use padded regexps
207
+
208
+ from := Loc {0 , i }.Clamp (start , end )
209
+ to := Loc {charCount , i }.Clamp (start , end )
210
+ matches := b .findAll (search , from , to )
211
+ found += len (matches )
212
+
213
+ for j := len (matches ) - 1 ; j >= 0 ; j -- {
214
+ // if we counted upwards, the different deltas would interfere
215
+ match := matches [j ]
216
+ var newText []byte
217
+ if captureGroups {
218
+ newText = search .ReplaceAll (b .Substr (match [0 ], match [1 ]), replace )
219
+ } else {
220
+ newText = replace
198
221
}
199
- } else {
200
- result = replace
201
- }
202
- found ++
203
- if i == end .Y {
204
- netrunes += util .CharacterCount (result ) - util .CharacterCount (in )
222
+ deltas = append (deltas , Delta {newText , match [0 ], match [1 ]})
205
223
}
206
- return result
207
- })
208
-
209
- from := Loc {charpos , i }
210
- to := Loc {charpos + util .CharacterCount (l ), i }
211
-
212
- deltas = append (deltas , Delta {newText , from , to })
224
+ } else {
225
+ newLine := search .ReplaceAllFunc (l , func (in []byte ) []byte {
226
+ found ++
227
+ var result []byte
228
+ if captureGroups {
229
+ match := search .FindSubmatchIndex (in )
230
+ result = search .Expand (result , replace , in , match )
231
+ } else {
232
+ result = replace
233
+ }
234
+ return result
235
+ })
236
+ deltas = append (deltas , Delta {newLine , Loc {0 , i }, Loc {charCount , i }})
237
+ }
213
238
}
239
+
214
240
b .MultipleReplace (deltas )
215
241
216
- return found , netrunes
242
+ return found , charCount - charsEnd
217
243
}
0 commit comments