From 5fadbf77d47ef27603c4e832f8ba42068a393e4f Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Thu, 8 Jun 2023 17:39:04 +0300 Subject: [PATCH] Implement InlayHint sync method and fix the bugs Co-Authored-By: Antonio Scandurra --- crates/editor/src/display_map/inlay_map.rs | 63 ++++++++++++++-------- crates/editor/src/editor.rs | 2 + crates/project/src/lsp_command.rs | 1 - 3 files changed, 42 insertions(+), 24 deletions(-) diff --git a/crates/editor/src/display_map/inlay_map.rs b/crates/editor/src/display_map/inlay_map.rs index 8afd6d5fdc87d4087a72caf85ae6d56fcdc8778a..d944074558434c2947b4c602afc6671134795677 100644 --- a/crates/editor/src/display_map/inlay_map.rs +++ b/crates/editor/src/display_map/inlay_map.rs @@ -177,7 +177,9 @@ impl<'a> Iterator for InlayChunks<'a> { *chunk = self.suggestion_chunks.next().unwrap(); } - let (prefix, suffix) = chunk.text.split_at(transform.len); + let (prefix, suffix) = chunk + .text + .split_at(cmp::min(transform.len, chunk.text.len())); chunk.text = suffix; self.output_offset.0 += prefix.len(); Chunk { @@ -264,23 +266,48 @@ impl InlayMap { snapshot.version += 1; } - let mut inlay_edits = Vec::new(); + let mut new_transforms = SumTree::new(); + let mut cursor = snapshot.transforms.cursor::(); + let mut suggestion_edits = suggestion_edits.iter().peekable(); + + while let Some(suggestion_edit) = suggestion_edits.next() { + if suggestion_edit.old.start >= *cursor.start() { + new_transforms.push_tree( + cursor.slice(&suggestion_edit.old.start, Bias::Right, &()), + &(), + ); + } - dbg!(self.inlays.len()); + if suggestion_edit.old.end > cursor.end(&()) { + cursor.seek_forward(&suggestion_edit.old.end, Bias::Right, &()); + } - for suggestion_edit in suggestion_edits { - let old = suggestion_edit.old; - let new = suggestion_edit.new; - // TODO kb copied from suggestion_map - inlay_edits.push(InlayEdit { - old: InlayOffset(old.start.0)..InlayOffset(old.end.0), - new: InlayOffset(old.start.0)..InlayOffset(new.end.0), - }) + let transform_start = SuggestionOffset(new_transforms.summary().input.len); + let mut transform_end = suggestion_edit.new.end; + if suggestion_edits + .peek() + .map_or(true, |edit| edit.old.start > cursor.end(&())) + { + transform_end += cursor.end(&()) - suggestion_edit.old.end; + cursor.next(&()); + } + new_transforms.push( + Transform::Isomorphic(suggestion_snapshot.text_summary_for_range( + suggestion_snapshot.to_point(transform_start) + ..suggestion_snapshot.to_point(transform_end), + )), + &(), + ); } + new_transforms.push_tree(cursor.suffix(&()), &()); + drop(cursor); + snapshot.suggestion_snapshot = suggestion_snapshot; + dbg!(new_transforms.items(&())); + snapshot.transforms = new_transforms; - (snapshot.clone(), inlay_edits) + (snapshot.clone(), Default::default()) } pub fn splice( @@ -580,7 +607,7 @@ mod tests { let (inlay_snapshot, _) = inlay_map.sync(suggestion_snapshot.clone(), suggestion_edits); assert_eq!(inlay_snapshot.text(), "XYZabc|123|defghi"); - ////////// case: replacing the anchor that got the hint: it should disappear, then undo and it should reappear again + ////////// case: replacing the anchor that got the hint: it should disappear buffer.update(cx, |buffer, cx| buffer.edit([(2..3, "C")], None, cx)); let (fold_snapshot, fold_edits) = fold_map.read( buffer.read(cx).snapshot(cx), @@ -590,15 +617,5 @@ mod tests { suggestion_map.sync(fold_snapshot.clone(), fold_edits); let (inlay_snapshot, _) = inlay_map.sync(suggestion_snapshot.clone(), suggestion_edits); assert_eq!(inlay_snapshot.text(), "XYZabCdefghi"); - - buffer.update(cx, |buffer, cx| buffer.undo(cx)); - let (fold_snapshot, fold_edits) = fold_map.read( - buffer.read(cx).snapshot(cx), - buffer_edits.consume().into_inner(), - ); - let (suggestion_snapshot, suggestion_edits) = - suggestion_map.sync(fold_snapshot.clone(), fold_edits); - let (inlay_snapshot, _) = inlay_map.sync(suggestion_snapshot.clone(), suggestion_edits); - assert_eq!(inlay_snapshot.text(), "XYZabc|123|defghi"); } } diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index b5d963efa4f2bd341947d4d243a30a45d2780c23..ffafef5cb936351e9dfdf0b7d366dee673aca31b 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -2672,6 +2672,8 @@ impl Editor { let buffer_id = excerpt_buffer_snapshot.remote_id(); let should_update_hints = editor .update(&mut cx, |editor, _| { + // TODO kb wrong: need to query hints per buffer, not per excerpt + // need to store the previous state and calculate the diff between them, and calculate anchors here too. editor.inlay_hint_versions.insert( InlayHintLocation { buffer_id, diff --git a/crates/project/src/lsp_command.rs b/crates/project/src/lsp_command.rs index 3089683cd5de5916ca8df688491d23b0459e4c84..85fec37eb882a383d2f9ce8ab53d80e4d390a724 100644 --- a/crates/project/src/lsp_command.rs +++ b/crates/project/src/lsp_command.rs @@ -1917,7 +1917,6 @@ impl LspCommand for InlayHints { .end .and_then(language::proto::deserialize_anchor) .context("invalid end")?; - // TODO kb has it to be multiple versions instead? buffer .update(&mut cx, |buffer, _| { buffer.wait_for_version(deserialize_version(&message.version))