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.rs26
1 files changed, 23 insertions, 3 deletions
diff --git a/crates/syntax/src/algo.rs b/crates/syntax/src/algo.rs
index 2acb215831..a8a8389394 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
@@ -25,7 +25,7 @@ pub fn ancestors_at_offset(
/// imprecise: if the cursor is strictly between two nodes of the desired type,
/// as in
///
-/// ```no_run
+/// ```ignore
/// struct Foo {}|struct Bar;
/// ```
///
@@ -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)
}