feat(element): distinguish block by its name

This commit is contained in:
PoiScript 2019-08-04 11:13:48 +08:00
parent 5b9ceebea4
commit da18d87aeb
6 changed files with 352 additions and 99 deletions

View file

@ -1,19 +1,15 @@
use memchr::{memchr, memchr_iter};
use crate::elements::Element;
#[cfg_attr(test, derive(PartialEq))]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[derive(Debug)]
pub struct Block<'a> {
pub name: &'a str,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub args: Option<&'a str>,
}
impl Block<'_> {
#[inline]
pub(crate) fn parse(text: &str) -> Option<(&str, Element<'_>, &str)> {
pub(crate) fn parse(text: &str) -> Option<(&str, Block<'_>, &str)> {
debug_assert!(text.starts_with("#+"));
if text.len() <= 8 || text[2..8].to_uppercase() != "BEGIN_" {
@ -36,18 +32,14 @@ impl Block<'_> {
for i in lines {
if text[pos..i].trim().eq_ignore_ascii_case(&end) {
return Some((
&text[i + 1..],
Element::Block(Block { name, args }),
&text[off..pos],
));
return Some((&text[i + 1..], Block { name, args }, &text[off..pos]));
}
pos = i + 1;
}
if text[pos..].trim().eq_ignore_ascii_case(&end) {
Some(("", Element::Block(Block { name, args }), &text[off..pos]))
Some(("", Block { name, args }, &text[off..pos]))
} else {
None
}
@ -60,10 +52,10 @@ fn parse() {
Block::parse("#+BEGIN_SRC\n#+END_SRC"),
Some((
"",
Element::Block(Block {
Block {
name: "SRC",
args: None,
}),
},
""
))
);
@ -71,12 +63,74 @@ fn parse() {
Block::parse("#+BEGIN_SRC javascript \nconsole.log('Hello World!');\n#+END_SRC\n"),
Some((
"",
Element::Block(Block {
Block {
name: "SRC",
args: Some("javascript"),
}),
},
"console.log('Hello World!');\n"
))
);
// TODO: more testing
}
#[derive(Debug)]
#[cfg_attr(test, derive(PartialEq))]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
pub struct SpecialBlock<'a> {
pub parameters: Option<&'a str>,
pub name: &'a str,
}
#[derive(Debug)]
#[cfg_attr(test, derive(PartialEq))]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
pub struct QuoteBlock<'a> {
pub parameters: Option<&'a str>,
}
#[derive(Debug)]
#[cfg_attr(test, derive(PartialEq))]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
pub struct CenterBlock<'a> {
pub parameters: Option<&'a str>,
}
#[derive(Debug)]
#[cfg_attr(test, derive(PartialEq))]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
pub struct VerseBlock<'a> {
pub parameters: Option<&'a str>,
}
#[derive(Debug)]
#[cfg_attr(test, derive(PartialEq))]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
pub struct CommentBlock<'a> {
pub data: Option<&'a str>,
pub contents: &'a str,
}
#[derive(Debug)]
#[cfg_attr(test, derive(PartialEq))]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
pub struct ExampleBlock<'a> {
pub data: Option<&'a str>,
pub contents: &'a str,
}
#[derive(Debug)]
#[cfg_attr(test, derive(PartialEq))]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
pub struct ExportBlock<'a> {
pub data: &'a str,
pub contents: &'a str,
}
#[derive(Debug)]
#[cfg_attr(test, derive(PartialEq))]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
pub struct SourceBlock<'a> {
pub contents: &'a str,
pub language: &'a str,
pub arguments: &'a str,
}

View file

@ -4,7 +4,7 @@ use memchr::{memchr, memchr2};
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[derive(Debug)]
pub struct Cookie<'a> {
value: &'a str,
pub value: &'a str,
}
impl Cookie<'_> {

View file

@ -23,9 +23,13 @@ mod timestamp;
mod title;
pub(crate) use emphasis::parse as parse_emphasis;
pub(crate) use block::Block;
pub use self::{
block::Block,
block::{
CenterBlock, CommentBlock, ExampleBlock, ExportBlock, QuoteBlock, SourceBlock,
SpecialBlock, VerseBlock,
},
clock::Clock,
cookie::Cookie,
drawer::Drawer,
@ -53,7 +57,14 @@ pub use self::{
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[cfg_attr(feature = "serde", serde(tag = "type", rename_all = "snake_case"))]
pub enum Element<'a> {
Block(Block<'a>),
SpecialBlock(SpecialBlock<'a>),
QuoteBlock(QuoteBlock<'a>),
CenterBlock(CenterBlock<'a>),
VerseBlock(VerseBlock<'a>),
CommentBlock(CommentBlock<'a>),
ExampleBlock(ExampleBlock<'a>),
ExportBlock(ExportBlock<'a>),
SourceBlock(SourceBlock<'a>),
BabelCall(BabelCall<'a>),
Section,
Clock(Clock<'a>),
@ -93,7 +104,10 @@ pub enum Element<'a> {
impl Element<'_> {
pub fn is_container(&self) -> bool {
match self {
Element::Block(_)
Element::SpecialBlock(_)
| Element::QuoteBlock(_)
| Element::CenterBlock(_)
| Element::VerseBlock(_)
| Element::Bold
| Element::Document
| Element::DynBlock(_)
@ -112,30 +126,50 @@ impl Element<'_> {
}
macro_rules! impl_from {
($ident:ident) => {
impl<'a> From<$ident<'a>> for Element<'a> {
fn from(ele: $ident<'a>) -> Element<'a> {
Element::$ident(ele)
($($ele0:ident),*; $($ele1:ident),*) => {
$(
impl<'a> From<$ele0<'a>> for Element<'a> {
fn from(ele: $ele0<'a>) -> Element<'a> {
Element::$ele0(ele)
}
}
}
)*
$(
impl<'a> From<$ele1> for Element<'a> {
fn from(ele: $ele1) -> Element<'a> {
Element::$ele1(ele)
}
}
)*
};
}
impl_from!(Block);
impl_from!(BabelCall);
impl_from!(Clock);
impl_from!(Cookie);
impl_from!(Drawer);
impl_from!(DynBlock);
impl_from!(FnDef);
impl_from!(FnRef);
impl_from!(InlineCall);
impl_from!(InlineSrc);
impl_from!(Keyword);
impl_from!(Link);
impl_from!(ListItem);
impl_from!(Macros);
impl_from!(Planning);
impl_from!(Snippet);
impl_from!(Timestamp);
impl_from!(Target);
impl_from!(
BabelCall,
CenterBlock,
Clock,
CommentBlock,
Cookie,
Drawer,
DynBlock,
ExampleBlock,
ExportBlock,
FnDef,
FnRef,
InlineCall,
InlineSrc,
Keyword,
Link,
ListItem,
Macros,
Planning,
QuoteBlock,
Snippet,
SourceBlock,
SpecialBlock,
Target,
Timestamp,
VerseBlock;
RadioTarget,
List
);