refactor: rename field names to align with org-elements-api

This commit is contained in:
PoiScript 2019-01-13 02:20:34 +08:00
parent f35c2d7bab
commit 93ed18602a
12 changed files with 278 additions and 298 deletions

View file

@ -3,7 +3,8 @@
pub struct Block;
impl Block {
pub fn parse(src: &str) -> Option<(usize, usize, usize, usize)> {
// return (name, args, contents-begin, contents-end, end)
pub fn parse(src: &str) -> Option<(&str, Option<&str>, usize, usize, usize)> {
if src.len() < 17 || !src[0..8].eq_ignore_ascii_case("#+BEGIN_") {
return None;
}
@ -15,7 +16,17 @@ impl Block {
let content = src.find(&format!("\n#+END_{}", &src[8..name]))?;
let end = eol!(src, content + 1);
Some((name, args, content, end + 1))
Some((
&src[8..name],
if name == args {
None
} else {
Some(&src[name..args])
},
args,
content + 1,
end + 1,
))
}
}

View file

@ -1,12 +1,10 @@
#[cfg_attr(test, derive(PartialEq))]
#[derive(Debug)]
pub struct DynBlock<'a> {
pub name: &'a str,
pub para: &'a str,
}
pub struct DynBlock;
impl<'a> DynBlock<'a> {
pub fn parse(src: &'a str) -> Option<(DynBlock<'a>, usize, usize)> {
impl DynBlock {
// return (name, parameters, contents-begin, contents-end, end)
pub fn parse(src: &str) -> Option<(&str, Option<&str>, usize, usize, usize)> {
if src.len() < 17 || !src[0..9].eq_ignore_ascii_case("#+BEGIN: ") {
return None;
}
@ -19,12 +17,15 @@ impl<'a> DynBlock<'a> {
let end = eol!(src, content + 1);
Some((
DynBlock {
name: &src[9..name],
para: &src[name..args].trim(),
&src[9..name],
if name == args {
None
} else {
Some(&src[name..args].trim())
},
content,
end,
args,
content + 1,
end + 1,
))
}
}
@ -34,18 +35,11 @@ fn parse() {
// TODO: testing
assert_eq!(
DynBlock::parse(
r"#+BEGIN: clocktable :scope file :block yesterday
r"#+BEGIN: clocktable :scope file
CONTENTS
#+END:
"
),
Some((
DynBlock {
name: "clocktable",
para: ":scope file :block yesterday"
},
57,
64
))
Some(("clocktable", Some(":scope file"), 31, 41, 48))
)
}

View file

@ -1,17 +1,14 @@
#[cfg_attr(test, derive(PartialEq))]
#[derive(Debug)]
pub struct FnDef<'a> {
pub label: &'a str,
pub contents: &'a str,
}
pub struct FnDef;
#[inline]
fn valid_label(ch: u8) -> bool {
ch.is_ascii_alphanumeric() || ch == b'-' || ch == b'_'
}
impl<'a> FnDef<'a> {
pub fn parse(src: &'a str) -> Option<(FnDef<'a>, usize)> {
impl FnDef {
pub fn parse(src: &str) -> Option<(&str, &str, usize)> {
starts_with!(src, "[fn:");
let label = until_while!(src, 4, b']', valid_label);
@ -22,13 +19,7 @@ impl<'a> FnDef<'a> {
let end = eol!(src);
Some((
FnDef {
label: &src[4..label],
contents: &src[label + 1..end],
},
end,
))
Some((&src[4..label], &src[label + 1..end], end))
}
}
@ -37,42 +28,30 @@ fn parse() {
assert_eq!(
FnDef::parse("[fn:1] https://orgmode.org").unwrap(),
(
FnDef {
label: "1",
contents: " https://orgmode.org",
},
"1",
" https://orgmode.org",
"[fn:1] https://orgmode.org".len()
)
);
assert_eq!(
FnDef::parse("[fn:word_1] https://orgmode.org").unwrap(),
(
FnDef {
label: "word_1",
contents: " https://orgmode.org",
},
"word_1",
" https://orgmode.org",
"[fn:word_1] https://orgmode.org".len()
)
);
assert_eq!(
FnDef::parse("[fn:WORD-1] https://orgmode.org").unwrap(),
(
FnDef {
label: "WORD-1",
contents: " https://orgmode.org",
},
"WORD-1",
" https://orgmode.org",
"[fn:WORD-1] https://orgmode.org".len()
)
);
assert_eq!(
FnDef::parse("[fn:WORD]").unwrap(),
(
FnDef {
label: "WORD",
contents: "",
},
"[fn:WORD]".len()
)
("WORD", "", "[fn:WORD]".len())
);
assert!(FnDef::parse("[fn:] https://orgmode.org").is_none());
assert!(FnDef::parse("[fn:wor d] https://orgmode.org").is_none());

View file

@ -1,12 +1,10 @@
#[cfg_attr(test, derive(PartialEq))]
#[derive(Debug)]
pub struct Keyword<'a> {
pub key: &'a str,
pub value: &'a str,
}
pub struct Keyword;
impl<'a> Keyword<'a> {
pub fn parse(src: &'a str) -> Option<(Keyword<'a>, usize)> {
impl Keyword {
// return (key, value, offset)
pub fn parse(src: &str) -> Option<(&str, &str, usize)> {
if cfg!(test) {
starts_with!(src, "#+");
}
@ -14,15 +12,9 @@ impl<'a> Keyword<'a> {
let key = until_while!(src, 2, b':', |c: u8| c.is_ascii_uppercase() || c == b'_');
// includes the eol character
let end = src.find('\n').map(|i| i + 1).unwrap_or(src.len());
let end = src.find('\n').map(|i| i + 1).unwrap_or_else(|| src.len());
Some((
Keyword {
key: &src[2..key],
value: &src[key + 1..end].trim(),
},
end,
))
Some((&src[2..key], &src[key + 1..end].trim(), end))
}
}
@ -118,43 +110,19 @@ fn parse_key<'a>(key: &'a str) -> Option<AffKeywordKey<'a>> {
fn parse() {
assert_eq!(
Keyword::parse("#+KEY:").unwrap(),
(
Keyword {
key: "KEY",
value: "",
},
"#+KEY:".len()
)
("KEY", "", "#+KEY:".len())
);
assert_eq!(
Keyword::parse("#+KEY: VALUE").unwrap(),
(
Keyword {
key: "KEY",
value: "VALUE",
},
"#+KEY: VALUE".len()
)
("KEY", "VALUE", "#+KEY: VALUE".len())
);
assert_eq!(
Keyword::parse("#+K_E_Y: VALUE").unwrap(),
(
Keyword {
key: "K_E_Y",
value: "VALUE",
},
"#+K_E_Y: VALUE".len()
)
("K_E_Y", "VALUE", "#+K_E_Y: VALUE".len())
);
assert_eq!(
Keyword::parse("#+KEY:VALUE\n").unwrap(),
(
Keyword {
key: "KEY",
value: "VALUE",
},
"#+KEY:VALUE\n".len()
)
("KEY", "VALUE", "#+KEY:VALUE\n".len())
);
assert!(Keyword::parse("#+KE Y: VALUE").is_none());
assert!(Keyword::parse("#+ KEY: VALUE").is_none());

View file

@ -2,12 +2,14 @@ pub mod block;
pub mod dyn_block;
pub mod fn_def;
pub mod keyword;
pub mod list;
pub mod rule;
pub use self::block::Block;
pub use self::dyn_block::DynBlock;
pub use self::fn_def::FnDef;
pub use self::keyword::Keyword;
pub use self::list::List;
pub use self::rule::Rule;
#[cfg_attr(test, derive(PartialEq, Debug))]
@ -18,44 +20,55 @@ pub enum Element<'a> {
// trailing space
trailing: usize,
},
Keyword(Keyword<'a>),
FnDef(FnDef<'a>),
Keyword {
key: &'a str,
value: &'a str,
},
FnDef {
label: &'a str,
contents: &'a str,
},
CenterBlock {
args: Option<&'a str>,
content_end: usize,
contents_end: usize,
end: usize,
},
QuoteBlock {
args: Option<&'a str>,
content_end: usize,
contents_end: usize,
end: usize,
},
SpecialBlock {
args: Option<&'a str>,
name: &'a str,
content_end: usize,
contents_end: usize,
end: usize,
},
CommentBlock {
content: &'a str,
args: Option<&'a str>,
contents: &'a str,
},
ExampleBlock {
content: &'a str,
args: Option<&'a str>,
contents: &'a str,
},
ExportBlock {
content: &'a str,
args: Option<&'a str>,
contents: &'a str,
},
SrcBlock {
content: &'a str,
args: Option<&'a str>,
contents: &'a str,
},
VerseBlock {
content: &'a str,
args: Option<&'a str>,
contents: &'a str,
},
DynBlock {
args: Option<&'a str>,
name: &'a str,
contents_end: usize,
end: usize,
},
Rule,
Comment(&'a str),
@ -75,9 +88,9 @@ impl<'a> Element<'a> {
loop {
// Unlike other element, footnote definition must starts at column 0
if bytes[pos] == b'[' {
if let Some((fd, off)) = FnDef::parse(&src[pos..]) {
if let Some((label, contents, off)) = FnDef::parse(&src[pos..]) {
return if pos == start {
(off + 1, Some(Element::FnDef(fd)), None)
(off + 1, Some(Element::FnDef { label, contents }), None)
} else {
(
start,
@ -85,7 +98,7 @@ impl<'a> Element<'a> {
end: pos - 1,
trailing: pos,
}),
Some((Element::FnDef(fd), off + 1)),
Some((Element::FnDef { label, contents }, off + 1)),
)
};
}
@ -103,7 +116,7 @@ impl<'a> Element<'a> {
(
start,
Some(Element::Paragraph {
end: end - 1,
end,
trailing: pos - 1,
}),
Some(($ele, $off)),
@ -113,14 +126,7 @@ impl<'a> Element<'a> {
}
if bytes[pos] == b'\n' {
return (
start,
Some(Element::Paragraph {
end: end - 1,
trailing: pos,
}),
None,
);
return (start, Some(Element::Paragraph { end, trailing: pos }), None);
}
// TODO: LaTeX environment
@ -133,112 +139,99 @@ impl<'a> Element<'a> {
}
}
if bytes[pos] == b'#' && bytes[pos + 1] == b'+' {
if let Some((name, args, content, end)) = Block::parse(&src[pos..]) {
match &src[pos + 8..pos + name] {
block_name if block_name.eq_ignore_ascii_case("CENTER") => ret!(
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") => ret!(
Element::QuoteBlock {
args: if name == args {
None
} else {
Some(&src[pos + name..pos + args].trim())
},
content_end: content + 1,
end,
},
pos + args
),
block_name if block_name.eq_ignore_ascii_case("COMMENT") => ret!(
if bytes[pos] == b'#' && bytes.get(pos + 1).filter(|&&b| b == b'+').is_some() {
if let Some((name, args, contents_beg, contents_end, end)) =
Block::parse(&src[pos..])
{
match name.to_uppercase().as_str() {
"COMMENT" => ret!(
Element::CommentBlock {
args: if name == args {
None
} else {
Some(&src[pos + name..pos + args])
},
content: &src[pos + args + 1..pos + content],
args,
contents: &src[pos + contents_beg + 1..pos + contents_end - 1],
},
pos + end
),
block_name if block_name.eq_ignore_ascii_case("EXAMPLE") => ret!(
"EXAMPLE" => ret!(
Element::ExampleBlock {
args: if name == args {
None
} else {
Some(&src[pos + name..pos + args])
},
content: &src[pos + args + 1..pos + content],
args,
contents: &src[pos + contents_beg + 1..pos + contents_end - 1],
},
pos + end
),
block_name if block_name.eq_ignore_ascii_case("EXPORT") => ret!(
"EXPORT" => ret!(
Element::ExportBlock {
args: if name == args {
None
} else {
Some(&src[pos + name..pos + args])
},
content: &src[pos + args + 1..pos + content],
args,
contents: &src[pos + contents_beg + 1..pos + contents_end - 1],
},
pos + end
),
block_name if block_name.eq_ignore_ascii_case("SRC") => ret!(
"SRC" => ret!(
Element::SrcBlock {
args: if name == args {
None
} else {
Some(&src[pos + name..pos + args])
},
content: &src[pos + args + 1..pos + content],
args,
contents: &src[pos + contents_beg + 1..pos + contents_end - 1],
},
pos + end
),
block_name if block_name.eq_ignore_ascii_case("VERSE") => ret!(
"VERSE" => ret!(
Element::VerseBlock {
args: if name == args {
None
} else {
Some(&src[pos + name..pos + args])
},
content: &src[pos + args + 1..pos + content],
args,
contents: &src[pos + contents_beg + 1..pos + contents_end - 1],
},
pos + end
),
block_name => ret!(
Element::SpecialBlock {
name: block_name,
args: if name == args {
None
} else {
Some(&src[pos + name..pos + args].trim())
},
content_end: content + 1,
"CENTER" => ret!(
Element::CenterBlock {
args,
contents_end,
end,
},
pos + args
pos + contents_beg
),
"QUOTE" => ret!(
Element::QuoteBlock {
args,
contents_end,
end,
},
pos + contents_beg
),
_ => ret!(
Element::SpecialBlock {
name,
args,
contents_end,
end,
},
pos + contents_beg
),
};
}
if let Some((kw, off)) = Keyword::parse(&src[pos..]) {
ret!(Element::Keyword(kw), off)
if let Some((name, args, contents_beg, contents_end, end)) =
DynBlock::parse(&src[pos..])
{
ret!(
Element::DynBlock {
name,
args,
contents_end,
end,
},
pos + contents_beg
)
}
if let Some((key, value, off)) = Keyword::parse(&src[pos..]) {
ret!(Element::Keyword { key, value }, off)
}
}
// Comment
if bytes[pos] == b'#' && bytes[pos + 1] == b' ' {
let eol = eol!(src, pos);
if bytes[pos] == b'#' && bytes.get(pos + 1).filter(|&&b| b == b' ').is_some() {
let eol = src[pos..]
.find('\n')
.map(|i| i + pos + 1)
.unwrap_or_else(|| src.len());
ret!(Element::Comment(&src[pos + 1..eol]), eol);
}
}

View file

@ -1,4 +1,5 @@
use elements::{FnDef, Keyword};
#![allow(unused_variables)]
use export::Handler;
use headline::Headline;
use objects::{Cookie, FnRef, InlineCall, InlineSrc, Link, Macros, RadioTarget, Snippet, Target};
@ -53,25 +54,35 @@ impl<W: Write> Handler<W> for HtmlHandler {
fn handle_end_special_block(&mut self, w: &mut W) -> Result<()> {
write!(w, "</div>")
}
fn handle_comment_block(&mut self, w: &mut W, content: &str, args: Option<&str>) -> Result<()> {
fn handle_comment_block(
&mut self,
w: &mut W,
contents: &str,
args: Option<&str>,
) -> Result<()> {
Ok(())
}
fn handle_example_block(&mut self, w: &mut W, content: &str, args: Option<&str>) -> Result<()> {
write!(w, "<pre><code>{}</code></pre>", content)
fn handle_example_block(
&mut self,
w: &mut W,
contents: &str,
args: Option<&str>,
) -> Result<()> {
write!(w, "<pre><code>{}</code></pre>", contents)
}
fn handle_export_block(&mut self, w: &mut W, content: &str, args: Option<&str>) -> Result<()> {
fn handle_export_block(&mut self, w: &mut W, contents: &str, args: Option<&str>) -> Result<()> {
Ok(())
}
fn handle_src_block(&mut self, w: &mut W, content: &str, args: Option<&str>) -> Result<()> {
write!(w, "<pre><code>{}</code></pre>", content)
fn handle_src_block(&mut self, w: &mut W, contents: &str, args: Option<&str>) -> Result<()> {
write!(w, "<pre><code>{}</code></pre>", contents)
}
fn handle_verse_block(&mut self, w: &mut W, content: &str, args: Option<&str>) -> Result<()> {
fn handle_verse_block(&mut self, w: &mut W, contents: &str, args: Option<&str>) -> Result<()> {
Ok(())
}
fn handle_dyn_block_start(&mut self, w: &mut W) -> Result<()> {
fn handle_start_dyn_block(&mut self, w: &mut W, name: &str, args: Option<&str>) -> Result<()> {
Ok(())
}
fn handle_dyn_block_end(&mut self, w: &mut W) -> Result<()> {
fn handle_end_dyn_block(&mut self, w: &mut W) -> Result<()> {
Ok(())
}
fn handle_list_start(&mut self, w: &mut W) -> Result<()> {
@ -89,7 +100,7 @@ impl<W: Write> Handler<W> for HtmlHandler {
fn handle_clock(&mut self, w: &mut W) -> Result<()> {
Ok(())
}
fn handle_comment(&mut self, w: &mut W, content: &str) -> Result<()> {
fn handle_comment(&mut self, w: &mut W, contents: &str) -> Result<()> {
Ok(())
}
fn handle_table_start(&mut self, w: &mut W) -> Result<()> {
@ -104,10 +115,10 @@ impl<W: Write> Handler<W> for HtmlHandler {
fn handle_latex_env(&mut self, w: &mut W) -> Result<()> {
Ok(())
}
fn handle_fn_def(&mut self, w: &mut W, fn_def: FnDef) -> Result<()> {
fn handle_fn_def(&mut self, w: &mut W, label: &str, contents: &str) -> Result<()> {
Ok(())
}
fn handle_keyword(&mut self, w: &mut W, kw: Keyword) -> Result<()> {
fn handle_keyword(&mut self, w: &mut W, key: &str, value: &str) -> Result<()> {
Ok(())
}
fn handle_rule(&mut self, w: &mut W) -> Result<()> {
@ -140,7 +151,11 @@ impl<W: Write> Handler<W> for HtmlHandler {
Ok(())
}
fn handle_snippet(&mut self, w: &mut W, snippet: Snippet) -> Result<()> {
Ok(())
if snippet.name.eq_ignore_ascii_case("HTML") {
write!(w, "{}", snippet.value)
} else {
Ok(())
}
}
fn handle_target(&mut self, w: &mut W, target: Target) -> Result<()> {
Ok(())
@ -169,13 +184,13 @@ impl<W: Write> Handler<W> for HtmlHandler {
fn handle_end_underline(&mut self, w: &mut W) -> Result<()> {
write!(w, "</u>")
}
fn handle_verbatim(&mut self, w: &mut W, content: &str) -> Result<()> {
write!(w, "<code>{}</code>", content)
fn handle_verbatim(&mut self, w: &mut W, contents: &str) -> Result<()> {
write!(w, "<code>{}</code>", contents)
}
fn handle_code(&mut self, w: &mut W, content: &str) -> Result<()> {
write!(w, "<code>{}</code>", content)
fn handle_code(&mut self, w: &mut W, contents: &str) -> Result<()> {
write!(w, "<code>{}</code>", contents)
}
fn handle_text(&mut self, w: &mut W, content: &str) -> Result<()> {
write!(w, "{}", content.replace('\n', " "))
fn handle_text(&mut self, w: &mut W, contents: &str) -> Result<()> {
write!(w, "{}", contents.replace('\n', " "))
}
}

View file

@ -2,7 +2,6 @@ mod html;
pub use self::html::HtmlHandler;
use elements::{FnDef, Keyword};
use headline::Headline;
use objects::{Cookie, FnRef, InlineCall, InlineSrc, Link, Macros, RadioTarget, Snippet, Target};
use parser::Parser;
@ -26,25 +25,27 @@ pub trait Handler<W: Write> {
args: Option<&str>,
) -> Result<()>;
fn handle_end_special_block(&mut self, w: &mut W) -> Result<()>;
fn handle_comment_block(&mut self, w: &mut W, content: &str, args: Option<&str>) -> Result<()>;
fn handle_example_block(&mut self, w: &mut W, content: &str, args: Option<&str>) -> Result<()>;
fn handle_export_block(&mut self, w: &mut W, content: &str, args: Option<&str>) -> Result<()>;
fn handle_src_block(&mut self, w: &mut W, content: &str, args: Option<&str>) -> Result<()>;
fn handle_verse_block(&mut self, w: &mut W, content: &str, args: Option<&str>) -> Result<()>;
fn handle_dyn_block_start(&mut self, w: &mut W) -> Result<()>;
fn handle_dyn_block_end(&mut self, w: &mut W) -> Result<()>;
fn handle_comment_block(&mut self, w: &mut W, contents: &str, args: Option<&str>)
-> Result<()>;
fn handle_example_block(&mut self, w: &mut W, contents: &str, args: Option<&str>)
-> Result<()>;
fn handle_export_block(&mut self, w: &mut W, contents: &str, args: Option<&str>) -> Result<()>;
fn handle_src_block(&mut self, w: &mut W, contents: &str, args: Option<&str>) -> Result<()>;
fn handle_verse_block(&mut self, w: &mut W, contents: &str, args: Option<&str>) -> Result<()>;
fn handle_start_dyn_block(&mut self, w: &mut W, name: &str, args: Option<&str>) -> Result<()>;
fn handle_end_dyn_block(&mut self, w: &mut W) -> Result<()>;
fn handle_list_start(&mut self, w: &mut W) -> Result<()>;
fn handle_list_end(&mut self, w: &mut W) -> Result<()>;
fn handle_aff_keywords(&mut self, w: &mut W) -> Result<()>;
fn handle_call(&mut self, w: &mut W) -> Result<()>;
fn handle_clock(&mut self, w: &mut W) -> Result<()>;
fn handle_comment(&mut self, w: &mut W, content: &str) -> Result<()>;
fn handle_comment(&mut self, w: &mut W, contents: &str) -> Result<()>;
fn handle_table_start(&mut self, w: &mut W) -> Result<()>;
fn handle_table_end(&mut self, w: &mut W) -> Result<()>;
fn handle_table_cell(&mut self, w: &mut W) -> Result<()>;
fn handle_latex_env(&mut self, w: &mut W) -> Result<()>;
fn handle_fn_def(&mut self, w: &mut W, fn_def: FnDef) -> Result<()>;
fn handle_keyword(&mut self, w: &mut W, kw: Keyword) -> Result<()>;
fn handle_fn_def(&mut self, w: &mut W, label: &str, contents: &str) -> Result<()>;
fn handle_keyword(&mut self, w: &mut W, key: &str, value: &str) -> Result<()>;
fn handle_rule(&mut self, w: &mut W) -> Result<()>;
fn handle_cookie(&mut self, w: &mut W, cookie: Cookie) -> Result<()>;
fn handle_fn_ref(&mut self, w: &mut W, fn_ref: FnRef) -> Result<()>;
@ -63,9 +64,9 @@ pub trait Handler<W: Write> {
fn handle_end_strike(&mut self, w: &mut W) -> Result<()>;
fn handle_start_underline(&mut self, w: &mut W) -> Result<()>;
fn handle_end_underline(&mut self, w: &mut W) -> Result<()>;
fn handle_verbatim(&mut self, w: &mut W, content: &str) -> Result<()>;
fn handle_code(&mut self, w: &mut W, content: &str) -> Result<()>;
fn handle_text(&mut self, w: &mut W, content: &str) -> Result<()>;
fn handle_verbatim(&mut self, w: &mut W, contents: &str) -> Result<()>;
fn handle_code(&mut self, w: &mut W, contents: &str) -> Result<()>;
fn handle_text(&mut self, w: &mut W, contents: &str) -> Result<()>;
}
pub struct Render<'a, W: Write, H: Handler<W>> {
@ -107,28 +108,31 @@ impl<'a, W: Write, H: Handler<W>> Render<'a, W, H> {
.handle_start_special_block(&mut self.writer, name, args)?
}
EndSpecialBlock => self.handler.handle_end_special_block(&mut self.writer)?,
CommentBlock { content, args } => {
CommentBlock { contents, args } => {
self.handler
.handle_comment_block(&mut self.writer, content, args)?
.handle_comment_block(&mut self.writer, contents, args)?
}
ExampleBlock { content, args } => {
ExampleBlock { contents, args } => {
self.handler
.handle_example_block(&mut self.writer, content, args)?
.handle_example_block(&mut self.writer, contents, args)?
}
ExportBlock { content, args } => {
ExportBlock { contents, args } => {
self.handler
.handle_export_block(&mut self.writer, content, args)?
.handle_export_block(&mut self.writer, contents, args)?
}
SrcBlock { content, args } => {
SrcBlock { contents, args } => {
self.handler
.handle_src_block(&mut self.writer, content, args)?
.handle_src_block(&mut self.writer, contents, args)?
}
VerseBlock { content, args } => {
VerseBlock { contents, args } => {
self.handler
.handle_verse_block(&mut self.writer, content, args)?
.handle_verse_block(&mut self.writer, contents, args)?
}
DynBlockStart => self.handler.handle_dyn_block_start(&mut self.writer)?,
DynBlockEnd => self.handler.handle_dyn_block_end(&mut self.writer)?,
StartDynBlock { name, args } => {
self.handler
.handle_start_dyn_block(&mut self.writer, name, args)?
}
EndDynBlock => self.handler.handle_end_dyn_block(&mut self.writer)?,
ListStart => self.handler.handle_list_start(&mut self.writer)?,
ListEnd => self.handler.handle_list_end(&mut self.writer)?,
AffKeywords => self.handler.handle_aff_keywords(&mut self.writer)?,
@ -139,8 +143,13 @@ impl<'a, W: Write, H: Handler<W>> Render<'a, W, H> {
TableEnd => self.handler.handle_table_end(&mut self.writer)?,
TableCell => self.handler.handle_table_cell(&mut self.writer)?,
LatexEnv => self.handler.handle_latex_env(&mut self.writer)?,
FnDef(f) => self.handler.handle_fn_def(&mut self.writer, f)?,
Keyword(keyword) => self.handler.handle_keyword(&mut self.writer, keyword)?,
FnDef { label, contents } => {
self.handler
.handle_fn_def(&mut self.writer, label, contents)?
}
Keyword { key, value } => {
self.handler.handle_keyword(&mut self.writer, key, value)?
}
Rule => self.handler.handle_rule(&mut self.writer)?,
Cookie(cookie) => self.handler.handle_cookie(&mut self.writer, cookie)?,
FnRef(fnref) => self.handler.handle_fn_ref(&mut self.writer, fnref)?,
@ -165,9 +174,9 @@ impl<'a, W: Write, H: Handler<W>> Render<'a, W, H> {
EndStrike => self.handler.handle_end_strike(&mut self.writer)?,
StartUnderline => self.handler.handle_start_underline(&mut self.writer)?,
EndUnderline => self.handler.handle_end_underline(&mut self.writer)?,
Verbatim(content) => self.handler.handle_verbatim(&mut self.writer, content)?,
Code(content) => self.handler.handle_code(&mut self.writer, content)?,
Text(content) => self.handler.handle_text(&mut self.writer, content)?,
Verbatim(contents) => self.handler.handle_verbatim(&mut self.writer, contents)?,
Code(contents) => self.handler.handle_code(&mut self.writer, contents)?,
Text(contents) => self.handler.handle_text(&mut self.writer, contents)?,
}
}

View file

@ -47,7 +47,7 @@ impl<'a> Headline<'a> {
#[inline]
fn parse_tags(src: &'a str) -> (Option<&'a str>, usize) {
if let Some(last) = src.split_whitespace().last() {
if last.starts_with(':') && last.ends_with(':') {
if last.len() > 2 && last.starts_with(':') && last.ends_with(':') {
(Some(last), src.rfind(':').unwrap() - last.len())
} else {
(None, src.len())

View file

@ -13,7 +13,7 @@ impl<'a> Cookie<'a> {
let num1 = until_while!(src, 1, |c| c == b'%' || c == b'/', |c: u8| c
.is_ascii_digit());
if src.len() > num1 && src.as_bytes()[num1 + 1] == b']' {
if src.as_bytes()[num1] == b'%' && *src.as_bytes().get(num1 + 1)? == b']' {
Some((
Cookie {
value: &src[0..num1 + 2],

View file

@ -11,10 +11,7 @@ impl<'a> Link<'a> {
starts_with!(src, "[[");
}
let path = until_while!(src, 2, b']', |c| c != b']'
&& c != b'<'
&& c != b'>'
&& c != b'\n');
let path = until_while!(src, 2, b']', |c| c != b'<' && c != b'>' && c != b'\n');
if cond_eq!(src, path + 1, b']') {
Some((
@ -25,10 +22,7 @@ impl<'a> Link<'a> {
path + 2,
))
} else if src.as_bytes()[path + 1] == b'[' {
let desc = until_while!(src, path + 2, b']', |c| c != b']'
&& c != b'['
&& c != b'\n');
let desc = until_while!(src, path + 2, b']', |c| c != b'[');
expect!(src, desc + 1, b']')?;
Some((

View file

@ -9,14 +9,10 @@ pub enum Container {
Section { end: usize },
Paragraph { end: usize, trailing: usize },
CenterBlock { content_end: usize, end: usize },
QuoteBlock { content_end: usize, end: usize },
SpecialBlock { content_end: usize, end: usize },
Drawer,
LatexEnv,
List,
Table,
CenterBlock { contents_end: usize, end: usize },
QuoteBlock { contents_end: usize, end: usize },
SpecialBlock { contents_end: usize, end: usize },
DynBlock { contents_end: usize, end: usize },
Italic { end: usize },
Strike { end: usize },
@ -45,30 +41,33 @@ pub enum Event<'a> {
args: Option<&'a str>,
},
EndSpecialBlock,
StartDynBlock {
name: &'a str,
args: Option<&'a str>,
},
EndDynBlock,
CommentBlock {
content: &'a str,
args: Option<&'a str>,
contents: &'a str,
},
ExampleBlock {
content: &'a str,
args: Option<&'a str>,
contents: &'a str,
},
ExportBlock {
content: &'a str,
args: Option<&'a str>,
contents: &'a str,
},
SrcBlock {
content: &'a str,
args: Option<&'a str>,
contents: &'a str,
},
VerseBlock {
content: &'a str,
args: Option<&'a str>,
contents: &'a str,
},
DynBlockStart,
DynBlockEnd,
ListStart,
ListEnd,
@ -85,8 +84,14 @@ pub enum Event<'a> {
TableCell,
LatexEnv,
FnDef(FnDef<'a>),
Keyword(Keyword<'a>),
FnDef {
label: &'a str,
contents: &'a str,
},
Keyword {
key: &'a str,
value: &'a str,
},
Rule,
Cookie(Cookie<'a>),
@ -172,21 +177,27 @@ impl<'a> Parser<'a> {
trailing: trailing + self.off,
}),
Element::QuoteBlock {
end, content_end, ..
end, contents_end, ..
} => self.stack.push(Container::QuoteBlock {
content_end: content_end + self.off,
contents_end: contents_end + self.off,
end: end + self.off,
}),
Element::CenterBlock {
end, content_end, ..
end, contents_end, ..
} => self.stack.push(Container::CenterBlock {
content_end: content_end + self.off,
contents_end: contents_end + self.off,
end: end + self.off,
}),
Element::SpecialBlock {
end, content_end, ..
end, contents_end, ..
} => self.stack.push(Container::SpecialBlock {
content_end: content_end + self.off,
contents_end: contents_end + self.off,
end: end + self.off,
}),
Element::DynBlock {
end, contents_end, ..
} => self.stack.push(Container::DynBlock {
contents_end: contents_end + self.off,
end: end + self.off,
}),
_ => (),
@ -239,7 +250,7 @@ impl<'a> Parser<'a> {
Container::CenterBlock { .. } => Event::EndCenterBlock,
Container::QuoteBlock { .. } => Event::EndQuoteBlock,
Container::SpecialBlock { .. } => Event::EndSpecialBlock,
_ => unimplemented!(),
Container::DynBlock { .. } => Event::EndDynBlock,
}
}
}
@ -248,12 +259,11 @@ impl<'a> Iterator for Parser<'a> {
type Item = Event<'a>;
fn next(&mut self) -> Option<Event<'a>> {
let tail = &self.text[self.off..];
if self.stack.is_empty() {
if self.off >= self.text.len() {
None
} else {
let tail = &self.text[self.off..];
Some(self.start_section_or_headline(tail))
}
} else {
@ -261,6 +271,7 @@ impl<'a> Iterator for Parser<'a> {
Some(match last {
Container::Headline { beg, end } => {
let tail = &self.text[self.off..];
if self.off >= end {
self.end()
} else if self.off == beg {
@ -269,20 +280,23 @@ impl<'a> Iterator for Parser<'a> {
self.start_headline(tail)
}
}
Container::CenterBlock {
content_end, end, ..
Container::DynBlock {
contents_end, end, ..
}
| Container::CenterBlock {
contents_end, end, ..
}
| Container::QuoteBlock {
content_end, end, ..
contents_end, end, ..
}
| Container::SpecialBlock {
content_end, end, ..
contents_end, end, ..
} => {
if self.off >= content_end {
if self.off >= contents_end {
self.off = end;
self.end()
} else {
self.next_ele(content_end)
self.next_ele(contents_end)
}
}
Container::Section { end } => {
@ -311,7 +325,6 @@ impl<'a> Iterator for Parser<'a> {
self.next_obj(end)
}
}
_ => unimplemented!(),
})
}
}
@ -344,18 +357,19 @@ impl<'a> From<Element<'a>> for Event<'a> {
fn from(ele: Element<'a>) -> Self {
match ele {
Element::Comment(c) => Event::Comment(c),
Element::FnDef(fd) => Event::FnDef(fd),
Element::Keyword(kw) => Event::Keyword(kw),
Element::FnDef { label, contents } => Event::FnDef { label, contents },
Element::Keyword { key, value } => Event::Keyword { key, value },
Element::Paragraph { .. } => Event::StartParagraph,
Element::Rule => Event::Rule,
Element::CenterBlock { .. } => Event::StartCenterBlock,
Element::QuoteBlock { .. } => Event::StartQuoteBlock,
Element::DynBlock { name, args, .. } => Event::StartDynBlock { name, args },
Element::SpecialBlock { name, args, .. } => Event::StartSpecialBlock { name, args },
Element::CommentBlock { args, content } => Event::CommentBlock { args, content },
Element::ExampleBlock { args, content } => Event::ExampleBlock { args, content },
Element::ExportBlock { args, content } => Event::ExportBlock { args, content },
Element::SrcBlock { args, content } => Event::SrcBlock { args, content },
Element::VerseBlock { args, content } => Event::VerseBlock { args, content },
Element::CommentBlock { args, contents } => Event::CommentBlock { args, contents },
Element::ExampleBlock { args, contents } => Event::ExampleBlock { args, contents },
Element::ExportBlock { args, contents } => Event::ExportBlock { args, contents },
Element::SrcBlock { args, contents } => Event::SrcBlock { args, contents },
Element::VerseBlock { args, contents } => Event::VerseBlock { args, contents },
}
}
}

View file

@ -16,13 +16,13 @@ macro_rules! expect {
#[macro_export]
macro_rules! eol {
($src:expr) => {
$src.find('\n').unwrap_or($src.len())
$src.find('\n').unwrap_or_else(|| $src.len())
};
($src:expr, $from:expr) => {
$src[$from..]
.find('\n')
.map(|i| i + $from)
.unwrap_or($src.len())
.unwrap_or_else(|| $src.len())
};
}
@ -132,6 +132,9 @@ macro_rules! starts_with {
#[macro_export]
macro_rules! skip_space {
($src:ident) => {
until!($src, |c| c != b' ').unwrap_or(0)
};
($src:ident, $from:expr) => {
until!($src[$from..], |c| c != b' ').unwrap_or(0) + $from
};