mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-14 14:13:58 +00:00
handle replace_with_many and replace_all
This commit is contained in:
parent
41dbaa415a
commit
d929121f7b
2 changed files with 97 additions and 16 deletions
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
num::NonZeroU32,
|
num::NonZeroU32,
|
||||||
|
ops::RangeInclusive,
|
||||||
sync::atomic::{AtomicU32, Ordering},
|
sync::atomic::{AtomicU32, Ordering},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -76,6 +77,26 @@ impl SyntaxEditor {
|
||||||
self.changes.push(Change::Replace(old.syntax_element(), Some(new.syntax_element())));
|
self.changes.push(Change::Replace(old.syntax_element(), Some(new.syntax_element())));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn replace_with_many(&mut self, old: impl Element, new: Vec<SyntaxElement>) {
|
||||||
|
let old = old.syntax_element();
|
||||||
|
debug_assert!(is_ancestor_or_self_of_element(&old, &self.root));
|
||||||
|
debug_assert!(
|
||||||
|
!(matches!(&old, SyntaxElement::Node(node) if node == &self.root) && new.len() > 1),
|
||||||
|
"cannot replace root node with many elements"
|
||||||
|
);
|
||||||
|
self.changes.push(Change::ReplaceWithMany(old.syntax_element(), new));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn replace_all(&mut self, range: RangeInclusive<SyntaxElement>, new: Vec<SyntaxElement>) {
|
||||||
|
if range.start() == range.end() {
|
||||||
|
self.replace_with_many(range.start(), new);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
debug_assert!(is_ancestor_or_self_of_element(range.start(), &self.root));
|
||||||
|
self.changes.push(Change::ReplaceAll(range, new))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn finish(self) -> SyntaxEdit {
|
pub fn finish(self) -> SyntaxEdit {
|
||||||
edit_algo::apply_edits(self)
|
edit_algo::apply_edits(self)
|
||||||
}
|
}
|
||||||
|
@ -186,10 +207,17 @@ impl Position {
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum Change {
|
enum Change {
|
||||||
|
/// Inserts a single element at the specified position.
|
||||||
Insert(Position, SyntaxElement),
|
Insert(Position, SyntaxElement),
|
||||||
|
/// Inserts many elements in-order at the specified position.
|
||||||
InsertAll(Position, Vec<SyntaxElement>),
|
InsertAll(Position, Vec<SyntaxElement>),
|
||||||
/// Represents both a replace single element and a delete element operation.
|
/// Represents both a replace single element and a delete element operation.
|
||||||
Replace(SyntaxElement, Option<SyntaxElement>),
|
Replace(SyntaxElement, Option<SyntaxElement>),
|
||||||
|
/// Replaces a single element with many elements.
|
||||||
|
ReplaceWithMany(SyntaxElement, Vec<SyntaxElement>),
|
||||||
|
/// Replaces a range of elements with another list of elements.
|
||||||
|
/// Range will always have start != end.
|
||||||
|
ReplaceAll(RangeInclusive<SyntaxElement>, Vec<SyntaxElement>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Change {
|
impl Change {
|
||||||
|
@ -202,24 +230,29 @@ impl Change {
|
||||||
),
|
),
|
||||||
PositionRepr::After(child) => TextRange::at(child.text_range().end(), 0.into()),
|
PositionRepr::After(child) => TextRange::at(child.text_range().end(), 0.into()),
|
||||||
},
|
},
|
||||||
Change::Replace(target, _) => target.text_range(),
|
Change::Replace(target, _) | Change::ReplaceWithMany(target, _) => target.text_range(),
|
||||||
|
Change::ReplaceAll(range, _) => {
|
||||||
|
range.start().text_range().cover(range.end().text_range())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn target_parent(&self) -> SyntaxNode {
|
fn target_parent(&self) -> SyntaxNode {
|
||||||
match self {
|
match self {
|
||||||
Change::Insert(target, _) | Change::InsertAll(target, _) => target.parent(),
|
Change::Insert(target, _) | Change::InsertAll(target, _) => target.parent(),
|
||||||
Change::Replace(SyntaxElement::Node(target), _) => {
|
Change::Replace(target, _) | Change::ReplaceWithMany(target, _) => match target {
|
||||||
target.parent().unwrap_or_else(|| target.clone())
|
SyntaxElement::Node(target) => target.parent().unwrap_or_else(|| target.clone()),
|
||||||
}
|
SyntaxElement::Token(target) => target.parent().unwrap(),
|
||||||
Change::Replace(SyntaxElement::Token(target), _) => target.parent().unwrap(),
|
},
|
||||||
|
Change::ReplaceAll(target, _) => target.start().parent().unwrap(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change_kind(&self) -> ChangeKind {
|
fn change_kind(&self) -> ChangeKind {
|
||||||
match self {
|
match self {
|
||||||
Change::Insert(_, _) | Change::InsertAll(_, _) => ChangeKind::Insert,
|
Change::Insert(_, _) | Change::InsertAll(_, _) => ChangeKind::Insert,
|
||||||
Change::Replace(_, _) => ChangeKind::Replace,
|
Change::Replace(_, _) | Change::ReplaceWithMany(_, _) => ChangeKind::Replace,
|
||||||
|
Change::ReplaceAll(_, _) => ChangeKind::ReplaceRange,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -227,7 +260,7 @@ impl Change {
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
enum ChangeKind {
|
enum ChangeKind {
|
||||||
Insert,
|
Insert,
|
||||||
// TODO: deal with replace spans
|
ReplaceRange,
|
||||||
Replace,
|
Replace,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -61,7 +61,13 @@ pub(super) fn apply_edits(editor: SyntaxEditor) -> SyntaxEdit {
|
||||||
.zip(changes.iter().skip(1))
|
.zip(changes.iter().skip(1))
|
||||||
.filter(|(l, r)| {
|
.filter(|(l, r)| {
|
||||||
// We only care about checking for disjoint replace ranges
|
// We only care about checking for disjoint replace ranges
|
||||||
l.change_kind() == ChangeKind::Replace && r.change_kind() == ChangeKind::Replace
|
matches!(
|
||||||
|
(l.change_kind(), r.change_kind()),
|
||||||
|
(
|
||||||
|
ChangeKind::Replace | ChangeKind::ReplaceRange,
|
||||||
|
ChangeKind::Replace | ChangeKind::ReplaceRange
|
||||||
|
)
|
||||||
|
)
|
||||||
})
|
})
|
||||||
.all(|(l, r)| {
|
.all(|(l, r)| {
|
||||||
get_node_depth(l.target_parent()) != get_node_depth(r.target_parent())
|
get_node_depth(l.target_parent()) != get_node_depth(r.target_parent())
|
||||||
|
@ -97,6 +103,7 @@ pub(super) fn apply_edits(editor: SyntaxEditor) -> SyntaxEdit {
|
||||||
// Pop off any ancestors that aren't applicable
|
// Pop off any ancestors that aren't applicable
|
||||||
changed_ancestors.drain((index + 1)..);
|
changed_ancestors.drain((index + 1)..);
|
||||||
|
|
||||||
|
// FIXME: Resolve changes that depend on a range of elements
|
||||||
let ancestor = &changed_ancestors[index];
|
let ancestor = &changed_ancestors[index];
|
||||||
|
|
||||||
dependent_changes.push(DependentChange {
|
dependent_changes.push(DependentChange {
|
||||||
|
@ -115,9 +122,12 @@ pub(super) fn apply_edits(editor: SyntaxEditor) -> SyntaxEdit {
|
||||||
// Add to changed ancestors, if applicable
|
// Add to changed ancestors, if applicable
|
||||||
match change {
|
match change {
|
||||||
Change::Insert(_, _) | Change::InsertAll(_, _) => {}
|
Change::Insert(_, _) | Change::InsertAll(_, _) => {}
|
||||||
Change::Replace(target, _) => {
|
Change::Replace(target, _) | Change::ReplaceWithMany(target, _) => {
|
||||||
changed_ancestors.push_back(ChangedAncestor::single(target, change_index))
|
changed_ancestors.push_back(ChangedAncestor::single(target, change_index))
|
||||||
}
|
}
|
||||||
|
Change::ReplaceAll(range, _) => {
|
||||||
|
changed_ancestors.push_back(ChangedAncestor::multiple(range, change_index))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,9 +147,15 @@ pub(super) fn apply_edits(editor: SyntaxEditor) -> SyntaxEdit {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Change::Replace(target, _) => {
|
Change::Replace(target, _) | Change::ReplaceWithMany(target, _) => {
|
||||||
*target = tree_mutator.make_element_mut(target);
|
*target = tree_mutator.make_element_mut(target);
|
||||||
}
|
}
|
||||||
|
Change::ReplaceAll(range, _) => {
|
||||||
|
let start = tree_mutator.make_element_mut(range.start());
|
||||||
|
let end = tree_mutator.make_element_mut(range.end());
|
||||||
|
|
||||||
|
*range = start..=end;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect changed elements
|
// Collect changed elements
|
||||||
|
@ -148,6 +164,10 @@ pub(super) fn apply_edits(editor: SyntaxEditor) -> SyntaxEdit {
|
||||||
Change::InsertAll(_, elements) => changed_elements.extend(elements.iter().cloned()),
|
Change::InsertAll(_, elements) => changed_elements.extend(elements.iter().cloned()),
|
||||||
Change::Replace(_, Some(element)) => changed_elements.push(element.clone()),
|
Change::Replace(_, Some(element)) => changed_elements.push(element.clone()),
|
||||||
Change::Replace(_, None) => {}
|
Change::Replace(_, None) => {}
|
||||||
|
Change::ReplaceWithMany(_, elements) => {
|
||||||
|
changed_elements.extend(elements.iter().cloned())
|
||||||
|
}
|
||||||
|
Change::ReplaceAll(_, elements) => changed_elements.extend(elements.iter().cloned()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,6 +180,9 @@ pub(super) fn apply_edits(editor: SyntaxEditor) -> SyntaxEdit {
|
||||||
}
|
}
|
||||||
// Silently drop outdated change
|
// Silently drop outdated change
|
||||||
Change::Replace(_, None) => continue,
|
Change::Replace(_, None) => continue,
|
||||||
|
Change::ReplaceAll(_, _) | Change::ReplaceWithMany(_, _) => {
|
||||||
|
unimplemented!("cannot resolve changes that depend on replacing many elements")
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let upmap_target_node = |target: &SyntaxNode| {
|
let upmap_target_node = |target: &SyntaxNode| {
|
||||||
|
@ -185,9 +208,12 @@ pub(super) fn apply_edits(editor: SyntaxEditor) -> SyntaxEdit {
|
||||||
*child = upmap_target(child);
|
*child = upmap_target(child);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Change::Replace(target, _) => {
|
Change::Replace(target, _) | Change::ReplaceWithMany(target, _) => {
|
||||||
*target = upmap_target(&target);
|
*target = upmap_target(&target);
|
||||||
}
|
}
|
||||||
|
Change::ReplaceAll(range, _) => {
|
||||||
|
*range = upmap_target(range.start())..=upmap_target(range.end());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -214,6 +240,16 @@ pub(super) fn apply_edits(editor: SyntaxEditor) -> SyntaxEdit {
|
||||||
let parent = target.parent().unwrap();
|
let parent = target.parent().unwrap();
|
||||||
parent.splice_children(target.index()..target.index() + 1, vec![new_target]);
|
parent.splice_children(target.index()..target.index() + 1, vec![new_target]);
|
||||||
}
|
}
|
||||||
|
Change::ReplaceWithMany(target, elements) => {
|
||||||
|
let parent = target.parent().unwrap();
|
||||||
|
parent.splice_children(target.index()..target.index() + 1, elements);
|
||||||
|
}
|
||||||
|
Change::ReplaceAll(range, elements) => {
|
||||||
|
let start = range.start().index();
|
||||||
|
let end = range.end().index();
|
||||||
|
let parent = range.start().parent().unwrap();
|
||||||
|
parent.splice_children(start..end + 1, elements);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -252,7 +288,7 @@ struct ChangedAncestor {
|
||||||
|
|
||||||
enum ChangedAncestorKind {
|
enum ChangedAncestorKind {
|
||||||
Single { node: SyntaxNode },
|
Single { node: SyntaxNode },
|
||||||
Range { changed_nodes: RangeInclusive<SyntaxNode>, in_parent: SyntaxNode },
|
Range { _changed_elements: RangeInclusive<SyntaxElement>, in_parent: SyntaxNode },
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ChangedAncestor {
|
impl ChangedAncestor {
|
||||||
|
@ -267,13 +303,25 @@ impl ChangedAncestor {
|
||||||
Self { kind, change_index }
|
Self { kind, change_index }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn multiple(range: &RangeInclusive<SyntaxElement>, change_index: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
kind: ChangedAncestorKind::Range {
|
||||||
|
_changed_elements: range.clone(),
|
||||||
|
in_parent: range.start().parent().unwrap(),
|
||||||
|
},
|
||||||
|
change_index,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn affected_range(&self) -> TextRange {
|
fn affected_range(&self) -> TextRange {
|
||||||
match &self.kind {
|
match &self.kind {
|
||||||
ChangedAncestorKind::Single { node } => node.text_range(),
|
ChangedAncestorKind::Single { node } => node.text_range(),
|
||||||
ChangedAncestorKind::Range { changed_nodes, in_parent: _ } => TextRange::new(
|
ChangedAncestorKind::Range { _changed_elements: changed_nodes, in_parent: _ } => {
|
||||||
changed_nodes.start().text_range().start(),
|
TextRange::new(
|
||||||
changed_nodes.end().text_range().end(),
|
changed_nodes.start().text_range().start(),
|
||||||
),
|
changed_nodes.end().text_range().end(),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue