feat: simplify public api

This commit is contained in:
PoiScript 2023-11-17 13:34:06 +08:00
parent 394c013fd2
commit e924359df6
No known key found for this signature in database
GPG key ID: 22C2B1249D99985E
10 changed files with 586 additions and 356 deletions

View file

@ -27,8 +27,7 @@ impl Traverser for MyHtmlHandler {
fn headline_title(&mut self, event: WalkEvent<&HeadlineTitle>, _ctx: &mut TraversalContext) {
match event {
WalkEvent::Enter(title) => {
let level = title.headline().and_then(|h| h.level()).unwrap_or(1);
let level = min(level, 6);
let level = title.headline().map(|h| min(h.level(), 6)).unwrap_or(1);
let raw = title.syntax().to_string();
self.0.push_str(format!(
"<h{level}><a id=\"{0}\" href=\"#{0}\">",
@ -36,8 +35,7 @@ impl Traverser for MyHtmlHandler {
));
}
WalkEvent::Leave(title) => {
let level = title.headline().and_then(|h| h.level()).unwrap_or(1);
let level = min(level, 6);
let level = title.headline().map(|h| min(h.level(), 6)).unwrap_or(1);
self.0.push_str(format!("</a></h{level}>"));
}
}

View file

@ -27,43 +27,17 @@ const nodes = [
first_child: [
["title", "HeadlineTitle"],
["section", "Section"],
["tags", "HeadlineTags"],
["planning", "Planning"],
["priority", "HeadlinePriority"],
],
children: [["headlines", "Headline"]],
token: [
["stars", "HEADLINE_STARS"],
["keyword", "HEADLINE_KEYWORD"],
],
token: [["keyword", "HEADLINE_KEYWORD"]],
post_blank: true,
},
{
struct: "HeadlineStars",
kind: ["HEADLINE_STARS"],
parent: [["headline", "Headline"]],
},
{
struct: "HeadlineTitle",
kind: ["HEADLINE_TITLE"],
parent: [["headline", "Headline"]],
},
{
struct: "HeadlineKeyword",
kind: ["HEADLINE_KEYWORD"],
parent: [["headline", "Headline"]],
},
{
struct: "HeadlinePriority",
kind: ["HEADLINE_PRIORITY"],
parent: [["headline", "Headline"]],
token: [["text", "TEXT"]],
},
{
struct: "HeadlineTags",
kind: ["HEADLINE_TAGS"],
parent: [["headline", "Headline"]],
},
{
struct: "PropertyDrawer",
kind: ["PROPERTY_DRAWER"],
@ -76,23 +50,6 @@ const nodes = [
{
struct: "Planning",
kind: ["PLANNING"],
last_child: [
["deadline", "PlanningDeadline"],
["scheduled", "PlanningScheduled"],
["closed", "PlanningClosed"],
],
},
{
struct: "PlanningDeadline",
kind: ["PLANNING_DEADLINE"],
},
{
struct: "PlanningScheduled",
kind: ["PLANNING_SCHEDULED"],
},
{
struct: "PlanningClosed",
kind: ["PLANNING_CLOSED"],
},
{
struct: "OrgTable",
@ -118,26 +75,6 @@ const nodes = [
struct: "ListItem",
kind: ["LIST_ITEM"],
first_child: [["content", "ListItemContent"]],
token: [
["indent", "LIST_ITEM_INDENT"],
["bullet", "LIST_ITEM_BULLET"],
],
},
{
struct: "ListItemIndent",
kind: ["LIST_ITEM_INDENT"],
},
{
struct: "ListItemTag",
kind: ["LIST_ITEM_TAG"],
},
{
struct: "ListItemBullet",
kind: ["LIST_ITEM_BULLET"],
},
{
struct: "ListItemContent",
kind: ["LIST_ITEM_CONTENT"],
},
{
struct: "Drawer",
@ -357,7 +294,14 @@ impl AstNode for ${node.struct} {
}> { Self::can_cast(node.kind()).then(|| ${node.struct} { syntax: node }) }
fn syntax(&self) -> &SyntaxNode { &self.syntax }
}
impl ${node.struct} {\n`;
impl ${node.struct} {
pub fn begin(&self) -> u32 {
self.syntax.text_range().start().into()
}
pub fn end(&self) -> u32 {
self.syntax.text_range().end().into()
}
`;
for (const [method, kind] of node.token || []) {
content += ` pub fn ${method}(&self) -> Option<SyntaxToken> { support::token(&self.syntax, ${kind}) }\n`;
}

View file

@ -32,6 +32,12 @@ impl AstNode for Document {
}
}
impl Document {
pub fn begin(&self) -> u32 {
self.syntax.text_range().start().into()
}
pub fn end(&self) -> u32 {
self.syntax.text_range().end().into()
}
pub fn section(&self) -> Option<Section> {
support::child(&self.syntax)
}
@ -66,6 +72,12 @@ impl AstNode for Section {
}
}
impl Section {
pub fn begin(&self) -> u32 {
self.syntax.text_range().start().into()
}
pub fn end(&self) -> u32 {
self.syntax.text_range().end().into()
}
pub fn post_blank(&self) -> usize {
super::blank_lines(&self.syntax)
}
@ -88,6 +100,12 @@ impl AstNode for Paragraph {
}
}
impl Paragraph {
pub fn begin(&self) -> u32 {
self.syntax.text_range().start().into()
}
pub fn end(&self) -> u32 {
self.syntax.text_range().end().into()
}
pub fn post_blank(&self) -> usize {
super::blank_lines(&self.syntax)
}
@ -130,8 +148,11 @@ impl AstNode for Headline {
}
}
impl Headline {
pub fn stars(&self) -> Option<SyntaxToken> {
support::token(&self.syntax, HEADLINE_STARS)
pub fn begin(&self) -> u32 {
self.syntax.text_range().start().into()
}
pub fn end(&self) -> u32 {
self.syntax.text_range().end().into()
}
pub fn keyword(&self) -> Option<SyntaxToken> {
support::token(&self.syntax, HEADLINE_KEYWORD)
@ -142,15 +163,9 @@ impl Headline {
pub fn section(&self) -> Option<Section> {
support::child(&self.syntax)
}
pub fn tags(&self) -> Option<HeadlineTags> {
support::child(&self.syntax)
}
pub fn planning(&self) -> Option<Planning> {
support::child(&self.syntax)
}
pub fn priority(&self) -> Option<HeadlinePriority> {
support::child(&self.syntax)
}
pub fn headlines(&self) -> AstChildren<Headline> {
support::children(&self.syntax)
}
@ -159,28 +174,6 @@ impl Headline {
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct HeadlineStars {
pub(crate) syntax: SyntaxNode,
}
impl AstNode for HeadlineStars {
type Language = OrgLanguage;
fn can_cast(kind: SyntaxKind) -> bool {
kind == HEADLINE_STARS
}
fn cast(node: SyntaxNode) -> Option<HeadlineStars> {
Self::can_cast(node.kind()).then(|| HeadlineStars { syntax: node })
}
fn syntax(&self) -> &SyntaxNode {
&self.syntax
}
}
impl HeadlineStars {
pub fn headline(&self) -> Option<Headline> {
self.syntax.parent().and_then(Headline::cast)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct HeadlineTitle {
pub(crate) syntax: SyntaxNode,
@ -198,75 +191,12 @@ impl AstNode for HeadlineTitle {
}
}
impl HeadlineTitle {
pub fn headline(&self) -> Option<Headline> {
self.syntax.parent().and_then(Headline::cast)
pub fn begin(&self) -> u32 {
self.syntax.text_range().start().into()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct HeadlineKeyword {
pub(crate) syntax: SyntaxNode,
}
impl AstNode for HeadlineKeyword {
type Language = OrgLanguage;
fn can_cast(kind: SyntaxKind) -> bool {
kind == HEADLINE_KEYWORD
pub fn end(&self) -> u32 {
self.syntax.text_range().end().into()
}
fn cast(node: SyntaxNode) -> Option<HeadlineKeyword> {
Self::can_cast(node.kind()).then(|| HeadlineKeyword { syntax: node })
}
fn syntax(&self) -> &SyntaxNode {
&self.syntax
}
}
impl HeadlineKeyword {
pub fn headline(&self) -> Option<Headline> {
self.syntax.parent().and_then(Headline::cast)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct HeadlinePriority {
pub(crate) syntax: SyntaxNode,
}
impl AstNode for HeadlinePriority {
type Language = OrgLanguage;
fn can_cast(kind: SyntaxKind) -> bool {
kind == HEADLINE_PRIORITY
}
fn cast(node: SyntaxNode) -> Option<HeadlinePriority> {
Self::can_cast(node.kind()).then(|| HeadlinePriority { syntax: node })
}
fn syntax(&self) -> &SyntaxNode {
&self.syntax
}
}
impl HeadlinePriority {
pub fn text(&self) -> Option<SyntaxToken> {
support::token(&self.syntax, TEXT)
}
pub fn headline(&self) -> Option<Headline> {
self.syntax.parent().and_then(Headline::cast)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct HeadlineTags {
pub(crate) syntax: SyntaxNode,
}
impl AstNode for HeadlineTags {
type Language = OrgLanguage;
fn can_cast(kind: SyntaxKind) -> bool {
kind == HEADLINE_TAGS
}
fn cast(node: SyntaxNode) -> Option<HeadlineTags> {
Self::can_cast(node.kind()).then(|| HeadlineTags { syntax: node })
}
fn syntax(&self) -> &SyntaxNode {
&self.syntax
}
}
impl HeadlineTags {
pub fn headline(&self) -> Option<Headline> {
self.syntax.parent().and_then(Headline::cast)
}
@ -289,6 +219,12 @@ impl AstNode for PropertyDrawer {
}
}
impl PropertyDrawer {
pub fn begin(&self) -> u32 {
self.syntax.text_range().start().into()
}
pub fn end(&self) -> u32 {
self.syntax.text_range().end().into()
}
pub fn node_properties(&self) -> AstChildren<NodeProperty> {
support::children(&self.syntax)
}
@ -310,7 +246,14 @@ impl AstNode for NodeProperty {
&self.syntax
}
}
impl NodeProperty {}
impl NodeProperty {
pub fn begin(&self) -> u32 {
self.syntax.text_range().start().into()
}
pub fn end(&self) -> u32 {
self.syntax.text_range().end().into()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Planning {
@ -329,71 +272,14 @@ impl AstNode for Planning {
}
}
impl Planning {
pub fn deadline(&self) -> Option<PlanningDeadline> {
super::last_child(&self.syntax)
pub fn begin(&self) -> u32 {
self.syntax.text_range().start().into()
}
pub fn scheduled(&self) -> Option<PlanningScheduled> {
super::last_child(&self.syntax)
}
pub fn closed(&self) -> Option<PlanningClosed> {
super::last_child(&self.syntax)
pub fn end(&self) -> u32 {
self.syntax.text_range().end().into()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct PlanningDeadline {
pub(crate) syntax: SyntaxNode,
}
impl AstNode for PlanningDeadline {
type Language = OrgLanguage;
fn can_cast(kind: SyntaxKind) -> bool {
kind == PLANNING_DEADLINE
}
fn cast(node: SyntaxNode) -> Option<PlanningDeadline> {
Self::can_cast(node.kind()).then(|| PlanningDeadline { syntax: node })
}
fn syntax(&self) -> &SyntaxNode {
&self.syntax
}
}
impl PlanningDeadline {}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct PlanningScheduled {
pub(crate) syntax: SyntaxNode,
}
impl AstNode for PlanningScheduled {
type Language = OrgLanguage;
fn can_cast(kind: SyntaxKind) -> bool {
kind == PLANNING_SCHEDULED
}
fn cast(node: SyntaxNode) -> Option<PlanningScheduled> {
Self::can_cast(node.kind()).then(|| PlanningScheduled { syntax: node })
}
fn syntax(&self) -> &SyntaxNode {
&self.syntax
}
}
impl PlanningScheduled {}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct PlanningClosed {
pub(crate) syntax: SyntaxNode,
}
impl AstNode for PlanningClosed {
type Language = OrgLanguage;
fn can_cast(kind: SyntaxKind) -> bool {
kind == PLANNING_CLOSED
}
fn cast(node: SyntaxNode) -> Option<PlanningClosed> {
Self::can_cast(node.kind()).then(|| PlanningClosed { syntax: node })
}
fn syntax(&self) -> &SyntaxNode {
&self.syntax
}
}
impl PlanningClosed {}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct OrgTable {
pub(crate) syntax: SyntaxNode,
@ -411,6 +297,12 @@ impl AstNode for OrgTable {
}
}
impl OrgTable {
pub fn begin(&self) -> u32 {
self.syntax.text_range().start().into()
}
pub fn end(&self) -> u32 {
self.syntax.text_range().end().into()
}
pub fn post_blank(&self) -> usize {
super::blank_lines(&self.syntax)
}
@ -452,7 +344,14 @@ impl AstNode for OrgTableRow {
&self.syntax
}
}
impl OrgTableRow {}
impl OrgTableRow {
pub fn begin(&self) -> u32 {
self.syntax.text_range().start().into()
}
pub fn end(&self) -> u32 {
self.syntax.text_range().end().into()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct OrgTableCell {
@ -470,7 +369,14 @@ impl AstNode for OrgTableCell {
&self.syntax
}
}
impl OrgTableCell {}
impl OrgTableCell {
pub fn begin(&self) -> u32 {
self.syntax.text_range().start().into()
}
pub fn end(&self) -> u32 {
self.syntax.text_range().end().into()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct List {
@ -489,6 +395,12 @@ impl AstNode for List {
}
}
impl List {
pub fn begin(&self) -> u32 {
self.syntax.text_range().start().into()
}
pub fn end(&self) -> u32 {
self.syntax.text_range().end().into()
}
pub fn items(&self) -> AstChildren<ListItem> {
support::children(&self.syntax)
}
@ -531,6 +443,12 @@ impl AstNode for ListItem {
}
}
impl ListItem {
pub fn begin(&self) -> u32 {
self.syntax.text_range().start().into()
}
pub fn end(&self) -> u32 {
self.syntax.text_range().end().into()
}
pub fn indent(&self) -> Option<SyntaxToken> {
support::token(&self.syntax, LIST_ITEM_INDENT)
}
@ -558,7 +476,14 @@ impl AstNode for ListItemIndent {
&self.syntax
}
}
impl ListItemIndent {}
impl ListItemIndent {
pub fn begin(&self) -> u32 {
self.syntax.text_range().start().into()
}
pub fn end(&self) -> u32 {
self.syntax.text_range().end().into()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ListItemTag {
@ -576,7 +501,14 @@ impl AstNode for ListItemTag {
&self.syntax
}
}
impl ListItemTag {}
impl ListItemTag {
pub fn begin(&self) -> u32 {
self.syntax.text_range().start().into()
}
pub fn end(&self) -> u32 {
self.syntax.text_range().end().into()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ListItemBullet {
@ -594,7 +526,14 @@ impl AstNode for ListItemBullet {
&self.syntax
}
}
impl ListItemBullet {}
impl ListItemBullet {
pub fn begin(&self) -> u32 {
self.syntax.text_range().start().into()
}
pub fn end(&self) -> u32 {
self.syntax.text_range().end().into()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ListItemContent {
@ -612,7 +551,14 @@ impl AstNode for ListItemContent {
&self.syntax
}
}
impl ListItemContent {}
impl ListItemContent {
pub fn begin(&self) -> u32 {
self.syntax.text_range().start().into()
}
pub fn end(&self) -> u32 {
self.syntax.text_range().end().into()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Drawer {
@ -630,7 +576,14 @@ impl AstNode for Drawer {
&self.syntax
}
}
impl Drawer {}
impl Drawer {
pub fn begin(&self) -> u32 {
self.syntax.text_range().start().into()
}
pub fn end(&self) -> u32 {
self.syntax.text_range().end().into()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct DynBlock {
@ -649,6 +602,12 @@ impl AstNode for DynBlock {
}
}
impl DynBlock {
pub fn begin(&self) -> u32 {
self.syntax.text_range().start().into()
}
pub fn end(&self) -> u32 {
self.syntax.text_range().end().into()
}
pub fn caption(&self) -> Option<AffiliatedKeyword> {
affiliated_keyword(&self.syntax, |k| k == "CAPTION")
}
@ -687,7 +646,14 @@ impl AstNode for Keyword {
&self.syntax
}
}
impl Keyword {}
impl Keyword {
pub fn begin(&self) -> u32 {
self.syntax.text_range().start().into()
}
pub fn end(&self) -> u32 {
self.syntax.text_range().end().into()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct BabelCall {
@ -705,7 +671,14 @@ impl AstNode for BabelCall {
&self.syntax
}
}
impl BabelCall {}
impl BabelCall {
pub fn begin(&self) -> u32 {
self.syntax.text_range().start().into()
}
pub fn end(&self) -> u32 {
self.syntax.text_range().end().into()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct AffiliatedKeyword {
@ -723,7 +696,14 @@ impl AstNode for AffiliatedKeyword {
&self.syntax
}
}
impl AffiliatedKeyword {}
impl AffiliatedKeyword {
pub fn begin(&self) -> u32 {
self.syntax.text_range().start().into()
}
pub fn end(&self) -> u32 {
self.syntax.text_range().end().into()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct TableEl {
@ -742,6 +722,12 @@ impl AstNode for TableEl {
}
}
impl TableEl {
pub fn begin(&self) -> u32 {
self.syntax.text_range().start().into()
}
pub fn end(&self) -> u32 {
self.syntax.text_range().end().into()
}
pub fn post_blank(&self) -> usize {
super::blank_lines(&self.syntax)
}
@ -764,6 +750,12 @@ impl AstNode for Clock {
}
}
impl Clock {
pub fn begin(&self) -> u32 {
self.syntax.text_range().start().into()
}
pub fn end(&self) -> u32 {
self.syntax.text_range().end().into()
}
pub fn post_blank(&self) -> usize {
super::blank_lines(&self.syntax)
}
@ -786,6 +778,12 @@ impl AstNode for FnDef {
}
}
impl FnDef {
pub fn begin(&self) -> u32 {
self.syntax.text_range().start().into()
}
pub fn end(&self) -> u32 {
self.syntax.text_range().end().into()
}
pub fn post_blank(&self) -> usize {
super::blank_lines(&self.syntax)
}
@ -828,6 +826,12 @@ impl AstNode for Comment {
}
}
impl Comment {
pub fn begin(&self) -> u32 {
self.syntax.text_range().start().into()
}
pub fn end(&self) -> u32 {
self.syntax.text_range().end().into()
}
pub fn text(&self) -> Option<SyntaxToken> {
support::token(&self.syntax, TEXT)
}
@ -873,6 +877,12 @@ impl AstNode for Rule {
}
}
impl Rule {
pub fn begin(&self) -> u32 {
self.syntax.text_range().start().into()
}
pub fn end(&self) -> u32 {
self.syntax.text_range().end().into()
}
pub fn post_blank(&self) -> usize {
super::blank_lines(&self.syntax)
}
@ -895,6 +905,12 @@ impl AstNode for FixedWidth {
}
}
impl FixedWidth {
pub fn begin(&self) -> u32 {
self.syntax.text_range().start().into()
}
pub fn end(&self) -> u32 {
self.syntax.text_range().end().into()
}
pub fn text(&self) -> Option<SyntaxToken> {
support::token(&self.syntax, TEXT)
}
@ -940,6 +956,12 @@ impl AstNode for SpecialBlock {
}
}
impl SpecialBlock {
pub fn begin(&self) -> u32 {
self.syntax.text_range().start().into()
}
pub fn end(&self) -> u32 {
self.syntax.text_range().end().into()
}
pub fn caption(&self) -> Option<AffiliatedKeyword> {
affiliated_keyword(&self.syntax, |k| k == "CAPTION")
}
@ -979,6 +1001,12 @@ impl AstNode for QuoteBlock {
}
}
impl QuoteBlock {
pub fn begin(&self) -> u32 {
self.syntax.text_range().start().into()
}
pub fn end(&self) -> u32 {
self.syntax.text_range().end().into()
}
pub fn caption(&self) -> Option<AffiliatedKeyword> {
affiliated_keyword(&self.syntax, |k| k == "CAPTION")
}
@ -1018,6 +1046,12 @@ impl AstNode for CenterBlock {
}
}
impl CenterBlock {
pub fn begin(&self) -> u32 {
self.syntax.text_range().start().into()
}
pub fn end(&self) -> u32 {
self.syntax.text_range().end().into()
}
pub fn caption(&self) -> Option<AffiliatedKeyword> {
affiliated_keyword(&self.syntax, |k| k == "CAPTION")
}
@ -1057,6 +1091,12 @@ impl AstNode for VerseBlock {
}
}
impl VerseBlock {
pub fn begin(&self) -> u32 {
self.syntax.text_range().start().into()
}
pub fn end(&self) -> u32 {
self.syntax.text_range().end().into()
}
pub fn caption(&self) -> Option<AffiliatedKeyword> {
affiliated_keyword(&self.syntax, |k| k == "CAPTION")
}
@ -1096,6 +1136,12 @@ impl AstNode for CommentBlock {
}
}
impl CommentBlock {
pub fn begin(&self) -> u32 {
self.syntax.text_range().start().into()
}
pub fn end(&self) -> u32 {
self.syntax.text_range().end().into()
}
pub fn caption(&self) -> Option<AffiliatedKeyword> {
affiliated_keyword(&self.syntax, |k| k == "CAPTION")
}
@ -1135,6 +1181,12 @@ impl AstNode for ExampleBlock {
}
}
impl ExampleBlock {
pub fn begin(&self) -> u32 {
self.syntax.text_range().start().into()
}
pub fn end(&self) -> u32 {
self.syntax.text_range().end().into()
}
pub fn caption(&self) -> Option<AffiliatedKeyword> {
affiliated_keyword(&self.syntax, |k| k == "CAPTION")
}
@ -1174,6 +1226,12 @@ impl AstNode for ExportBlock {
}
}
impl ExportBlock {
pub fn begin(&self) -> u32 {
self.syntax.text_range().start().into()
}
pub fn end(&self) -> u32 {
self.syntax.text_range().end().into()
}
pub fn caption(&self) -> Option<AffiliatedKeyword> {
affiliated_keyword(&self.syntax, |k| k == "CAPTION")
}
@ -1213,6 +1271,12 @@ impl AstNode for SourceBlock {
}
}
impl SourceBlock {
pub fn begin(&self) -> u32 {
self.syntax.text_range().start().into()
}
pub fn end(&self) -> u32 {
self.syntax.text_range().end().into()
}
pub fn caption(&self) -> Option<AffiliatedKeyword> {
affiliated_keyword(&self.syntax, |k| k == "CAPTION")
}
@ -1251,7 +1315,14 @@ impl AstNode for InlineCall {
&self.syntax
}
}
impl InlineCall {}
impl InlineCall {
pub fn begin(&self) -> u32 {
self.syntax.text_range().start().into()
}
pub fn end(&self) -> u32 {
self.syntax.text_range().end().into()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct InlineSrc {
@ -1269,7 +1340,14 @@ impl AstNode for InlineSrc {
&self.syntax
}
}
impl InlineSrc {}
impl InlineSrc {
pub fn begin(&self) -> u32 {
self.syntax.text_range().start().into()
}
pub fn end(&self) -> u32 {
self.syntax.text_range().end().into()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Link {
@ -1288,6 +1366,12 @@ impl AstNode for Link {
}
}
impl Link {
pub fn begin(&self) -> u32 {
self.syntax.text_range().start().into()
}
pub fn end(&self) -> u32 {
self.syntax.text_range().end().into()
}
pub fn path(&self) -> Option<SyntaxToken> {
support::token(&self.syntax, LINK_PATH)
}
@ -1309,7 +1393,14 @@ impl AstNode for Cookie {
&self.syntax
}
}
impl Cookie {}
impl Cookie {
pub fn begin(&self) -> u32 {
self.syntax.text_range().start().into()
}
pub fn end(&self) -> u32 {
self.syntax.text_range().end().into()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct RadioTarget {
@ -1327,7 +1418,14 @@ impl AstNode for RadioTarget {
&self.syntax
}
}
impl RadioTarget {}
impl RadioTarget {
pub fn begin(&self) -> u32 {
self.syntax.text_range().start().into()
}
pub fn end(&self) -> u32 {
self.syntax.text_range().end().into()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct FnRef {
@ -1345,7 +1443,14 @@ impl AstNode for FnRef {
&self.syntax
}
}
impl FnRef {}
impl FnRef {
pub fn begin(&self) -> u32 {
self.syntax.text_range().start().into()
}
pub fn end(&self) -> u32 {
self.syntax.text_range().end().into()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct LatexEnvironment {
@ -1363,7 +1468,14 @@ impl AstNode for LatexEnvironment {
&self.syntax
}
}
impl LatexEnvironment {}
impl LatexEnvironment {
pub fn begin(&self) -> u32 {
self.syntax.text_range().start().into()
}
pub fn end(&self) -> u32 {
self.syntax.text_range().end().into()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Macros {
@ -1381,7 +1493,14 @@ impl AstNode for Macros {
&self.syntax
}
}
impl Macros {}
impl Macros {
pub fn begin(&self) -> u32 {
self.syntax.text_range().start().into()
}
pub fn end(&self) -> u32 {
self.syntax.text_range().end().into()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct MacrosArgument {
@ -1399,7 +1518,14 @@ impl AstNode for MacrosArgument {
&self.syntax
}
}
impl MacrosArgument {}
impl MacrosArgument {
pub fn begin(&self) -> u32 {
self.syntax.text_range().start().into()
}
pub fn end(&self) -> u32 {
self.syntax.text_range().end().into()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Snippet {
@ -1418,6 +1544,12 @@ impl AstNode for Snippet {
}
}
impl Snippet {
pub fn begin(&self) -> u32 {
self.syntax.text_range().start().into()
}
pub fn end(&self) -> u32 {
self.syntax.text_range().end().into()
}
pub fn name(&self) -> Option<SyntaxToken> {
support::token(&self.syntax, TEXT)
}
@ -1439,7 +1571,14 @@ impl AstNode for Target {
&self.syntax
}
}
impl Target {}
impl Target {
pub fn begin(&self) -> u32 {
self.syntax.text_range().start().into()
}
pub fn end(&self) -> u32 {
self.syntax.text_range().end().into()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Bold {
@ -1457,7 +1596,14 @@ impl AstNode for Bold {
&self.syntax
}
}
impl Bold {}
impl Bold {
pub fn begin(&self) -> u32 {
self.syntax.text_range().start().into()
}
pub fn end(&self) -> u32 {
self.syntax.text_range().end().into()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Strike {
@ -1475,7 +1621,14 @@ impl AstNode for Strike {
&self.syntax
}
}
impl Strike {}
impl Strike {
pub fn begin(&self) -> u32 {
self.syntax.text_range().start().into()
}
pub fn end(&self) -> u32 {
self.syntax.text_range().end().into()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Italic {
@ -1493,7 +1646,14 @@ impl AstNode for Italic {
&self.syntax
}
}
impl Italic {}
impl Italic {
pub fn begin(&self) -> u32 {
self.syntax.text_range().start().into()
}
pub fn end(&self) -> u32 {
self.syntax.text_range().end().into()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Underline {
@ -1511,7 +1671,14 @@ impl AstNode for Underline {
&self.syntax
}
}
impl Underline {}
impl Underline {
pub fn begin(&self) -> u32 {
self.syntax.text_range().start().into()
}
pub fn end(&self) -> u32 {
self.syntax.text_range().end().into()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Verbatim {
@ -1529,7 +1696,14 @@ impl AstNode for Verbatim {
&self.syntax
}
}
impl Verbatim {}
impl Verbatim {
pub fn begin(&self) -> u32 {
self.syntax.text_range().start().into()
}
pub fn end(&self) -> u32 {
self.syntax.text_range().end().into()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Code {
@ -1548,6 +1722,12 @@ impl AstNode for Code {
}
}
impl Code {
pub fn begin(&self) -> u32 {
self.syntax.text_range().start().into()
}
pub fn end(&self) -> u32 {
self.syntax.text_range().end().into()
}
pub fn text(&self) -> Option<SyntaxToken> {
support::token(&self.syntax, TEXT)
}
@ -1570,6 +1750,12 @@ impl AstNode for Timestamp {
}
}
impl Timestamp {
pub fn begin(&self) -> u32 {
self.syntax.text_range().start().into()
}
pub fn end(&self) -> u32 {
self.syntax.text_range().end().into()
}
pub fn year_start(&self) -> Option<SyntaxToken> {
support::token(&self.syntax, TIMESTAMP_YEAR)
}

View file

@ -1,8 +1,6 @@
use rowan::ast::support;
use crate::syntax::{SyntaxKind, SyntaxToken};
use crate::syntax::{SyntaxElement, SyntaxKind, SyntaxToken};
use super::{filter_token, Headline, HeadlinePriority, HeadlineTags, Timestamp};
use super::{filter_token, Headline, Timestamp};
impl Headline {
/// Return level of this headline
@ -11,12 +9,19 @@ impl Headline {
/// use orgize::{Org, ast::Headline};
///
/// let hdl = Org::parse("* ").first_node::<Headline>().unwrap();
/// assert_eq!(hdl.level(), Some(1));
/// assert_eq!(hdl.level(), 1);
/// let hdl = Org::parse("****** hello").first_node::<Headline>().unwrap();
/// assert_eq!(hdl.level(), Some(6));
/// assert_eq!(hdl.level(), 6);
/// ```
pub fn level(&self) -> Option<usize> {
self.stars().map(|stars| stars.text().len())
pub fn level(&self) -> usize {
self.syntax
.children_with_tokens()
.find_map(filter_token(SyntaxKind::HEADLINE_STARS))
.map(|stars| stars.text().len())
.unwrap_or_else(|| {
debug_assert!(false, "headline must contains starts token");
0
})
}
/// Return `true` if this headline contains a COMMENT keyword
@ -54,34 +59,67 @@ impl Headline {
/// assert!(!hdl.is_archived());
/// ```
pub fn is_archived(&self) -> bool {
self.tags()
.map(|tags| {
tags.syntax
.children_with_tokens()
.any(|elem| matches!(elem, SyntaxElement::Token(t) if t.text() == "ARCHIVE"))
})
.unwrap_or_default()
self.tags().any(|t| t.text() == "ARCHIVE")
}
/// Returns this headline's closed timestamp, or `None` if not set.
pub fn closed(&self) -> Option<Timestamp> {
self.planning()
.and_then(|planning| planning.closed())
.and_then(|node| support::child::<Timestamp>(&node.syntax))
self.planning().and_then(|planning| planning.closed())
}
/// Returns this headline's scheduled timestamp, or `None` if not set.
pub fn scheduled(&self) -> Option<Timestamp> {
self.planning()
.and_then(|planning| planning.scheduled())
.and_then(|node| support::child::<Timestamp>(&node.syntax))
self.planning().and_then(|planning| planning.scheduled())
}
/// Returns this headline's deadline timestamp, or `None` if not set.
pub fn deadline(&self) -> Option<Timestamp> {
self.planning()
.and_then(|planning| planning.deadline())
.and_then(|node| support::child::<Timestamp>(&node.syntax))
self.planning().and_then(|planning| planning.deadline())
}
/// Returns an iterator of text token in this tags
///
/// ```rust
/// use orgize::{Org, ast::Headline};
///
/// let tags_vec = |input: &str| {
/// let hdl = Org::parse(input).first_node::<Headline>().unwrap();
/// let tags: Vec<_> = hdl.tags().map(|t| t.to_string()).collect();
/// tags
/// };
///
/// assert_eq!(tags_vec("* :tag:"), vec!["tag".to_string()]);
/// assert_eq!(tags_vec("* [#A] :::::a2%:"), vec!["a2%".to_string()]);
/// assert_eq!(tags_vec("* TODO :tag: :a2%:"), vec!["tag".to_string(), "a2%".to_string()]);
/// assert_eq!(tags_vec("* title :tag:a2%:"), vec!["tag".to_string(), "a2%".to_string()]);
/// ```
pub fn tags(&self) -> impl Iterator<Item = SyntaxToken> {
self.syntax
.children()
.find(|n| n.kind() == SyntaxKind::HEADLINE_TAGS)
.into_iter()
.flat_map(|t| t.children_with_tokens())
.filter_map(filter_token(SyntaxKind::TEXT))
}
/// Returns priority text
///
/// ```rust
/// use orgize::{Org, ast::Headline};
///
/// let hdl = Org::parse("* [#A]").first_node::<Headline>().unwrap();
/// assert_eq!(hdl.priority().unwrap().text(), "A");
/// let hdl = Org::parse("* [#破]").first_node::<Headline>().unwrap();
/// assert_eq!(hdl.priority().unwrap().text(), "破");
/// ```
pub fn priority(&self) -> Option<SyntaxToken> {
self.syntax
.children()
.find(|n| n.kind() == SyntaxKind::HEADLINE_PRIORITY)
.and_then(|n| {
n.children_with_tokens()
.find_map(filter_token(SyntaxKind::TEXT))
})
}
}
@ -316,43 +354,3 @@ impl Headline {
// }
// }
// }
impl HeadlineTags {
/// Returns an iterator of text token in this tags
///
/// ```rust
/// use orgize::{Org, ast::HeadlineTags};
///
/// let tags_vec = |input: &str| {
/// let tags = Org::parse(input).first_node::<HeadlineTags>().unwrap();
/// let tags: Vec<_> = tags.iter().map(|t| t.to_string()).collect();
/// tags
/// };
///
/// assert_eq!(tags_vec("* :tag:"), vec!["tag".to_string()]);
/// assert_eq!(tags_vec("* [#A] :::::a2%:"), vec!["a2%".to_string()]);
/// assert_eq!(tags_vec("* TODO :tag: :a2%:"), vec!["tag".to_string(), "a2%".to_string()]);
/// assert_eq!(tags_vec("* title :tag:a2%:"), vec!["tag".to_string(), "a2%".to_string()]);
/// ```
pub fn iter(&self) -> impl Iterator<Item = SyntaxToken> {
self.syntax
.children_with_tokens()
.filter_map(filter_token(SyntaxKind::TEXT))
}
}
impl HeadlinePriority {
/// Returns priority text
///
/// ```rust
/// use orgize::{Org, ast::HeadlinePriority};
///
/// let priority = Org::parse("* [#A]").first_node::<HeadlinePriority>().unwrap();
/// assert_eq!(priority.text_string().unwrap(), "A".to_string());
/// let priority = Org::parse("* [#破]").first_node::<HeadlinePriority>().unwrap();
/// assert_eq!(priority.text_string().unwrap(), "破".to_string());
/// ```
pub fn text_string(&self) -> Option<String> {
self.text().map(|tk| tk.to_string())
}
}

View file

@ -1,7 +1,55 @@
use super::List;
use crate::syntax::SyntaxKind;
use super::{filter_token, List};
use crate::{syntax::SyntaxKind, SyntaxElement, SyntaxToken};
impl List {
pub fn indent(&self) -> usize {
self.syntax
.children_with_tokens()
.find_map(filter_token(SyntaxKind::LIST_ITEM_INDENT))
.map(|t| t.text().len())
.unwrap_or_else(|| {
debug_assert!(false, "list must contains indent token");
0
})
}
pub fn bullet(&self) -> Option<SyntaxToken> {
self.syntax
.children_with_tokens()
.find_map(filter_token(SyntaxKind::LIST_ITEM_BULLET))
}
pub fn checkbox(&self) -> Option<SyntaxToken> {
self.syntax
.children()
.find(|n| n.kind() == SyntaxKind::LIST_ITEM_CHECK_BOX)
.and_then(|n| {
n.children_with_tokens()
.find_map(filter_token(SyntaxKind::TEXT))
})
}
pub fn counter(&self) -> Option<SyntaxToken> {
self.syntax
.children()
.find(|n| n.kind() == SyntaxKind::LIST_ITEM_COUNTER)
.and_then(|n| {
n.children_with_tokens()
.find_map(filter_token(SyntaxKind::TEXT))
})
}
pub fn tag(&self) -> impl Iterator<Item = SyntaxElement> {
self.syntax
.children()
.find(|n| n.kind() == SyntaxKind::LIST_ITEM_TAG)
.into_iter()
.flat_map(|n| {
n.children_with_tokens()
.filter(|n| n.kind() != SyntaxKind::COLON2)
})
}
/// Returns `true` if this list is an ordered link
///
/// ```rust

View file

@ -8,6 +8,7 @@ mod headline;
mod inline_call;
mod link;
mod list;
mod planning;
mod snippet;
mod table;
mod timestamp;

67
src/ast/planning.rs Normal file
View file

@ -0,0 +1,67 @@
use rowan::ast::AstNode;
use super::{Planning, Timestamp};
use crate::syntax::SyntaxKind;
impl Planning {
/// Returns deadline timestamp
///
///
/// ```rust
/// use orgize::{ast::Planning, Org};
///
/// let s = Org::parse("* a\nDEADLINE: <2019-04-08 Mon>")
/// .first_node::<Planning>()
/// .unwrap()
/// .deadline()
/// .unwrap();
/// assert_eq!(s.day_start().unwrap().text(), "08");
/// ```
pub fn deadline(&self) -> Option<Timestamp> {
self.syntax
.children()
.filter(|n| n.kind() == SyntaxKind::PLANNING_DEADLINE)
.last()
.and_then(|n| n.children().find_map(Timestamp::cast))
}
/// Returns scheduled timestamp
///
/// ```rust
/// use orgize::{ast::Planning, Org};
///
/// let s = Org::parse("* a\nSCHEDULED: <2019-04-08 Mon>")
/// .first_node::<Planning>()
/// .unwrap()
/// .scheduled()
/// .unwrap();
/// assert_eq!(s.year_start().unwrap().text(), "2019");
/// ```
pub fn scheduled(&self) -> Option<Timestamp> {
self.syntax
.children()
.filter(|n| n.kind() == SyntaxKind::PLANNING_SCHEDULED)
.last()
.and_then(|n| n.children().find_map(Timestamp::cast))
}
/// Returns closed timestamp
///
/// ```rust
/// use orgize::{ast::Planning, Org};
///
/// let s = Org::parse("* a\nCLOSED: <2019-04-08 Mon>")
/// .first_node::<Planning>()
/// .unwrap()
/// .closed()
/// .unwrap();
/// assert_eq!(s.month_start().unwrap().text(), "04");
/// ```
pub fn closed(&self) -> Option<Timestamp> {
self.syntax
.children()
.filter(|n| n.kind() == SyntaxKind::PLANNING_CLOSED)
.last()
.and_then(|n| n.children().find_map(Timestamp::cast))
}
}

View file

@ -28,14 +28,12 @@
/// fn headline_title(&mut self, event: WalkEvent<&HeadlineTitle>, _ctx: &mut TraversalContext) {
/// match event {
/// WalkEvent::Enter(title) => {
/// let level = title.headline().and_then(|h| h.level()).unwrap_or(1);
/// let level = min(level, 6);
/// let level = title.headline().map(|h| min(h.level(), 6)).unwrap_or(1);
/// let raw = title.syntax().to_string();
/// self.0.push_str(format!("<h{level}><a id=\"{0}\" href=\"#{0}\">", slugify!(&raw)));
/// }
/// WalkEvent::Leave(title) => {
/// let level = title.headline().and_then(|h| h.level()).unwrap_or(1);
/// let level = min(level, 6);
/// let level = title.headline().map(|h| min(h.level(), 6)).unwrap_or(1);
/// self.0.push_str(format!("</a></h{level}>"));
/// }
/// }

View file

@ -1,4 +1,5 @@
use rowan::WalkEvent;
use std::cmp::min;
use std::fmt;
use super::TraversalContext;
@ -188,19 +189,11 @@ impl Traverser for HtmlExport {
fn headline_title(&mut self, event: WalkEvent<&HeadlineTitle>, _ctx: &mut TraversalContext) {
self.output += &match event {
WalkEvent::Enter(title) => {
let level = title
.headline()
.and_then(|hdl| hdl.level())
.map(|lvl| std::cmp::min(lvl, 6))
.unwrap_or(1);
let level = title.headline().map(|h| min(h.level(), 6)).unwrap_or(1);
format!("<h{level}>")
}
WalkEvent::Leave(title) => {
let level = title
.headline()
.and_then(|hdl| hdl.level())
.map(|lvl| std::cmp::min(lvl, 6))
.unwrap_or(1);
let level = title.headline().map(|h| min(h.level(), 6)).unwrap_or(1);
format!("</h{level}>")
}
};

View file

@ -273,8 +273,8 @@ fn parse() {
);
let hdl = to_headline("* TODO foo\nbar\n** baz\n");
assert_eq!(hdl.level(), Some(1));
assert_eq!(hdl.keyword().as_ref().map(|x| x.text()), Some("TODO"));
assert_eq!(hdl.level(), 1);
assert_eq!(hdl.keyword().unwrap().text(), "TODO");
insta::assert_debug_snapshot!(
hdl.syntax,
@r###"
@ -299,11 +299,8 @@ fn parse() {
);
let hdl = to_headline("** [#A] foo\n* baz");
assert_eq!(hdl.level(), Some(2));
assert_eq!(
hdl.priority().unwrap().text_string().unwrap(),
"A".to_string()
);
assert_eq!(hdl.level(), 2);
assert_eq!(hdl.priority().unwrap().text(), "A");
insta::assert_debug_snapshot!(
hdl.syntax,
@r###"
@ -329,41 +326,41 @@ fn issue_15_16() {
let to_headline = to_ast::<Headline>(headline_node);
assert!(to_headline("* a ::").tags().is_none());
assert!(to_headline("* a : :").tags().is_none());
assert!(to_headline("* a :(:").tags().is_none());
assert!(to_headline("* a :a: :").tags().is_none());
assert!(to_headline("* a :a :").tags().is_none());
assert!(to_headline("* a a:").tags().is_none());
assert!(to_headline("* a :a").tags().is_none());
assert!(to_headline("* a ::").tags().count() == 0);
assert!(to_headline("* a : :").tags().count() == 0);
assert!(to_headline("* a :(:").tags().count() == 0);
assert!(to_headline("* a :a: :").tags().count() == 0);
assert!(to_headline("* a :a :").tags().count() == 0);
assert!(to_headline("* a a:").tags().count() == 0);
assert!(to_headline("* a :a").tags().count() == 0);
let tags = to_headline("* a \t:_:").tags().unwrap();
let tags = to_headline("* a \t:_:").tags();
assert_eq!(
vec!["_".to_string()],
tags.iter().map(|x| x.to_string()).collect::<Vec<_>>(),
tags.map(|x| x.to_string()).collect::<Vec<_>>(),
);
let tags = to_headline("* a \t :@:").tags().unwrap();
let tags = to_headline("* a \t :@:").tags();
assert_eq!(
vec!["@".to_string()],
tags.iter().map(|x| x.to_string()).collect::<Vec<_>>(),
tags.map(|x| x.to_string()).collect::<Vec<_>>(),
);
let tags = to_headline("* a :#:").tags().unwrap();
let tags = to_headline("* a :#:").tags();
assert_eq!(
vec!["#".to_string()],
tags.iter().map(|x| x.to_string()).collect::<Vec<_>>(),
tags.map(|x| x.to_string()).collect::<Vec<_>>(),
);
let tags = to_headline("* a\t :%:").tags().unwrap();
let tags = to_headline("* a\t :%:").tags();
assert_eq!(
vec!["%".to_string()],
tags.iter().map(|x| x.to_string()).collect::<Vec<_>>(),
tags.map(|x| x.to_string()).collect::<Vec<_>>(),
);
let tags = to_headline("* a :余: :破:").tags().unwrap();
let tags = to_headline("* a :余: :破:").tags();
assert_eq!(
vec!["".to_string(), "".to_string()],
tags.iter().map(|x| x.to_string()).collect::<Vec<_>>(),
tags.map(|x| x.to_string()).collect::<Vec<_>>(),
);
}