From 5ffd0004f1579aa42f7a3015f408cdbe803ae030 Mon Sep 17 00:00:00 2001
From: PoiScript
Date: Sun, 6 Oct 2019 11:42:44 +0800
Subject: [PATCH] refactor(parsers): introduce InlinePositions struct
---
orgize/src/parsers.rs | 115 +++++++++++++++++++-----------------------
orgize/tests/parse.rs | 6 +++
2 files changed, 59 insertions(+), 62 deletions(-)
diff --git a/orgize/src/parsers.rs b/orgize/src/parsers.rs
index 472b501..93cf69e 100644
--- a/orgize/src/parsers.rs
+++ b/orgize/src/parsers.rs
@@ -437,6 +437,48 @@ pub fn match_block<'a, T: ElementArena<'a>>(
}
}
+struct InlinePositions<'a> {
+ bytes: &'a [u8],
+ position: usize,
+ next: Option,
+}
+
+impl InlinePositions<'_> {
+ fn new(bytes: &[u8]) -> InlinePositions<'_> {
+ InlinePositions {
+ bytes,
+ position: 0,
+ next: Some(0),
+ }
+ }
+}
+
+impl Iterator for InlinePositions<'_> {
+ type Item = usize;
+
+ fn next(&mut self) -> Option {
+ lazy_static::lazy_static! {
+ static ref PRE_BYTES: BytesConst =
+ bytes!(b'@', b'<', b'[', b' ', b'(', b'{', b'\'', b'"', b'\n');
+ }
+
+ self.next.take().or_else(|| {
+ PRE_BYTES.find(&self.bytes[self.position..]).map(|i| {
+ self.position += i + 1;
+
+ match self.bytes[self.position - 1] {
+ b'{' => {
+ self.next = Some(self.position);
+ self.position - 1
+ }
+ b' ' | b'(' | b'\'' | b'"' | b'\n' => self.position,
+ _ => self.position - 1,
+ }
+ })
+ })
+ }
+}
+
pub fn parse_inlines<'a, T: ElementArena<'a>>(
arena: &mut T,
content: &'a str,
@@ -445,78 +487,27 @@ pub fn parse_inlines<'a, T: ElementArena<'a>>(
) {
let mut tail = content;
- if let Some(new_tail) = parse_inline(tail, arena, containers, parent) {
- tail = new_tail;
+ if let Some(tail_) = parse_inline(tail, arena, containers, parent) {
+ tail = tail_;
}
- let mut text = tail;
- let mut pos = 0;
-
- macro_rules! insert_text {
- ($value:expr) => {
+ while let Some((tail_, i)) = InlinePositions::new(tail.as_bytes())
+ .filter_map(|i| parse_inline(&tail[i..], arena, containers, parent).map(|tail| (tail, i)))
+ .next()
+ {
+ if i != 0 {
arena.insert_before_last_child(
Element::Text {
- value: $value.into(),
+ value: tail[0..i].into(),
},
parent,
);
- pos = 0;
- };
- }
-
- macro_rules! update_tail {
- ($new_tail:ident) => {
- debug_assert_ne!(tail, $new_tail);
- tail = $new_tail;
- text = $new_tail;
- };
- }
-
- lazy_static::lazy_static! {
- static ref PRE_BYTES: BytesConst =
- bytes!(b'@', b'<', b'[', b' ', b'(', b'{', b'\'', b'"', b'\n');
- }
-
- while let Some(off) = PRE_BYTES.find(tail.as_bytes()) {
- match tail.as_bytes()[off] {
- b'{' => {
- if let Some(new_tail) = parse_inline(&tail[off..], arena, containers, parent) {
- if pos != 0 {
- insert_text!(&text[0..pos + off]);
- }
- update_tail!(new_tail);
- continue;
- } else if let Some(new_tail) =
- parse_inline(&tail[off + 1..], arena, containers, parent)
- {
- insert_text!(&text[0..pos + off + 1]);
- update_tail!(new_tail);
- continue;
- }
- }
- b' ' | b'(' | b'\'' | b'"' | b'\n' => {
- if let Some(new_tail) = parse_inline(&tail[off + 1..], arena, containers, parent) {
- insert_text!(&text[0..pos + off + 1]);
- update_tail!(new_tail);
- continue;
- }
- }
- _ => {
- if let Some(new_tail) = parse_inline(&tail[off..], arena, containers, parent) {
- if pos != 0 {
- insert_text!(&text[0..pos + off]);
- }
- update_tail!(new_tail);
- continue;
- }
- }
}
- tail = &tail[off + 1..];
- pos += off + 1;
+ tail = tail_;
}
- if !text.is_empty() {
- arena.append_element(Element::Text { value: text.into() }, parent);
+ if !tail.is_empty() {
+ arena.append_element(Element::Text { value: tail.into() }, parent);
}
}
diff --git a/orgize/tests/parse.rs b/orgize/tests/parse.rs
index d079ae1..30b4017 100644
--- a/orgize/tests/parse.rs
+++ b/orgize/tests/parse.rs
@@ -21,6 +21,12 @@ test_suite!(
verbatim
and code
"
);
+test_suite!(
+ link,
+ "Visit[[http://example.com][link1]]or[[http://example.com][link1]].",
+ r#""#
+);
+
test_suite!(
section_and_headline,
r#"* title 1