Skip to content

Commit 001318d

Browse files
committed
lets get into the mess...
1 parent 603a3c9 commit 001318d

File tree

1 file changed

+151
-39
lines changed
  • crates/pg_workspace_new/src/workspace/server

1 file changed

+151
-39
lines changed

crates/pg_workspace_new/src/workspace/server/change.rs

Lines changed: 151 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -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

283320
impl 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 *\nfrom\n test;\n\nselect\n\nalter table test\ndrop 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

Comments
 (0)