@@ -140,6 +140,8 @@ impl Document {
140
140
let mut start = change_range. start ( ) ;
141
141
let mut end = change_range. end ( ) . min ( content_size) ;
142
142
143
+ let is_trim = change_range. start ( ) >= content_size;
144
+
143
145
let mut affected_indices = Vec :: new ( ) ;
144
146
let mut prev_index = None ;
145
147
let mut next_index = None ;
@@ -157,23 +159,20 @@ impl Document {
157
159
}
158
160
}
159
161
160
- let start_incl = prev_index
162
+ let first_affected_stmt_start = prev_index
161
163
. map ( |i| self . positions [ i] . 1 . start ( ) )
162
164
. unwrap_or ( start) ;
163
- let end_incl = next_index
165
+
166
+ let mut last_affected_stmt_end = next_index
164
167
. map ( |i| self . positions [ i] . 1 . end ( ) )
165
168
. unwrap_or_else ( || end) ;
166
169
167
- let end_incl = if is_addition {
168
- end_incl. add ( diff_size)
169
- } else {
170
- end_incl. sub ( diff_size)
171
- } ;
172
-
173
- let end = if is_addition {
174
- end. add ( diff_size)
175
- } else {
176
- end. sub ( diff_size)
170
+ if is_addition {
171
+ end = end. add ( diff_size) ;
172
+ last_affected_stmt_end = last_affected_stmt_end. add ( diff_size) ;
173
+ } else if !is_trim {
174
+ end = end. sub ( diff_size) ;
175
+ last_affected_stmt_end = last_affected_stmt_end. sub ( diff_size)
177
176
} ;
178
177
179
178
Affected {
@@ -185,8 +184,10 @@ impl Document {
185
184
prev_index,
186
185
next_index,
187
186
full_affected_range : TextRange :: new (
188
- start_incl,
189
- end_incl. min ( content_size) . max ( start_incl) ,
187
+ first_affected_stmt_start,
188
+ last_affected_stmt_end
189
+ . min ( content_size)
190
+ . max ( first_affected_stmt_start) ,
190
191
) ,
191
192
}
192
193
}
@@ -221,6 +222,7 @@ impl Document {
221
222
let mut changed: Vec < StatementChange > = Vec :: with_capacity ( self . positions . len ( ) ) ;
222
223
223
224
let change_range = change. range . unwrap ( ) ;
225
+ let previous_content = self . content . clone ( ) ;
224
226
let new_content = change. apply_to_text ( & self . content ) ;
225
227
226
228
// we first need to determine the affected range and all affected statements, as well as
@@ -261,15 +263,15 @@ impl Document {
261
263
let new_range = new_ranges[ 0 ] . add ( affected_range. start ( ) ) ;
262
264
let ( old_id, old_range) = self . positions [ affected_idx] . clone ( ) ;
263
265
264
- // move all statements after the afffected range
266
+ // move all statements after the affected range
265
267
self . move_ranges ( old_range. end ( ) , change. diff_size ( ) , change. is_addition ( ) ) ;
266
268
267
269
let new_id = self . id_generator . next ( ) ;
268
270
self . positions [ affected_idx] = ( new_id. clone ( ) , new_range) ;
269
271
270
272
changed. push ( StatementChange :: Modified ( ModifiedStatement {
271
273
old_stmt : old_id. clone ( ) ,
272
- old_stmt_text : self . content [ old_range] . to_string ( ) ,
274
+ old_stmt_text : previous_content [ old_range] . to_string ( ) ,
273
275
274
276
new_stmt : new_id,
275
277
new_stmt_text : changed_content[ new_ranges[ 0 ] ] . to_string ( ) ,
@@ -1285,4 +1287,139 @@ mod tests {
1285
1287
1286
1288
assert_document_integrity ( & d) ;
1287
1289
}
1290
+
1291
+ #[ test]
1292
+ fn remove_trailing_whitespace ( ) {
1293
+ let path = PgTPath :: new ( "test.sql" ) ;
1294
+
1295
+ let mut doc = Document :: new ( path. clone ( ) , "select * from " . to_string ( ) , 0 ) ;
1296
+
1297
+ let change = ChangeFileParams {
1298
+ path : path. clone ( ) ,
1299
+ version : 1 ,
1300
+ changes : vec ! [ ChangeParams {
1301
+ text: "" . to_string( ) ,
1302
+ range: Some ( TextRange :: new( 13 . into( ) , 14 . into( ) ) ) ,
1303
+ } ] ,
1304
+ } ;
1305
+
1306
+ let changed = doc. apply_file_change ( & change) ;
1307
+
1308
+ assert_eq ! ( doc. content, "select * from" ) ;
1309
+
1310
+ assert_eq ! ( changed. len( ) , 1 ) ;
1311
+
1312
+ match & changed[ 0 ] {
1313
+ StatementChange :: Modified ( stmt) => {
1314
+ let ModifiedStatement {
1315
+ change_range,
1316
+ change_text,
1317
+ new_stmt_text,
1318
+ old_stmt_text,
1319
+ ..
1320
+ } = stmt;
1321
+
1322
+ assert_eq ! ( change_range, & TextRange :: new( 13 . into( ) , 14 . into( ) ) ) ;
1323
+ assert_eq ! ( change_text, "" ) ;
1324
+ assert_eq ! ( new_stmt_text, "select * from" ) ;
1325
+
1326
+ // the whitespace was not considered
1327
+ // to be a part of the statement
1328
+ assert_eq ! ( old_stmt_text, "select * from" ) ;
1329
+ }
1330
+
1331
+ _ => assert ! ( false , "Did not yield a modified statement." ) ,
1332
+ }
1333
+
1334
+ assert_document_integrity ( & doc) ;
1335
+ }
1336
+
1337
+ #[ test]
1338
+ fn remove_trailing_whitespace_and_last_char ( ) {
1339
+ let path = PgTPath :: new ( "test.sql" ) ;
1340
+
1341
+ let mut doc = Document :: new ( path. clone ( ) , "select * from " . to_string ( ) , 0 ) ;
1342
+
1343
+ let change = ChangeFileParams {
1344
+ path : path. clone ( ) ,
1345
+ version : 1 ,
1346
+ changes : vec ! [ ChangeParams {
1347
+ text: "" . to_string( ) ,
1348
+ range: Some ( TextRange :: new( 12 . into( ) , 14 . into( ) ) ) ,
1349
+ } ] ,
1350
+ } ;
1351
+
1352
+ let changed = doc. apply_file_change ( & change) ;
1353
+
1354
+ assert_eq ! ( doc. content, "select * fro" ) ;
1355
+
1356
+ assert_eq ! ( changed. len( ) , 1 ) ;
1357
+
1358
+ match & changed[ 0 ] {
1359
+ StatementChange :: Modified ( stmt) => {
1360
+ let ModifiedStatement {
1361
+ change_range,
1362
+ change_text,
1363
+ new_stmt_text,
1364
+ old_stmt_text,
1365
+ ..
1366
+ } = stmt;
1367
+
1368
+ assert_eq ! ( change_range, & TextRange :: new( 12 . into( ) , 14 . into( ) ) ) ;
1369
+ assert_eq ! ( change_text, "" ) ;
1370
+ assert_eq ! ( new_stmt_text, "select * fro" ) ;
1371
+
1372
+ // the whitespace was not considered
1373
+ // to be a part of the statement
1374
+ assert_eq ! ( old_stmt_text, "select * from" ) ;
1375
+ }
1376
+
1377
+ _ => assert ! ( false , "Did not yield a modified statement." ) ,
1378
+ }
1379
+
1380
+ assert_document_integrity ( & doc) ;
1381
+ }
1382
+
1383
+ #[ test]
1384
+ fn remove_inbetween_whitespace ( ) {
1385
+ let path = PgTPath :: new ( "test.sql" ) ;
1386
+
1387
+ let mut doc = Document :: new ( path. clone ( ) , "select * from users" . to_string ( ) , 0 ) ;
1388
+
1389
+ let change = ChangeFileParams {
1390
+ path : path. clone ( ) ,
1391
+ version : 1 ,
1392
+ changes : vec ! [ ChangeParams {
1393
+ text: "" . to_string( ) ,
1394
+ range: Some ( TextRange :: new( 9 . into( ) , 11 . into( ) ) ) ,
1395
+ } ] ,
1396
+ } ;
1397
+
1398
+ let changed = doc. apply_file_change ( & change) ;
1399
+
1400
+ assert_eq ! ( doc. content, "select * from users" ) ;
1401
+
1402
+ assert_eq ! ( changed. len( ) , 1 ) ;
1403
+
1404
+ match & changed[ 0 ] {
1405
+ StatementChange :: Modified ( stmt) => {
1406
+ let ModifiedStatement {
1407
+ change_range,
1408
+ change_text,
1409
+ new_stmt_text,
1410
+ old_stmt_text,
1411
+ ..
1412
+ } = stmt;
1413
+
1414
+ assert_eq ! ( change_range, & TextRange :: new( 9 . into( ) , 11 . into( ) ) ) ;
1415
+ assert_eq ! ( change_text, "" ) ;
1416
+ assert_eq ! ( old_stmt_text, "select * from users" ) ;
1417
+ assert_eq ! ( new_stmt_text, "select * from users" ) ;
1418
+ }
1419
+
1420
+ _ => assert ! ( false , "Did not yield a modified statement." ) ,
1421
+ }
1422
+
1423
+ assert_document_integrity ( & doc) ;
1424
+ }
1288
1425
}
0 commit comments