feat: block parsing
This commit is contained in:
parent
55e6d67fae
commit
79477b812e
5 changed files with 442 additions and 20 deletions
|
|
@ -1,14 +1,24 @@
|
|||
pub enum BlockStart {
|
||||
name: BlockName,
|
||||
#[cfg_attr(test, derive(PartialEq, Debug))]
|
||||
pub struct Block;
|
||||
|
||||
impl Block {
|
||||
pub fn parse(src: &str) -> Option<(usize, usize, usize, usize)> {
|
||||
if src.len() < 17 || !src[0..8].eq_ignore_ascii_case("#+BEGIN_") {
|
||||
return None;
|
||||
}
|
||||
|
||||
let args = eol!(src);
|
||||
let name = until_while!(src, 8, |c| c == b' ' || c == b'\n', |c: u8| c
|
||||
.is_ascii_alphabetic());
|
||||
// TODO: ignore case match
|
||||
let content = src.find(&format!("\n#+END_{}", &src[8..name]))?;
|
||||
let end = eol!(src, content + 1);
|
||||
|
||||
Some((name, args, content, end + 1))
|
||||
}
|
||||
}
|
||||
|
||||
pub enum BlockName {
|
||||
Center,
|
||||
Comment,
|
||||
Example,
|
||||
Export,
|
||||
Quote,
|
||||
Src,
|
||||
Verbose,
|
||||
Special
|
||||
#[test]
|
||||
fn parse() {
|
||||
// TODO: testing
|
||||
}
|
||||
|
|
|
|||
0
src/elements/dyn_block.rs
Normal file
0
src/elements/dyn_block.rs
Normal file
|
|
@ -1,7 +1,9 @@
|
|||
pub mod block;
|
||||
pub mod fn_def;
|
||||
pub mod keyword;
|
||||
pub mod rule;
|
||||
|
||||
pub use self::block::Block;
|
||||
pub use self::fn_def::FnDef;
|
||||
pub use self::keyword::Keyword;
|
||||
pub use self::rule::Rule;
|
||||
|
|
@ -17,6 +19,42 @@ pub enum Element<'a> {
|
|||
Keyword(Keyword<'a>),
|
||||
FnDef(FnDef<'a>),
|
||||
|
||||
CenterBlock {
|
||||
args: Option<&'a str>,
|
||||
content_end: usize,
|
||||
end: usize,
|
||||
},
|
||||
QuoteBlock {
|
||||
args: Option<&'a str>,
|
||||
content_end: usize,
|
||||
end: usize,
|
||||
},
|
||||
SpecialBlock {
|
||||
args: Option<&'a str>,
|
||||
name: &'a str,
|
||||
content_end: usize,
|
||||
end: usize,
|
||||
},
|
||||
CommentBlock {
|
||||
content: &'a str,
|
||||
args: Option<&'a str>,
|
||||
},
|
||||
ExampleBlock {
|
||||
content: &'a str,
|
||||
args: Option<&'a str>,
|
||||
},
|
||||
ExportBlock {
|
||||
content: &'a str,
|
||||
args: Option<&'a str>,
|
||||
},
|
||||
SrcBlock {
|
||||
content: &'a str,
|
||||
args: Option<&'a str>,
|
||||
},
|
||||
VerseBlock {
|
||||
content: &'a str,
|
||||
args: Option<&'a str>,
|
||||
},
|
||||
Rule,
|
||||
Comment(&'a str),
|
||||
}
|
||||
|
|
@ -105,8 +143,305 @@ impl<'a> Element<'a> {
|
|||
}
|
||||
|
||||
if bytes[pos] == b'#' {
|
||||
// Keyword
|
||||
if bytes[pos + 1] == b'+' {
|
||||
if let Some((name, args, content, end)) = Block::parse(&src[pos..]) {
|
||||
// TODO: use macros
|
||||
return match &src[pos + 8..pos + name] {
|
||||
block_name if block_name.eq_ignore_ascii_case("CENTER") => {
|
||||
if pos == start {
|
||||
(
|
||||
pos + args,
|
||||
Some(Element::CenterBlock {
|
||||
args: if name == args {
|
||||
None
|
||||
} else {
|
||||
Some(&src[pos + name..pos + args])
|
||||
},
|
||||
content_end: content + 1,
|
||||
end,
|
||||
}),
|
||||
None,
|
||||
)
|
||||
} else {
|
||||
(
|
||||
start,
|
||||
Some(Element::Paragraph {
|
||||
end: if pos == start { end } else { end - 1 },
|
||||
trailing: pos - 1,
|
||||
}),
|
||||
Some((
|
||||
Element::CenterBlock {
|
||||
args: if name == args {
|
||||
None
|
||||
} else {
|
||||
Some(&src[pos + name..pos + args])
|
||||
},
|
||||
content_end: content + 1,
|
||||
end,
|
||||
},
|
||||
pos + args,
|
||||
)),
|
||||
)
|
||||
}
|
||||
}
|
||||
block_name if block_name.eq_ignore_ascii_case("QUOTE") => {
|
||||
if pos == start {
|
||||
(
|
||||
pos + args,
|
||||
Some(Element::QuoteBlock {
|
||||
args: if name == args {
|
||||
None
|
||||
} else {
|
||||
Some(&src[pos + name..pos + args].trim())
|
||||
},
|
||||
content_end: content + 1,
|
||||
end,
|
||||
}),
|
||||
None,
|
||||
)
|
||||
} else {
|
||||
(
|
||||
start,
|
||||
Some(Element::Paragraph {
|
||||
end: if pos == start { end } else { end - 1 },
|
||||
trailing: pos - 1,
|
||||
}),
|
||||
Some((
|
||||
Element::QuoteBlock {
|
||||
args: if name == args {
|
||||
None
|
||||
} else {
|
||||
Some(
|
||||
&src[pos + name..pos + args].trim(),
|
||||
)
|
||||
},
|
||||
content_end: content + 1,
|
||||
end,
|
||||
},
|
||||
args + pos,
|
||||
)),
|
||||
)
|
||||
}
|
||||
}
|
||||
block_name if block_name.eq_ignore_ascii_case("COMMENT") => {
|
||||
if pos == start {
|
||||
(
|
||||
args,
|
||||
Some(Element::CommentBlock {
|
||||
args: if name == args {
|
||||
None
|
||||
} else {
|
||||
Some(&src[pos + name..pos + args])
|
||||
},
|
||||
content: &src[pos + args..pos + content],
|
||||
}),
|
||||
None,
|
||||
)
|
||||
} else {
|
||||
(
|
||||
start,
|
||||
Some(Element::Paragraph {
|
||||
end: if pos == start { end } else { end - 1 },
|
||||
trailing: pos - 1,
|
||||
}),
|
||||
Some((
|
||||
Element::CommentBlock {
|
||||
args: if name == args {
|
||||
None
|
||||
} else {
|
||||
Some(&src[pos + name..pos + args])
|
||||
},
|
||||
content: &src[pos + args..pos + content],
|
||||
},
|
||||
args,
|
||||
)),
|
||||
)
|
||||
}
|
||||
}
|
||||
block_name if block_name.eq_ignore_ascii_case("EXAMPLE") => {
|
||||
if pos == start {
|
||||
(
|
||||
args,
|
||||
Some(Element::ExampleBlock {
|
||||
args: if name == args {
|
||||
None
|
||||
} else {
|
||||
Some(&src[pos + name..pos + args])
|
||||
},
|
||||
content: &src[pos + args..pos + content],
|
||||
}),
|
||||
None,
|
||||
)
|
||||
} else {
|
||||
(
|
||||
start,
|
||||
Some(Element::Paragraph {
|
||||
end: if pos == start { end } else { end - 1 },
|
||||
trailing: pos - 1,
|
||||
}),
|
||||
Some((
|
||||
Element::ExampleBlock {
|
||||
args: if name == args {
|
||||
None
|
||||
} else {
|
||||
Some(&src[pos + name..pos + args])
|
||||
},
|
||||
content: &src[pos + args..pos + content],
|
||||
},
|
||||
args,
|
||||
)),
|
||||
)
|
||||
}
|
||||
}
|
||||
block_name if block_name.eq_ignore_ascii_case("EXPORT") => {
|
||||
if pos == start {
|
||||
(
|
||||
args,
|
||||
Some(Element::ExportBlock {
|
||||
args: if name == args {
|
||||
None
|
||||
} else {
|
||||
Some(&src[pos + name..pos + args])
|
||||
},
|
||||
content: &src[pos + args..pos + content],
|
||||
}),
|
||||
None,
|
||||
)
|
||||
} else {
|
||||
(
|
||||
start,
|
||||
Some(Element::Paragraph {
|
||||
end: if pos == start { end } else { end - 1 },
|
||||
trailing: pos - 1,
|
||||
}),
|
||||
Some((
|
||||
Element::ExportBlock {
|
||||
args: if name == args {
|
||||
None
|
||||
} else {
|
||||
Some(&src[pos + name..pos + args])
|
||||
},
|
||||
content: &src[pos + args..pos + content],
|
||||
},
|
||||
args,
|
||||
)),
|
||||
)
|
||||
}
|
||||
}
|
||||
block_name if block_name.eq_ignore_ascii_case("SRC") => {
|
||||
if pos == start {
|
||||
(
|
||||
args,
|
||||
Some(Element::SrcBlock {
|
||||
args: if name == args {
|
||||
None
|
||||
} else {
|
||||
Some(&src[pos + name..pos + args])
|
||||
},
|
||||
content: &src[pos + args..pos + content],
|
||||
}),
|
||||
None,
|
||||
)
|
||||
} else {
|
||||
(
|
||||
start,
|
||||
Some(Element::Paragraph {
|
||||
end: if pos == start { end } else { end - 1 },
|
||||
trailing: pos - 1,
|
||||
}),
|
||||
Some((
|
||||
Element::SrcBlock {
|
||||
args: if name == args {
|
||||
None
|
||||
} else {
|
||||
Some(&src[pos + name..pos + args])
|
||||
},
|
||||
content: &src[pos + args..pos + content],
|
||||
},
|
||||
args,
|
||||
)),
|
||||
)
|
||||
}
|
||||
}
|
||||
block_name if block_name.eq_ignore_ascii_case("VERSE") => {
|
||||
if pos == start {
|
||||
(
|
||||
args,
|
||||
Some(Element::VerseBlock {
|
||||
args: if name == args {
|
||||
None
|
||||
} else {
|
||||
Some(&src[pos + name..pos + args])
|
||||
},
|
||||
content: &src[pos + args..pos + content],
|
||||
}),
|
||||
None,
|
||||
)
|
||||
} else {
|
||||
(
|
||||
start,
|
||||
Some(Element::Paragraph {
|
||||
end: if pos == start { end } else { end - 1 },
|
||||
trailing: pos - 1,
|
||||
}),
|
||||
Some((
|
||||
Element::VerseBlock {
|
||||
args: if name == args {
|
||||
None
|
||||
} else {
|
||||
Some(&src[pos + name..pos + args])
|
||||
},
|
||||
content: &src[pos + args..pos + content],
|
||||
},
|
||||
args,
|
||||
)),
|
||||
)
|
||||
}
|
||||
}
|
||||
block_name => {
|
||||
if pos == start {
|
||||
(
|
||||
pos + args,
|
||||
Some(Element::SpecialBlock {
|
||||
name: block_name,
|
||||
args: if name == args {
|
||||
None
|
||||
} else {
|
||||
Some(&src[pos + name..pos + args].trim())
|
||||
},
|
||||
content_end: content + 1,
|
||||
end,
|
||||
}),
|
||||
None,
|
||||
)
|
||||
} else {
|
||||
(
|
||||
start,
|
||||
Some(Element::Paragraph {
|
||||
end: if pos == start { end } else { end - 1 },
|
||||
trailing: pos - 1,
|
||||
}),
|
||||
Some((
|
||||
Element::SpecialBlock {
|
||||
name: block_name,
|
||||
args: if name == args {
|
||||
None
|
||||
} else {
|
||||
Some(
|
||||
&src[pos + name..pos + args].trim(),
|
||||
)
|
||||
},
|
||||
content_end: content + 1,
|
||||
end,
|
||||
},
|
||||
pos + args,
|
||||
)),
|
||||
)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if let Some((kw, off)) = Keyword::parse(&src[pos..]) {
|
||||
return if pos == start {
|
||||
(off, Some(Element::Keyword(kw)), None)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue