feat: Org::node_at_offset api

This commit is contained in:
PoiScript 2024-04-01 11:41:40 +08:00
parent ddb71dc714
commit e82adf92b7
No known key found for this signature in database
GPG key ID: 22C2B1249D99985E

View file

@ -1,5 +1,5 @@
use rowan::ast::AstNode;
use rowan::GreenNode;
use rowan::{GreenNode, TextSize};
use crate::ast::Document;
use crate::config::ParseConfig;
@ -66,4 +66,41 @@ impl Org {
}
find(SyntaxNode::new_root(self.green.clone()))
}
/// Returns node in given offset
///
/// ```rust
/// use orgize::{Org, ast::Headline};
///
/// let org = Org::parse("\n\n* foo\n* bar");
///
/// assert!(org.node_at_offset::<Headline>(0).is_none());
///
/// let hdl = org.node_at_offset::<Headline>(2).unwrap();
/// assert_eq!(hdl.title_raw(), "foo");
///
/// let hdl = org.node_at_offset::<Headline>(9).unwrap();
/// assert_eq!(hdl.title_raw(), "bar");
///
/// assert!(org.node_at_offset::<Headline>(999).is_none());
/// ```
pub fn node_at_offset<N: AstNode<Language = OrgLanguage>>(
&self,
offset: impl Into<TextSize>,
) -> Option<N> {
let offset = offset.into();
fn find<N: AstNode<Language = OrgLanguage>>(
node: SyntaxNode,
offset: TextSize,
) -> Option<N> {
if !node.text_range().contains(offset) {
None
} else if N::can_cast(node.kind()) {
N::cast(node)
} else {
node.children().find_map(|node| find(node, offset))
}
}
find(SyntaxNode::new_root(self.green.clone()), offset)
}
}