diff --git a/examples/html-slugify.rs b/examples/html-slugify.rs
index 6f62d4d..672ac09 100644
--- a/examples/html-slugify.rs
+++ b/examples/html-slugify.rs
@@ -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!(
"",
@@ -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!(""));
}
}
diff --git a/src/ast/generate.js b/src/ast/generate.js
index 12145b2..8aca5bd 100644
--- a/src/ast/generate.js
+++ b/src/ast/generate.js
@@ -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 { support::token(&self.syntax, ${kind}) }\n`;
}
diff --git a/src/ast/generated.rs b/src/ast/generated.rs
index d52c64a..90c2554 100644
--- a/src/ast/generated.rs
+++ b/src/ast/generated.rs
@@ -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 {
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 {
- 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 {
support::token(&self.syntax, HEADLINE_KEYWORD)
@@ -142,15 +163,9 @@ impl Headline {
pub fn section(&self) -> Option {
support::child(&self.syntax)
}
- pub fn tags(&self) -> Option {
- support::child(&self.syntax)
- }
pub fn planning(&self) -> Option {
support::child(&self.syntax)
}
- pub fn priority(&self) -> Option {
- support::child(&self.syntax)
- }
pub fn headlines(&self) -> AstChildren {
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 {
- Self::can_cast(node.kind()).then(|| HeadlineStars { syntax: node })
- }
- fn syntax(&self) -> &SyntaxNode {
- &self.syntax
- }
-}
-impl HeadlineStars {
- pub fn headline(&self) -> Option {
- 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 {
- 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 {
- Self::can_cast(node.kind()).then(|| HeadlineKeyword { syntax: node })
- }
- fn syntax(&self) -> &SyntaxNode {
- &self.syntax
- }
-}
-impl HeadlineKeyword {
- pub fn headline(&self) -> Option {
- 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 {
- Self::can_cast(node.kind()).then(|| HeadlinePriority { syntax: node })
- }
- fn syntax(&self) -> &SyntaxNode {
- &self.syntax
- }
-}
-impl HeadlinePriority {
- pub fn text(&self) -> Option {
- support::token(&self.syntax, TEXT)
- }
- pub fn headline(&self) -> Option {
- 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 {
- Self::can_cast(node.kind()).then(|| HeadlineTags { syntax: node })
- }
- fn syntax(&self) -> &SyntaxNode {
- &self.syntax
- }
-}
-impl HeadlineTags {
pub fn headline(&self) -> Option {
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 {
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 {
- super::last_child(&self.syntax)
+ pub fn begin(&self) -> u32 {
+ self.syntax.text_range().start().into()
}
- pub fn scheduled(&self) -> Option {
- super::last_child(&self.syntax)
- }
- pub fn closed(&self) -> Option {
- 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 {
- 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 {
- 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 {
- 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 {
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 {
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 {
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 {
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 {
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 {
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 {
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 {
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 {
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 {
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 {
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 {
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 {
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 {
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 {
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 {
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 {
support::token(&self.syntax, TIMESTAMP_YEAR)
}
diff --git a/src/ast/headline.rs b/src/ast/headline.rs
index f4d4dfe..54cd52d 100644
--- a/src/ast/headline.rs
+++ b/src/ast/headline.rs
@@ -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::().unwrap();
- /// assert_eq!(hdl.level(), Some(1));
+ /// assert_eq!(hdl.level(), 1);
/// let hdl = Org::parse("****** hello").first_node::().unwrap();
- /// assert_eq!(hdl.level(), Some(6));
+ /// assert_eq!(hdl.level(), 6);
/// ```
- pub fn level(&self) -> Option {
- 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 {
- self.planning()
- .and_then(|planning| planning.closed())
- .and_then(|node| support::child::(&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 {
- self.planning()
- .and_then(|planning| planning.scheduled())
- .and_then(|node| support::child::(&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 {
- self.planning()
- .and_then(|planning| planning.deadline())
- .and_then(|node| support::child::(&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::().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- {
+ 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::().unwrap();
+ /// assert_eq!(hdl.priority().unwrap().text(), "A");
+ /// let hdl = Org::parse("* [#破]").first_node::().unwrap();
+ /// assert_eq!(hdl.priority().unwrap().text(), "破");
+ /// ```
+ pub fn priority(&self) -> Option {
+ 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::().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
- {
- 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::().unwrap();
- /// assert_eq!(priority.text_string().unwrap(), "A".to_string());
- /// let priority = Org::parse("* [#破]").first_node::().unwrap();
- /// assert_eq!(priority.text_string().unwrap(), "破".to_string());
- /// ```
- pub fn text_string(&self) -> Option {
- self.text().map(|tk| tk.to_string())
- }
-}
diff --git a/src/ast/list.rs b/src/ast/list.rs
index 1ca114e..5a694c7 100644
--- a/src/ast/list.rs
+++ b/src/ast/list.rs
@@ -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 {
+ self.syntax
+ .children_with_tokens()
+ .find_map(filter_token(SyntaxKind::LIST_ITEM_BULLET))
+ }
+
+ pub fn checkbox(&self) -> Option {
+ 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 {
+ 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
- {
+ 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
diff --git a/src/ast/mod.rs b/src/ast/mod.rs
index dadd2cf..1bfdf94 100644
--- a/src/ast/mod.rs
+++ b/src/ast/mod.rs
@@ -8,6 +8,7 @@ mod headline;
mod inline_call;
mod link;
mod list;
+mod planning;
mod snippet;
mod table;
mod timestamp;
diff --git a/src/ast/planning.rs b/src/ast/planning.rs
new file mode 100644
index 0000000..f0b68c9
--- /dev/null
+++ b/src/ast/planning.rs
@@ -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::()
+ /// .unwrap()
+ /// .deadline()
+ /// .unwrap();
+ /// assert_eq!(s.day_start().unwrap().text(), "08");
+ /// ```
+ pub fn deadline(&self) -> Option {
+ 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::()
+ /// .unwrap()
+ /// .scheduled()
+ /// .unwrap();
+ /// assert_eq!(s.year_start().unwrap().text(), "2019");
+ /// ```
+ pub fn scheduled(&self) -> Option {
+ 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::()
+ /// .unwrap()
+ /// .closed()
+ /// .unwrap();
+ /// assert_eq!(s.month_start().unwrap().text(), "04");
+ /// ```
+ pub fn closed(&self) -> Option {
+ self.syntax
+ .children()
+ .filter(|n| n.kind() == SyntaxKind::PLANNING_CLOSED)
+ .last()
+ .and_then(|n| n.children().find_map(Timestamp::cast))
+ }
+}
diff --git a/src/export/forward.rs b/src/export/forward.rs
index 602061f..cfe87fc 100644
--- a/src/export/forward.rs
+++ b/src/export/forward.rs
@@ -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!("", 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!(""));
/// }
/// }
diff --git a/src/export/html.rs b/src/export/html.rs
index 0ee41df..df894f7 100644
--- a/src/export/html.rs
+++ b/src/export/html.rs
@@ -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!("")
}
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!("")
}
};
diff --git a/src/syntax/headline.rs b/src/syntax/headline.rs
index 6bf47db..1821659 100644
--- a/src/syntax/headline.rs
+++ b/src/syntax/headline.rs
@@ -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_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::>(),
+ tags.map(|x| x.to_string()).collect::>(),
);
- 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::>(),
+ tags.map(|x| x.to_string()).collect::>(),
);
- 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::>(),
+ tags.map(|x| x.to_string()).collect::>(),
);
- 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::>(),
+ tags.map(|x| x.to_string()).collect::>(),
);
- 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::>(),
+ tags.map(|x| x.to_string()).collect::>(),
);
}