@@ -90,28 +90,22 @@ impl TextEdit {
90
90
_ => ( ) ,
91
91
}
92
92
93
- let mut total_len = TextSize :: of ( & * text) ;
93
+ let text_size = TextSize :: of ( & * text) ;
94
+ let mut total_len = text_size. clone ( ) ;
94
95
for indel in & self . indels {
95
96
total_len += TextSize :: of ( & indel. insert ) ;
96
- total_len -= indel. delete . end ( ) - indel . delete . start ( ) ;
97
+ total_len -= indel. delete . len ( ) ;
97
98
}
98
- let mut buf = String :: with_capacity ( total_len. into ( ) ) ;
99
- let mut prev = 0 ;
100
- for indel in & self . indels {
101
- let start: usize = indel. delete . start ( ) . into ( ) ;
102
- let end: usize = indel. delete . end ( ) . into ( ) ;
103
- if start > prev {
104
- buf. push_str ( & text[ prev..start] ) ;
105
- }
106
- buf. push_str ( & indel. insert ) ;
107
- prev = end;
99
+
100
+ if let Some ( additional) = total_len. checked_sub ( text_size. into ( ) ) {
101
+ text. reserve ( additional. into ( ) ) ;
102
+ }
103
+
104
+ for indel in self . indels . iter ( ) . rev ( ) {
105
+ indel. apply ( text) ;
108
106
}
109
- buf. push_str ( & text[ prev..text. len ( ) ] ) ;
110
- assert_eq ! ( TextSize :: of( & buf) , total_len) ;
111
107
112
- // FIXME: figure out a way to mutate the text in-place or reuse the
113
- // memory in some other way
114
- * text = buf;
108
+ assert_eq ! ( TextSize :: of( & * text) , total_len) ;
115
109
}
116
110
117
111
pub fn union ( & mut self , other : TextEdit ) -> Result < ( ) , TextEdit > {
@@ -203,3 +197,45 @@ fn check_disjoint_and_sort(indels: &mut [impl std::borrow::Borrow<Indel>]) -> bo
203
197
l. delete . end ( ) <= r. delete . start ( ) || l == r
204
198
} )
205
199
}
200
+
201
+ #[ cfg( test) ]
202
+ mod tests {
203
+ use super :: { TextEdit , TextEditBuilder , TextRange } ;
204
+
205
+ fn range ( start : u32 , end : u32 ) -> TextRange {
206
+ TextRange :: new ( start. into ( ) , end. into ( ) )
207
+ }
208
+
209
+ #[ test]
210
+ fn test_apply ( ) {
211
+ let mut text = "_11h1_2222_xx3333_4444_6666" . to_string ( ) ;
212
+ let mut builder = TextEditBuilder :: default ( ) ;
213
+ builder. replace ( range ( 3 , 4 ) , "1" . to_string ( ) ) ;
214
+ builder. delete ( range ( 11 , 13 ) ) ;
215
+ builder. insert ( 22 . into ( ) , "_5555" . to_string ( ) ) ;
216
+
217
+ let text_edit = builder. finish ( ) ;
218
+ text_edit. apply ( & mut text) ;
219
+
220
+ assert_eq ! ( text, "_1111_2222_3333_4444_5555_6666" )
221
+ }
222
+
223
+ #[ test]
224
+ fn test_union ( ) {
225
+ let mut edit1 = TextEdit :: delete ( range ( 7 , 11 ) ) ;
226
+ let mut builder = TextEditBuilder :: default ( ) ;
227
+ builder. delete ( range ( 1 , 5 ) ) ;
228
+ builder. delete ( range ( 13 , 17 ) ) ;
229
+
230
+ let edit2 = builder. finish ( ) ;
231
+ assert ! ( edit1. union ( edit2) . is_ok( ) ) ;
232
+ assert_eq ! ( edit1. indels. len( ) , 3 ) ;
233
+ }
234
+
235
+ #[ test]
236
+ fn test_union_panics ( ) {
237
+ let mut edit1 = TextEdit :: delete ( range ( 7 , 11 ) ) ;
238
+ let edit2 = TextEdit :: delete ( range ( 9 , 13 ) ) ;
239
+ assert ! ( edit1. union ( edit2) . is_err( ) ) ;
240
+ }
241
+ }
0 commit comments