feat(element): distinguish block by its name
This commit is contained in:
parent
5b9ceebea4
commit
da18d87aeb
6 changed files with 352 additions and 99 deletions
|
|
@ -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,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<'_> {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue