@@ -122,13 +122,22 @@ impl Document {
122122 // special case: if no statement is affected, the affected range is between the prev and
123123 // the next statement
124124 if affected. is_empty ( ) {
125- let start = self
125+ // since we do not now whether the change should be part of the previous statement, we
126+ // will take the range form the start of the previous statement to the start of the
127+ // next statement. if the resulting split has length one, we will modify it instead.
128+
129+ let ( from_stmt_index, from_stmt_range) = self
126130 . statements
127131 . iter ( )
132+ . enumerate ( )
128133 . rev ( )
129- . find ( |( _, r) | r. end ( ) <= change. range . unwrap ( ) . start ( ) )
130- . map ( |( _, r) | r. end ( ) )
131- . unwrap_or ( TextSize :: new ( 0 ) ) ;
134+ . find ( |( _, ( _, r) ) | r. start ( ) <= change. range . unwrap ( ) . start ( ) )
135+ . map ( |( i, ( _, r) ) | ( i, * r) )
136+ . unwrap_or ( ( 0 , TextRange :: empty ( TextSize :: new ( 0 ) ) ) ) ;
137+
138+
139+ let start = from_stmt_range. start ( ) ;
140+
132141 let end = self
133142 . statements
134143 . iter ( )
@@ -141,24 +150,49 @@ impl Document {
141150 . get ( usize:: from ( start) ..usize:: from ( end) )
142151 . unwrap ( ) ;
143152
144- // add new statements
145- for range in pg_statement_splitter:: split ( affected) . ranges {
146- let doc_range = range + start;
147- match self
148- . statements
149- . binary_search_by ( |( _, r) | r. start ( ) . cmp ( & doc_range. start ( ) ) )
150- {
151- Ok ( _) => { }
152- Err ( pos) => {
153- let new_id = self . id_generator . next ( ) ;
154- self . statements . insert ( pos, ( new_id, doc_range) ) ;
155- changed. push ( StatementChange :: Added ( Statement {
156- ref_ : StatementRef {
157- path : self . path . clone ( ) ,
158- id : new_id,
159- } ,
160- text : new_content[ doc_range] . to_string ( ) ,
161- } ) ) ;
153+ let new_ranges = pg_statement_splitter:: split ( affected) . ranges ;
154+
155+ if new_ranges. len ( ) == 1 && !from_stmt_range. is_empty ( ) {
156+ if !change. is_whitespace ( ) {
157+ // modify previous statement
158+ let new_stmt = & new_ranges[ 0 ] ;
159+
160+ let new_id = self . id_generator . next ( ) ;
161+ let old_stmt = self . statement ( & self . statements [ from_stmt_index] ) ;
162+ self . statements [ from_stmt_index] = ( new_id, new_stmt. add ( start) ) ;
163+
164+ println ! ( "change prev" ) ;
165+ let changed_stmt = ChangedStatement {
166+ old : old_stmt,
167+ new_ref : self . statement_ref ( & self . statements [ from_stmt_index] ) ,
168+ // change must be relative to statement
169+ // TODO: range and text must be filled up with whitespaces
170+ range : change. range . unwrap ( ) . sub ( from_stmt_range. start ( ) ) ,
171+ text : change. text . clone ( ) ,
172+ } ;
173+
174+ changed. push ( StatementChange :: Modified ( changed_stmt) ) ;
175+ }
176+ } else {
177+ // add new statements
178+ for range in new_ranges {
179+ let doc_range = range + start;
180+ match self
181+ . statements
182+ . binary_search_by ( |( _, r) | r. start ( ) . cmp ( & doc_range. start ( ) ) )
183+ {
184+ Ok ( _) => { }
185+ Err ( pos) => {
186+ let new_id = self . id_generator . next ( ) ;
187+ self . statements . insert ( pos, ( new_id, doc_range) ) ;
188+ changed. push ( StatementChange :: Added ( Statement {
189+ ref_ : StatementRef {
190+ path : self . path . clone ( ) ,
191+ id : new_id,
192+ } ,
193+ text : new_content[ doc_range] . to_string ( ) ,
194+ } ) ) ;
195+ }
162196 }
163197 }
164198 }
@@ -204,22 +238,25 @@ impl Document {
204238 let ranges = pg_statement_splitter:: split ( changed_content) . ranges ;
205239
206240 if affected. len ( ) == 1 && ranges. len ( ) == 1 {
207- // from one to one, so we do a modification
208- let stmt = & affected[ 0 ] ;
209- let new_stmt = & ranges[ 0 ] ;
210-
211- let new_id = self . id_generator . next ( ) ;
212- self . statements [ stmt. 0 ] = ( new_id, new_stmt. add ( start) ) ;
213-
214- let changed_stmt = ChangedStatement {
215- old : self . statement ( & stmt. 1 ) ,
216- new_ref : self . statement_ref ( & self . statements [ stmt. 0 ] ) ,
217- // change must be relative to statement
218- range : change. range . unwrap ( ) . sub ( stmt. 1 . 1 . start ( ) ) ,
219- text : change. text . clone ( ) ,
220- } ;
221-
222- changed. push ( StatementChange :: Modified ( changed_stmt) ) ;
241+ if !change. is_whitespace ( ) {
242+ // from one to one, so we do a modification
243+ let stmt = & affected[ 0 ] ;
244+ let new_stmt = & ranges[ 0 ] ;
245+
246+ let new_id = self . id_generator . next ( ) ;
247+ self . statements [ stmt. 0 ] = ( new_id, new_stmt. add ( start) ) ;
248+
249+ println ! ( "change one to one" ) ;
250+ let changed_stmt = ChangedStatement {
251+ old : self . statement ( & stmt. 1 ) ,
252+ new_ref : self . statement_ref ( & self . statements [ stmt. 0 ] ) ,
253+ // change must be relative to statement
254+ range : change. range . unwrap ( ) . sub ( stmt. 1 . 1 . start ( ) ) ,
255+ text : change. text . clone ( ) ,
256+ } ;
257+
258+ changed. push ( StatementChange :: Modified ( changed_stmt) ) ;
259+ }
223260 } else {
224261 // delete and add new ones
225262 for ( _, ( id, r) ) in & affected {
@@ -282,7 +319,7 @@ fn apply_text_change(text: &str, range: Option<TextRange>, change_text: &str) ->
282319
283320impl ChangeParams {
284321 pub fn is_whitespace ( & self ) -> bool {
285- self . text . chars ( ) . all ( char:: is_whitespace)
322+ self . text . chars ( ) . count ( ) > 0 && self . text . chars ( ) . all ( char:: is_whitespace)
286323 }
287324
288325 pub fn diff_size ( & self ) -> TextSize {
@@ -362,6 +399,81 @@ mod tests {
362399 assert_document_integrity ( & d) ;
363400 }
364401
402+ #[ test]
403+ fn julians_sample ( ) {
404+ let path = PgLspPath :: new ( "test.sql" ) ;
405+ let input = "select\n *\n from\n test;\n \n select\n \n alter table test\n drop column id;" ;
406+ let mut d = Document :: new ( path. clone ( ) , input. to_string ( ) , 0 ) ;
407+
408+ assert_eq ! ( d. statements. len( ) , 3 ) ;
409+ println ! ( "{:#?}" , d. statements) ;
410+
411+ let change1 = ChangeFileParams {
412+ path : path. clone ( ) ,
413+ version : 1 ,
414+ changes : vec ! [ ChangeParams {
415+ text: " " . to_string( ) ,
416+ range: Some ( TextRange :: new( 31 . into( ) , 31 . into( ) ) ) ,
417+ } ] ,
418+ } ;
419+
420+ let changed1 = d. apply_file_change ( & change1) ;
421+ println ! ( "after change 1" ) ;
422+ println ! ( "{:#?}" , d. content) ;
423+ println ! ( "{:#?}" , d. statements) ;
424+ println ! ( "{:#?}" , changed1) ;
425+
426+ // problem: this creates a new statement
427+ let change2 = ChangeFileParams {
428+ path : path. clone ( ) ,
429+ version : 2 ,
430+ changes : vec ! [ ChangeParams {
431+ text: ";" . to_string( ) ,
432+ range: Some ( TextRange :: new( 32 . into( ) , 32 . into( ) ) ) ,
433+ } ] ,
434+ } ;
435+
436+ let changed2 = d. apply_file_change ( & change2) ;
437+ println ! ( "after change 2" ) ;
438+ println ! ( "{:#?}" , d. content) ;
439+ println ! ( "{:#?}" , d. statements) ;
440+ println ! ( "{:#?}" , changed2) ;
441+
442+ let change3 = ChangeFileParams {
443+ path : path. clone ( ) ,
444+ version : 3 ,
445+ changes : vec ! [ ChangeParams {
446+ text: "" . to_string( ) ,
447+ range: Some ( TextRange :: new( 32 . into( ) , 33 . into( ) ) ) ,
448+ } ] ,
449+ } ;
450+
451+ let changed3 = d. apply_file_change ( & change3) ;
452+ println ! ( "after change 3" ) ;
453+ println ! ( "{:#?}" , d. content) ;
454+ println ! ( "{:#?}" , d. statements) ;
455+ println ! ( "{:#?}" , changed3) ;
456+
457+ //
458+ // assert_eq!(changed.len(), 4);
459+ // assert!(matches!(
460+ // changed[0],
461+ // StatementChange::Deleted(StatementRef { id: 0, .. })
462+ // ));
463+ // assert!(matches!(
464+ // changed[1],
465+ // StatementChange::Deleted(StatementRef { id: 1, .. })
466+ // ));
467+ // assert!(
468+ // matches!(&changed[2], StatementChange::Added(Statement { ref_: _, text }) if text == "select id,test from users;")
469+ // );
470+ // assert!(
471+ // matches!(&changed[3], StatementChange::Added(Statement { ref_: _, text }) if text == "select 1;")
472+ // );
473+ //
474+ assert_document_integrity ( & d) ;
475+ }
476+
365477 #[ test]
366478 fn across_statements ( ) {
367479 let path = PgLspPath :: new ( "test.sql" ) ;
0 commit comments