diff options
| -rw-r--r-- | src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edit_algo.rs | 23 |
1 files changed, 19 insertions, 4 deletions
diff --git a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edit_algo.rs b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edit_algo.rs index 4d6cb01c01c..2adc1f67d14 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edit_algo.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edit_algo.rs @@ -1,4 +1,4 @@ -use std::{collections::VecDeque, ops::RangeInclusive}; +use std::{cmp::Ordering, collections::VecDeque, ops::RangeInclusive}; use rowan::TextRange; use rustc_hash::FxHashMap; @@ -30,7 +30,12 @@ pub(super) fn apply_edits(editor: SyntaxEditor) -> SyntaxEdit { let SyntaxEditor { root, mut changes, mappings, annotations } = editor; - // Sort changes by range then change kind, so that we can: + let mut node_depths = FxHashMap::<SyntaxNode, usize>::default(); + let mut get_node_depth = |node: SyntaxNode| { + *node_depths.entry(node).or_insert_with_key(|node| node.ancestors().count()) + }; + + // Sort changes by range, then depth, then change kind, so that we can: // - ensure that parent edits are ordered before child edits // - ensure that inserts will be guaranteed to be inserted at the right range // - easily check for disjoint replace ranges @@ -38,6 +43,16 @@ pub(super) fn apply_edits(editor: SyntaxEditor) -> SyntaxEdit { a.target_range() .start() .cmp(&b.target_range().start()) + .then_with(|| { + let a_target = a.target_parent(); + let b_target = b.target_parent(); + + if a_target == b_target { + return Ordering::Equal; + } + + get_node_depth(a_target).cmp(&get_node_depth(b_target)) + }) .then(a.change_kind().cmp(&b.change_kind())) }); @@ -49,8 +64,8 @@ pub(super) fn apply_edits(editor: SyntaxEditor) -> SyntaxEdit { l.change_kind() == ChangeKind::Replace && r.change_kind() == ChangeKind::Replace }) .all(|(l, r)| { - (l.target_parent() != r.target_parent() - || l.target_range().intersect(r.target_range()).is_none()) + get_node_depth(l.target_parent()) != get_node_depth(r.target_parent()) + || l.target_range().intersect(r.target_range()).is_none() }); if stdx::never!( |
