@@ -122,6 +122,26 @@ func (b *Buffer) findUp(r *regexp.Regexp, start, end Loc) ([2]Loc, bool) {
122122 return [2 ]Loc {}, false
123123}
124124
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+
125145// FindNext finds the next occurrence of a given string in the buffer
126146// It returns the start and end location of the match (if found) and
127147// 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
165185}
166186
167187// 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
169189// added or removed on the last line of the range
170190func (b * Buffer ) ReplaceRegex (start , end Loc , search * regexp.Regexp , replace []byte , captureGroups bool ) (int , int ) {
171191 if start .GreaterThan (end ) {
172192 start , end = end , start
173193 }
174194
175- netrunes := 0
176-
177195 found := 0
196+ var charCount int
178197 var deltas []Delta
198+
179199 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 )
200+ l := b .LineBytes (i )
201+ charCount = util .CharacterCount (l )
202+ if (i == start .Y && start .X > 0 ) || (i == end .Y && end .X < charCount ) {
203+ // This replacement code works in general, but it creates a separate
204+ // modification for each match. We only use it for the first and last
205+ // lines, which may use padded regexps
206+
207+ from := Loc {0 , i }.Clamp (start , end )
208+ to := Loc {charCount , i }.Clamp (start , end )
209+ matches := b .findAll (search , from , to )
210+ found += len (matches )
211+
212+ for j := len (matches ) - 1 ; j >= 0 ; j -- {
213+ // if we counted upwards, the different deltas would interfere
214+ match := matches [j ]
215+ var newText []byte
216+ if captureGroups {
217+ newText = search .ReplaceAll (b .Substr (match [0 ], match [1 ]), replace )
218+ } else {
219+ newText = replace
198220 }
199- } else {
200- result = replace
201- }
202- found ++
203- if i == end .Y {
204- netrunes += util .CharacterCount (result ) - util .CharacterCount (in )
221+ deltas = append (deltas , Delta {newText , match [0 ], match [1 ]})
205222 }
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 })
223+ } else {
224+ newLine := search .ReplaceAllFunc (l , func (in []byte ) []byte {
225+ found ++
226+ var result []byte
227+ if captureGroups {
228+ match := search .FindSubmatchIndex (in )
229+ result = search .Expand (result , replace , in , match )
230+ } else {
231+ result = replace
232+ }
233+ return result
234+ })
235+ deltas = append (deltas , Delta {newLine , Loc {0 , i }, Loc {charCount , i }})
236+ }
213237 }
238+
214239 b .MultipleReplace (deltas )
215240
216- return found , netrunes
241+ deltaX := util .CharacterCount (b .LineBytes (end .Y )) - charCount
242+ return found , deltaX
217243}
0 commit comments