@@ -170,141 +170,100 @@ impl Source for ReplaceSource {
170170 }
171171
172172 fn rope ( & self ) -> Vec < & str > {
173- let inner_source_code = self . inner . rope ( ) ;
174-
175- if self . replacements . is_empty ( ) {
176- return inner_source_code;
177- }
178-
179- let mut result = Vec :: new ( ) ;
180- let mut pos: u32 = 0 ;
181- let mut chunk_index = 0 ;
182- let mut chunk_pos = 0 ; // Position within current chunk
183- let mut replacement_index = 0 ;
184-
185- // Calculate total length to determine positions
186- let mut chunk_start_positions = Vec :: new ( ) ;
187- let mut total_pos = 0 ;
188- for chunk in & inner_source_code {
189- chunk_start_positions. push ( total_pos) ;
190- total_pos += chunk. len ( ) as u32 ;
191- }
192-
193- while replacement_index < self . replacements . len ( )
194- || chunk_index < inner_source_code. len ( )
195- {
196- let next_replacement = self . replacements . get ( replacement_index) ;
197-
198- // Process chunks until we hit a replacement or finish
199- while chunk_index < inner_source_code. len ( ) {
200- let chunk = inner_source_code[ chunk_index] ;
201- let chunk_start = chunk_start_positions[ chunk_index] ;
202- let chunk_end = chunk_start + chunk. len ( ) as u32 ;
203-
204- // Check if there's a replacement that starts within this chunk
205- if let Some ( replacement) = next_replacement {
206- if replacement. start >= chunk_start && replacement. start < chunk_end {
207- // Replacement starts within this chunk
208- let offset_in_chunk = ( replacement. start - chunk_start) as usize ;
209-
210- // Add the part of chunk before replacement
211- if offset_in_chunk > chunk_pos {
212- result. push ( & chunk[ chunk_pos..offset_in_chunk] ) ;
213- }
214-
215- // Add replacement content
216- result. push ( & replacement. content ) ;
173+ let inner_rope = self . inner . rope ( ) ;
174+ let mut rope =
175+ Vec :: with_capacity ( inner_rope. len ( ) + self . replacements . len ( ) * 2 ) ;
176+
177+ let mut pos: usize = 0 ;
178+ let mut replacement_idx: usize = 0 ;
179+ let mut replacement_end: Option < usize > = None ;
180+ let mut next_replacement: Option < usize > = ( replacement_idx
181+ < self . replacements . len ( ) )
182+ . then ( || self . replacements [ replacement_idx] . start as usize ) ;
183+
184+ ' chunk_loop: for chunk in self . inner . rope ( ) {
185+ let mut chunk_pos = 0 ;
186+ let end_pos = pos + chunk. len ( ) ;
187+
188+ // Skip over when it has been replaced
189+ if let Some ( replacement_end) =
190+ replacement_end. filter ( |replacement_end| * replacement_end > pos)
191+ {
192+ // Skip over the whole chunk
193+ if replacement_end >= end_pos {
194+ pos = end_pos;
195+ continue ;
196+ }
197+ // Partially skip over chunk
198+ chunk_pos = replacement_end - pos;
199+ pos += chunk_pos;
200+ }
217201
218- // Update positions
219- pos = replacement. end ;
220- replacement_index += 1 ;
202+ // Is a replacement in the chunk?
203+ while let Some ( next_replacement_pos) = next_replacement
204+ . filter ( |next_replacement_pos| * next_replacement_pos < end_pos)
205+ {
206+ if next_replacement_pos > pos {
207+ // Emit chunk until replacement
208+ let offset = next_replacement_pos - pos;
209+ let chunk_slice = & chunk[ chunk_pos..( chunk_pos + offset) ] ;
210+ rope. push ( chunk_slice) ;
211+ chunk_pos += offset;
212+ pos = next_replacement_pos;
213+ }
214+ // Insert replacement content split into chunks by lines
215+ let replacement = & self . replacements [ replacement_idx] ;
216+ rope. push ( & replacement. content ) ;
221217
222- // Find where to continue after replacement
223- let mut found_continue_pos = false ;
224- for ( idx, & chunk_start_pos) in
225- chunk_start_positions. iter ( ) . enumerate ( )
226- {
227- let chunk_end_pos =
228- chunk_start_pos + inner_source_code[ idx] . len ( ) as u32 ;
229-
230- if pos >= chunk_start_pos && pos < chunk_end_pos {
231- // Continue from within this chunk
232- chunk_index = idx;
233- chunk_pos = ( pos - chunk_start_pos) as usize ;
234- found_continue_pos = true ;
235- break ;
236- } else if pos <= chunk_start_pos {
237- // Continue from the start of this chunk
238- chunk_index = idx;
239- chunk_pos = 0 ;
240- found_continue_pos = true ;
241- break ;
242- }
243- }
218+ // Remove replaced content by settings this variable
219+ replacement_end = if let Some ( replacement_end) = replacement_end {
220+ Some ( replacement_end. max ( replacement. end as usize ) )
221+ } else {
222+ Some ( replacement. end as usize )
223+ } ;
244224
245- if !found_continue_pos {
246- // Replacement goes beyond all chunks
247- chunk_index = inner_source_code. len ( ) ;
248- }
225+ // Move to next replacement
226+ replacement_idx += 1 ;
227+ next_replacement = if replacement_idx < self . replacements . len ( ) {
228+ Some ( self . replacements [ replacement_idx] . start as usize )
229+ } else {
230+ None
231+ } ;
249232
250- break ;
251- } else if replacement. start < chunk_start {
252- // Replacement starts before this chunk
253- result. push ( & replacement. content ) ;
254- replacement_index += 1 ;
255-
256- // Skip chunks that are replaced
257- pos = replacement. end ;
258- while chunk_index < inner_source_code. len ( ) {
259- let current_chunk_start = chunk_start_positions[ chunk_index] ;
260- let current_chunk_end = current_chunk_start
261- + inner_source_code[ chunk_index] . len ( ) as u32 ;
262-
263- if pos <= current_chunk_start {
264- // Start from beginning of this chunk
265- chunk_pos = 0 ;
266- break ;
267- } else if pos < current_chunk_end {
268- // Start from middle of this chunk
269- chunk_pos = ( pos - current_chunk_start) as usize ;
270- break ;
271- } else {
272- // Skip this entire chunk
273- chunk_index += 1 ;
274- }
275- }
276- break ;
233+ // Skip over when it has been replaced
234+ let offset = chunk. len ( ) as i64 - end_pos as i64
235+ + replacement_end. unwrap ( ) as i64
236+ - chunk_pos as i64 ;
237+ if offset > 0 {
238+ // Skip over whole chunk
239+ if replacement_end
240+ . is_some_and ( |replacement_end| replacement_end >= end_pos)
241+ {
242+ pos = end_pos;
243+ continue ' chunk_loop;
277244 }
278- }
279245
280- // No replacement affecting this chunk, add the remaining part
281- if chunk_pos == 0
282- && ( next_replacement. is_none ( )
283- || next_replacement. unwrap ( ) . start > chunk_end)
284- {
285- // Add entire chunk
286- result. push ( chunk) ;
287- } else if chunk_pos < chunk. len ( ) {
288- // Add remaining part of chunk
289- result. push ( & chunk[ chunk_pos..] ) ;
246+ // Partially skip over chunk
247+ chunk_pos += offset as usize ;
248+ pos += offset as usize ;
290249 }
291-
292- chunk_index += 1 ;
293- chunk_pos = 0 ;
294- pos = chunk_end;
295250 }
296251
297- // Handle remaining replacements that are beyond all chunks
298- while replacement_index < self . replacements . len ( ) {
299- let replacement = & self . replacements [ replacement_index] ;
300- if replacement. start >= pos {
301- result. push ( & replacement. content ) ;
302- }
303- replacement_index += 1 ;
252+ // Emit remaining chunk
253+ if chunk_pos < chunk. len ( ) {
254+ rope. push ( & chunk[ chunk_pos..] ) ;
304255 }
256+ pos = end_pos;
305257 }
306258
307- result
259+ // Handle remaining replacements one by one
260+ while replacement_idx < self . replacements . len ( ) {
261+ let content = & self . replacements [ replacement_idx] . content ;
262+ rope. push ( content) ;
263+ replacement_idx += 1 ;
264+ }
265+
266+ rope
308267 }
309268
310269 fn buffer ( & self ) -> Cow < [ u8 ] > {
@@ -365,7 +324,10 @@ impl Source for ReplaceSource {
365324 }
366325
367326 fn to_writer ( & self , writer : & mut dyn std:: io:: Write ) -> std:: io:: Result < ( ) > {
368- writer. write_all ( self . source ( ) . as_bytes ( ) )
327+ for text in self . rope ( ) {
328+ writer. write_all ( text. as_bytes ( ) ) ?;
329+ }
330+ Ok ( ( ) )
369331 }
370332}
371333
0 commit comments