Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/syntax/src/algo.rs')
-rw-r--r--crates/syntax/src/algo.rs24
1 files changed, 22 insertions, 2 deletions
diff --git a/crates/syntax/src/algo.rs b/crates/syntax/src/algo.rs
index 2acb215831..3b85b137aa 100644
--- a/crates/syntax/src/algo.rs
+++ b/crates/syntax/src/algo.rs
@@ -3,8 +3,8 @@
use itertools::Itertools;
use crate::{
- AstNode, Direction, NodeOrToken, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, TextRange,
- TextSize,
+ syntax_editor::Element, AstNode, Direction, NodeOrToken, SyntaxElement, SyntaxKind, SyntaxNode,
+ SyntaxToken, TextRange, TextSize,
};
/// Returns ancestors of the node at the offset, sorted by length. This should
@@ -89,6 +89,26 @@ pub fn least_common_ancestor(u: &SyntaxNode, v: &SyntaxNode) -> Option<SyntaxNod
Some(res)
}
+pub fn least_common_ancestor_element(u: impl Element, v: impl Element) -> Option<SyntaxNode> {
+ let u = u.syntax_element();
+ let v = v.syntax_element();
+ if u == v {
+ return match u {
+ NodeOrToken::Node(node) => Some(node),
+ NodeOrToken::Token(token) => token.parent(),
+ };
+ }
+
+ let u_depth = u.ancestors().count();
+ let v_depth = v.ancestors().count();
+ let keep = u_depth.min(v_depth);
+
+ let u_candidates = u.ancestors().skip(u_depth - keep);
+ let v_candidates = v.ancestors().skip(v_depth - keep);
+ let (res, _) = u_candidates.zip(v_candidates).find(|(x, y)| x == y)?;
+ Some(res)
+}
+
pub fn neighbor<T: AstNode>(me: &T, direction: Direction) -> Option<T> {
me.syntax().siblings(direction).skip(1).find_map(T::cast)
}