@@ -294,7 +294,10 @@ impl Document {
294294 new_stmt_text : changed_content[ new_ranges[ 0 ] ] . to_string ( ) ,
295295 // change must be relative to the statement
296296 change_text : change. text . clone ( ) ,
297- change_range : change_range. sub ( old_range. start ( ) ) ,
297+ // make sure we always have a valid range >= 0
298+ change_range : change_range
299+ . checked_sub ( old_range. start ( ) )
300+ . unwrap_or ( change_range. sub ( change_range. start ( ) ) ) ,
298301 } ) ) ;
299302 }
300303
@@ -931,6 +934,46 @@ mod tests {
931934 assert_document_integrity ( & d) ;
932935 }
933936
937+ #[ test]
938+ fn removing_newline_at_the_beginning ( ) {
939+ let path = PgLTPath :: new ( "test.sql" ) ;
940+ let input = "\n " ;
941+
942+ let mut d = Document :: new ( path. clone ( ) , input. to_string ( ) , 1 ) ;
943+
944+ assert_eq ! ( d. positions. len( ) , 0 ) ;
945+
946+ let change = ChangeFileParams {
947+ path : path. clone ( ) ,
948+ version : 2 ,
949+ changes : vec ! [ ChangeParams {
950+ text: "\n begin;\n \n select 1\n \n rollback;\n " . to_string( ) ,
951+ range: Some ( TextRange :: new( 0 . into( ) , 1 . into( ) ) ) ,
952+ } ] ,
953+ } ;
954+
955+ let changes = d. apply_file_change ( & change) ;
956+
957+ assert_eq ! ( changes. len( ) , 3 ) ;
958+
959+ assert_document_integrity ( & d) ;
960+
961+ let change2 = ChangeFileParams {
962+ path : path. clone ( ) ,
963+ version : 3 ,
964+ changes : vec ! [ ChangeParams {
965+ text: "" . to_string( ) ,
966+ range: Some ( TextRange :: new( 0 . into( ) , 1 . into( ) ) ) ,
967+ } ] ,
968+ } ;
969+
970+ let changes2 = d. apply_file_change ( & change2) ;
971+
972+ assert_eq ! ( changes2. len( ) , 1 ) ;
973+
974+ assert_document_integrity ( & d) ;
975+ }
976+
934977 #[ test]
935978 fn apply_changes_at_end_of_statement ( ) {
936979 let path = PgLTPath :: new ( "test.sql" ) ;
0 commit comments