@@ -11,6 +11,7 @@ struct AdjustmentMarker {
1111 #[ allow( dead_code) ]
1212 original_range : TextRange ,
1313 adjusted_range : TextRange ,
14+ replacement_txt : String ,
1415 registered_offset_at_start : TextSize ,
1516
1617 #[ allow( dead_code) ]
@@ -38,6 +39,7 @@ impl AdjustmentMarker {
3839 AdjustmentMarker {
3940 original_range,
4041 adjustment_direction,
42+ replacement_txt : replacement_txt. into ( ) ,
4143 range_size_difference : TextSize :: new ( range_size_difference. try_into ( ) . unwrap ( ) ) ,
4244
4345 // will be calculated during `.build()`
@@ -65,20 +67,18 @@ impl AdjustmentMarker {
6567/// This builder allows you to register multiple text replacements and their effects on ranges,
6668/// then build a tracker that can map positions between the original and adjusted text.
6769#[ derive( Debug ) ]
68- pub struct RangeAdjustmentsTrackerBuilder {
70+ pub struct TextRangeReplacementBuilder {
6971 markers : Vec < AdjustmentMarker > ,
72+ text : String ,
7073}
7174
72- impl Default for RangeAdjustmentsTrackerBuilder {
73- fn default ( ) -> Self {
74- Self :: new ( )
75- }
76- }
77-
78- impl RangeAdjustmentsTrackerBuilder {
75+ impl TextRangeReplacementBuilder {
7976 /// Creates a new empty builder for range adjustments tracking.
80- pub fn new ( ) -> Self {
81- Self { markers : vec ! [ ] }
77+ pub fn new ( text : & str ) -> Self {
78+ Self {
79+ markers : vec ! [ ] ,
80+ text : text. to_string ( ) ,
81+ }
8282 }
8383
8484 /// Registers a text replacement that affects range positions.
@@ -87,7 +87,7 @@ impl RangeAdjustmentsTrackerBuilder {
8787 ///
8888 /// * `original_range` - The range in the original text that will be replaced
8989 /// * `replacement_text` - The text that will replace the content in the original range
90- pub fn register_adjustment ( & mut self , original_range : TextRange , replacement_text : & str ) {
90+ pub fn replace_range ( & mut self , original_range : TextRange , replacement_text : & str ) {
9191 if usize:: from ( original_range. len ( ) ) == replacement_text. len ( ) {
9292 return ;
9393 }
@@ -105,7 +105,7 @@ impl RangeAdjustmentsTrackerBuilder {
105105 /// # Panics
106106 ///
107107 /// Panics if any adjustment involves shortening the text, as this is not yet implemented.
108- pub fn build ( mut self ) -> RangeAdjustmentsTracker {
108+ pub fn build ( mut self ) -> TextRangeReplacement {
109109 self . markers . sort_by_key ( |r| r. original_range . start ( ) ) ;
110110
111111 let mut total_offset: usize = 0 ;
@@ -132,8 +132,15 @@ impl RangeAdjustmentsTrackerBuilder {
132132 }
133133 }
134134
135- RangeAdjustmentsTracker {
135+ for marker in self . markers . iter ( ) . rev ( ) {
136+ let std_range: std:: ops:: Range < usize > = marker. original_range . into ( ) ;
137+ self . text
138+ . replace_range ( std_range, marker. replacement_txt . as_str ( ) ) ;
139+ }
140+
141+ TextRangeReplacement {
136142 markers : self . markers ,
143+ text : self . text ,
137144 }
138145 }
139146}
@@ -150,11 +157,17 @@ impl RangeAdjustmentsTrackerBuilder {
150157/// `$2` with `auth.users`, this tracker can map positions in the adjusted text
151158/// `"select email from auth.users"` back to positions in the original text.
152159#[ derive( Debug ) ]
153- pub struct RangeAdjustmentsTracker {
160+ pub struct TextRangeReplacement {
154161 markers : Vec < AdjustmentMarker > ,
162+ text : String ,
155163}
156164
157- impl RangeAdjustmentsTracker {
165+ impl TextRangeReplacement {
166+ /// Returns the adjusted text.
167+ pub fn text ( & self ) -> & str {
168+ & self . text
169+ }
170+
158171 /// Maps a position in the adjusted text back to its corresponding position in the original text.
159172 ///
160173 ///
@@ -208,68 +221,50 @@ impl RangeAdjustmentsTracker {
208221mod tests {
209222 use crate :: TextSize ;
210223
211- use crate :: range_adjustment_tracker:: RangeAdjustmentsTrackerBuilder ;
212-
213- fn range_of_substr ( full_str : & str , sub_str : & str ) -> Option < std:: ops:: Range < usize > > {
214- for ( i, _) in full_str. char_indices ( ) {
215- if & full_str[ i..i + sub_str. len ( ) ] == sub_str {
216- return Some ( i..i + sub_str. len ( ) ) ;
217- }
218- }
219- None
220- }
224+ use crate :: text_range_replacement:: TextRangeReplacementBuilder ;
221225
222226 #[ test]
223227 fn tracks_adjustments ( ) {
224- let mut sql = "select $1 from $2 where $3 = $4 limit 5;" . to_string ( ) ;
228+ let sql = "select $1 from $2 where $3 = $4 limit 5;" ;
225229
226230 let range_1: std:: ops:: Range < usize > = 7 ..9 ;
227231 let range_2: std:: ops:: Range < usize > = 15 ..17 ;
228232 let range_3: std:: ops:: Range < usize > = 24 ..26 ;
229233 let range_4: std:: ops:: Range < usize > = 29 ..31 ;
230234 let og_end = sql. len ( ) ;
231235
232- let mut adjustment_tracker_builder = RangeAdjustmentsTrackerBuilder :: new ( ) ;
236+ let mut replacement_builder = TextRangeReplacementBuilder :: new ( sql ) ;
233237
234238 let replacement_4 = "'00000000-0000-0000-0000-000000000000'" ;
235- adjustment_tracker_builder
236- . register_adjustment ( range_4. clone ( ) . try_into ( ) . unwrap ( ) , replacement_4) ;
237- sql. replace_range ( range_4. clone ( ) , replacement_4) ;
238-
239239 let replacement_3 = "id" ;
240- adjustment_tracker_builder
241- . register_adjustment ( range_3. clone ( ) . try_into ( ) . unwrap ( ) , replacement_3) ;
242- sql. replace_range ( range_3. clone ( ) , replacement_3) ;
243-
244240 let replacement_2 = "auth.users" ;
245- adjustment_tracker_builder
246- . register_adjustment ( range_2. clone ( ) . try_into ( ) . unwrap ( ) , replacement_2) ;
247- sql. replace_range ( range_2. clone ( ) , replacement_2) ;
248-
249241 let replacement_1 = "email" ;
250- adjustment_tracker_builder
251- . register_adjustment ( range_1. clone ( ) . try_into ( ) . unwrap ( ) , replacement_1) ;
252- sql. replace_range ( range_1. clone ( ) , replacement_1) ;
242+
243+ // start in the middle – the tracker builder can deal with unordered registers
244+ replacement_builder. replace_range ( range_2. clone ( ) . try_into ( ) . unwrap ( ) , replacement_2) ;
245+ replacement_builder. replace_range ( range_4. clone ( ) . try_into ( ) . unwrap ( ) , replacement_4) ;
246+ replacement_builder. replace_range ( range_1. clone ( ) . try_into ( ) . unwrap ( ) , replacement_1) ;
247+ replacement_builder. replace_range ( range_3. clone ( ) . try_into ( ) . unwrap ( ) , replacement_3) ;
248+
249+ let text_replacement = replacement_builder. build ( ) ;
253250
254251 assert_eq ! (
255- sql . as_str ( ) ,
252+ text_replacement . text ( ) ,
256253 "select email from auth.users where id = '00000000-0000-0000-0000-000000000000' limit 5;"
257254 ) ;
258255
259- let adjustment_tracker = adjustment_tracker_builder. build ( ) ;
260-
261- let repl_range_1 = range_of_substr ( sql. as_str ( ) , replacement_1) . unwrap ( ) ;
262- let repl_range_2 = range_of_substr ( sql. as_str ( ) , replacement_2) . unwrap ( ) ;
263- let repl_range_3 = range_of_substr ( sql. as_str ( ) , replacement_3) . unwrap ( ) ;
264- let repl_range_4 = range_of_substr ( sql. as_str ( ) , replacement_4) . unwrap ( ) ;
256+ let repl_range_1 = 7 ..12 ;
257+ let repl_range_2 = 18 ..28 ;
258+ let repl_range_3 = 35 ..37 ;
259+ let repl_range_4 = 40 ..78 ;
265260
266261 // |select |email from auth.users where id = '00000000-0000-0000-0000-000000000000' limit 5;
267262 // maps to
268263 // |select |$1 from $2 where $3 = $4 limit 5;
269264 for i in 0 ..repl_range_1. clone ( ) . start {
270265 let between_og_0_1 = 0 ..range_1. start ;
271266 let adjusted =
272- adjustment_tracker . to_original_position ( TextSize :: new ( i. try_into ( ) . unwrap ( ) ) ) ;
267+ text_replacement . to_original_position ( TextSize :: new ( i. try_into ( ) . unwrap ( ) ) ) ;
273268 assert ! ( between_og_0_1. contains( & usize :: from( adjusted) ) ) ;
274269 }
275270
@@ -278,7 +273,7 @@ mod tests {
278273 // select |$1| from $2 where $3 = $4 limit 5;
279274 for i in repl_range_1. clone ( ) {
280275 let pos = TextSize :: new ( i. try_into ( ) . unwrap ( ) ) ;
281- let og_pos = adjustment_tracker . to_original_position ( pos) ;
276+ let og_pos = text_replacement . to_original_position ( pos) ;
282277 assert ! ( range_1. contains( & usize :: from( og_pos) ) ) ;
283278 }
284279
@@ -288,7 +283,7 @@ mod tests {
288283 for i in repl_range_1. end ..repl_range_2. clone ( ) . start {
289284 let between_og_1_2 = range_1. end ..range_2. start ;
290285 let adjusted =
291- adjustment_tracker . to_original_position ( TextSize :: new ( i. try_into ( ) . unwrap ( ) ) ) ;
286+ text_replacement . to_original_position ( TextSize :: new ( i. try_into ( ) . unwrap ( ) ) ) ;
292287 assert ! ( between_og_1_2. contains( & usize :: from( adjusted) ) ) ;
293288 }
294289
@@ -297,7 +292,7 @@ mod tests {
297292 // select $1 from |$2| where $3 = $4 limit 5;
298293 for i in repl_range_2. clone ( ) {
299294 let pos = TextSize :: new ( i. try_into ( ) . unwrap ( ) ) ;
300- let og_pos = adjustment_tracker . to_original_position ( pos) ;
295+ let og_pos = text_replacement . to_original_position ( pos) ;
301296 assert ! ( range_2. contains( & usize :: from( og_pos) ) ) ;
302297 }
303298
@@ -307,7 +302,7 @@ mod tests {
307302 for i in repl_range_2. end ..repl_range_3. clone ( ) . start {
308303 let between_og_2_3 = range_2. end ..range_3. start ;
309304 let adjusted =
310- adjustment_tracker . to_original_position ( TextSize :: new ( i. try_into ( ) . unwrap ( ) ) ) ;
305+ text_replacement . to_original_position ( TextSize :: new ( i. try_into ( ) . unwrap ( ) ) ) ;
311306 assert ! ( between_og_2_3. contains( & usize :: from( adjusted) ) ) ;
312307 }
313308
@@ -318,7 +313,7 @@ mod tests {
318313 // NOTE: this isn't even hanlded by the tracker, since `id` has the same length as `$3`
319314 for i in repl_range_3. clone ( ) {
320315 let pos = TextSize :: new ( i. try_into ( ) . unwrap ( ) ) ;
321- let og_pos = adjustment_tracker . to_original_position ( pos) ;
316+ let og_pos = text_replacement . to_original_position ( pos) ;
322317 assert ! ( range_3. contains( & usize :: from( og_pos) ) ) ;
323318 }
324319
@@ -328,7 +323,7 @@ mod tests {
328323 for i in repl_range_3. end ..repl_range_4. clone ( ) . start {
329324 let between_og_3_4 = range_3. end ..range_4. start ;
330325 let adjusted =
331- adjustment_tracker . to_original_position ( TextSize :: new ( i. try_into ( ) . unwrap ( ) ) ) ;
326+ text_replacement . to_original_position ( TextSize :: new ( i. try_into ( ) . unwrap ( ) ) ) ;
332327 assert ! ( between_og_3_4. contains( & usize :: from( adjusted) ) ) ;
333328 }
334329
@@ -337,7 +332,7 @@ mod tests {
337332 // select $1 from $2 where $3 = |$4| limit 5;
338333 for i in repl_range_4. clone ( ) {
339334 let pos = TextSize :: new ( i. try_into ( ) . unwrap ( ) ) ;
340- let og_pos = adjustment_tracker . to_original_position ( pos) ;
335+ let og_pos = text_replacement . to_original_position ( pos) ;
341336 assert ! ( range_4. contains( & usize :: from( og_pos) ) ) ;
342337 }
343338
@@ -347,7 +342,7 @@ mod tests {
347342 for i in repl_range_4. end ..sql. len ( ) {
348343 let between_og_4_end = range_4. end ..og_end;
349344 let adjusted =
350- adjustment_tracker . to_original_position ( TextSize :: new ( i. try_into ( ) . unwrap ( ) ) ) ;
345+ text_replacement . to_original_position ( TextSize :: new ( i. try_into ( ) . unwrap ( ) ) ) ;
351346 assert ! ( between_og_4_end. contains( & usize :: from( adjusted) ) ) ;
352347 }
353348 }
0 commit comments