From 93ed18602a972523767ffc6cb6cad5ac006516b7 Mon Sep 17 00:00:00 2001 From: PoiScript Date: Sun, 13 Jan 2019 02:20:34 +0800 Subject: [PATCH] refactor: rename field names to align with org-elements-api --- src/elements/block.rs | 15 ++- src/elements/dyn_block.rs | 34 +++---- src/elements/fn_def.rs | 43 +++------ src/elements/keyword.rs | 52 ++--------- src/elements/mod.rs | 191 ++++++++++++++++++-------------------- src/export/html.rs | 55 +++++++---- src/export/mod.rs | 71 +++++++------- src/headline.rs | 2 +- src/objects/cookie.rs | 2 +- src/objects/link.rs | 10 +- src/parser.rs | 94 +++++++++++-------- src/utils.rs | 7 +- 12 files changed, 278 insertions(+), 298 deletions(-) diff --git a/src/elements/block.rs b/src/elements/block.rs index 37b718b..a482645 100644 --- a/src/elements/block.rs +++ b/src/elements/block.rs @@ -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, + )) } } diff --git a/src/elements/dyn_block.rs b/src/elements/dyn_block.rs index ad7f0a3..0c9036a 100644 --- a/src/elements/dyn_block.rs +++ b/src/elements/dyn_block.rs @@ -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)) ) } diff --git a/src/elements/fn_def.rs b/src/elements/fn_def.rs index 0bcfb33..cfa89d2 100644 --- a/src/elements/fn_def.rs +++ b/src/elements/fn_def.rs @@ -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()); diff --git a/src/elements/keyword.rs b/src/elements/keyword.rs index ebb1f0d..6c1ffa2 100644 --- a/src/elements/keyword.rs +++ b/src/elements/keyword.rs @@ -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> { 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()); diff --git a/src/elements/mod.rs b/src/elements/mod.rs index 51a2018..6e0e9f1 100644 --- a/src/elements/mod.rs +++ b/src/elements/mod.rs @@ -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); } } diff --git a/src/export/html.rs b/src/export/html.rs index d5124f9..b4d4605 100644 --- a/src/export/html.rs +++ b/src/export/html.rs @@ -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 Handler for HtmlHandler { fn handle_end_special_block(&mut self, w: &mut W) -> Result<()> { write!(w, "") } - 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, "
{}
", content) + fn handle_example_block( + &mut self, + w: &mut W, + contents: &str, + args: Option<&str>, + ) -> Result<()> { + write!(w, "
{}
", 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, "
{}
", content) + fn handle_src_block(&mut self, w: &mut W, contents: &str, args: Option<&str>) -> Result<()> { + write!(w, "
{}
", 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 Handler 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 Handler 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 Handler 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 Handler for HtmlHandler { fn handle_end_underline(&mut self, w: &mut W) -> Result<()> { write!(w, "") } - fn handle_verbatim(&mut self, w: &mut W, content: &str) -> Result<()> { - write!(w, "{}", content) + fn handle_verbatim(&mut self, w: &mut W, contents: &str) -> Result<()> { + write!(w, "{}", contents) } - fn handle_code(&mut self, w: &mut W, content: &str) -> Result<()> { - write!(w, "{}", content) + fn handle_code(&mut self, w: &mut W, contents: &str) -> Result<()> { + write!(w, "{}", 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', " ")) } } diff --git a/src/export/mod.rs b/src/export/mod.rs index 2deb3d9..5dbd19b 100644 --- a/src/export/mod.rs +++ b/src/export/mod.rs @@ -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 { 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 { 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> { @@ -107,28 +108,31 @@ impl<'a, W: Write, H: Handler> 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> 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> 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)?, } } diff --git a/src/headline.rs b/src/headline.rs index 5cf2f60..273fd56 100644 --- a/src/headline.rs +++ b/src/headline.rs @@ -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()) diff --git a/src/objects/cookie.rs b/src/objects/cookie.rs index d1513dc..e93298b 100644 --- a/src/objects/cookie.rs +++ b/src/objects/cookie.rs @@ -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], diff --git a/src/objects/link.rs b/src/objects/link.rs index 27ee9c7..10473ee 100644 --- a/src/objects/link.rs +++ b/src/objects/link.rs @@ -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(( diff --git a/src/parser.rs b/src/parser.rs index b9a55b1..00e84bb 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -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> { - 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> 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 }, } } } diff --git a/src/utils.rs b/src/utils.rs index d61cb1b..826e157 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -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 };