Encapsulate inline parsing

- Rename Inline stuff to Line
- Rename SubText stuff to Inline
pull/1/head
trivernis 5 years ago
parent c4485e1394
commit ba7fd40f92

2
Cargo.lock generated

@ -358,7 +358,7 @@ dependencies = [
[[package]] [[package]]
name = "snekdown" name = "snekdown"
version = "0.5.4" version = "0.5.5"
dependencies = [ dependencies = [
"chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",

@ -1,6 +1,6 @@
[package] [package]
name = "snekdown" name = "snekdown"
version = "0.5.4" version = "0.5.5"
authors = ["trivernis <trivernis@protonmail.com>"] authors = ["trivernis <trivernis@protonmail.com>"]
edition = "2018" edition = "2018"
license-file = "LICENSE" license-file = "LICENSE"

Binary file not shown.

@ -25,33 +25,33 @@ impl ToHtml for Element {
match self { match self {
Element::Block(block) => block.to_html(), Element::Block(block) => block.to_html(),
Element::Inline(inline) => inline.to_html(), Element::Inline(inline) => inline.to_html(),
Element::SubText(sub) => sub.to_html(), Element::Line(line) => line.to_html(),
} }
} }
} }
impl ToHtml for Inline { impl ToHtml for Line {
fn to_html(&self) -> String { fn to_html(&self) -> String {
match self { match self {
Inline::Text(text) => text.to_html(), Line::Text(text) => text.to_html(),
Inline::Ruler(ruler) => ruler.to_html(), Line::Ruler(ruler) => ruler.to_html(),
Inline::Anchor(anchor) => anchor.to_html(), Line::Anchor(anchor) => anchor.to_html(),
} }
} }
} }
impl ToHtml for SubText { impl ToHtml for Inline {
fn to_html(&self) -> String { fn to_html(&self) -> String {
match self { match self {
SubText::Url(url) => url.to_html(), Inline::Url(url) => url.to_html(),
SubText::Monospace(mono) => mono.to_html(), Inline::Monospace(mono) => mono.to_html(),
SubText::Striked(striked) => striked.to_html(), Inline::Striked(striked) => striked.to_html(),
SubText::Plain(plain) => plain.to_html(), Inline::Plain(plain) => plain.to_html(),
SubText::Italic(italic) => italic.to_html(), Inline::Italic(italic) => italic.to_html(),
SubText::Underlined(under) => under.to_html(), Inline::Underlined(under) => under.to_html(),
SubText::Bold(bold) => bold.to_html(), Inline::Bold(bold) => bold.to_html(),
SubText::Image(img) => img.to_html(), Inline::Image(img) => img.to_html(),
SubText::Placeholder(placeholder) => placeholder.lock().unwrap().to_html(), Inline::Placeholder(placeholder) => placeholder.lock().unwrap().to_html(),
} }
} }
} }
@ -277,7 +277,7 @@ impl ToHtml for Ruler {
} }
} }
impl ToHtml for Text { impl ToHtml for TextLine {
fn to_html(&self) -> String { fn to_html(&self) -> String {
self.subtext self.subtext
.iter() .iter()

@ -281,6 +281,7 @@ impl CharStateMachine for Parser {
} }
} }
/// seeks until it encounters a linebreak character
fn seek_until_linebreak(&mut self) { fn seek_until_linebreak(&mut self) {
if self.check_special(&LB) { if self.check_special(&LB) {
self.skip_char(); self.skip_char();

@ -36,8 +36,8 @@ pub enum MetadataValue {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum Element { pub enum Element {
Block(Box<Block>), Block(Box<Block>),
Line(Box<Line>),
Inline(Box<Inline>), Inline(Box<Inline>),
SubText(Box<SubText>),
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -53,8 +53,8 @@ pub enum Block {
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum Inline { pub enum Line {
Text(Text), Text(TextLine),
Ruler(Ruler), Ruler(Ruler),
Anchor(Anchor), Anchor(Anchor),
} }
@ -77,13 +77,13 @@ pub struct Section {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Header { pub struct Header {
pub(crate) size: u8, pub(crate) size: u8,
pub(crate) line: Inline, pub(crate) line: Line,
pub(crate) anchor: String, pub(crate) anchor: String,
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Paragraph { pub struct Paragraph {
pub(crate) elements: Vec<Inline>, pub(crate) elements: Vec<Line>,
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -94,7 +94,7 @@ pub struct List {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct ListItem { pub struct ListItem {
pub(crate) text: Inline, pub(crate) text: Line,
pub(crate) level: u16, pub(crate) level: u16,
pub(crate) ordered: bool, pub(crate) ordered: bool,
pub(crate) children: Vec<ListItem>, pub(crate) children: Vec<ListItem>,
@ -113,7 +113,7 @@ pub struct Row {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Cell { pub struct Cell {
pub(crate) text: Inline, pub(crate) text: Line,
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -125,7 +125,7 @@ pub struct CodeBlock {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Quote { pub struct Quote {
pub(crate) metadata: Option<InlineMetadata>, pub(crate) metadata: Option<InlineMetadata>,
pub(crate) text: Vec<Text>, pub(crate) text: Vec<TextLine>,
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -148,12 +148,12 @@ pub struct InlineMetadata {
pub struct Ruler {} pub struct Ruler {}
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Text { pub struct TextLine {
pub subtext: Vec<SubText>, pub subtext: Vec<Inline>,
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum SubText { pub enum Inline {
Plain(PlainText), Plain(PlainText),
Bold(BoldText), Bold(BoldText),
Italic(ItalicText), Italic(ItalicText),
@ -172,22 +172,22 @@ pub struct PlainText {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct BoldText { pub struct BoldText {
pub(crate) value: Box<SubText>, pub(crate) value: Box<Inline>,
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct ItalicText { pub struct ItalicText {
pub(crate) value: Box<SubText>, pub(crate) value: Box<Inline>,
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct UnderlinedText { pub struct UnderlinedText {
pub(crate) value: Box<SubText>, pub(crate) value: Box<Inline>,
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct StrikedText { pub struct StrikedText {
pub(crate) value: Box<SubText>, pub(crate) value: Box<Inline>,
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -215,7 +215,7 @@ pub struct Placeholder {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Anchor { pub struct Anchor {
pub(crate) description: Box<Inline>, pub(crate) description: Box<Line>,
pub(crate) reference: String, pub(crate) reference: String,
} }
@ -266,7 +266,7 @@ impl Document {
self.elements.iter().for_each(|e| match e { self.elements.iter().for_each(|e| match e {
Block::Section(sec) => { Block::Section(sec) => {
if !sec.get_hide_in_toc() { if !sec.get_hide_in_toc() {
let mut item = ListItem::new(Inline::Anchor(sec.header.get_anchor()), 1, true); let mut item = ListItem::new(Line::Anchor(sec.header.get_anchor()), 1, true);
item.children.append(&mut sec.get_toc_list().items); item.children.append(&mut sec.get_toc_list().items);
list.add_item(item); list.add_item(item);
} }
@ -322,7 +322,7 @@ impl Section {
self.elements.iter().for_each(|e| { self.elements.iter().for_each(|e| {
if let Block::Section(sec) = e { if let Block::Section(sec) = e {
if !sec.get_hide_in_toc() { if !sec.get_hide_in_toc() {
let mut item = ListItem::new(Inline::Anchor(sec.header.get_anchor()), 1, true); let mut item = ListItem::new(Line::Anchor(sec.header.get_anchor()), 1, true);
item.children.append(&mut sec.get_toc_list().items); item.children.append(&mut sec.get_toc_list().items);
list.add_item(item); list.add_item(item);
} }
@ -342,7 +342,7 @@ impl Section {
} }
impl Header { impl Header {
pub fn new(content: Inline, anchor: String) -> Self { pub fn new(content: Line, anchor: String) -> Self {
Self { Self {
size: 0, size: 0,
anchor, anchor,
@ -365,7 +365,7 @@ impl Paragraph {
} }
} }
pub fn add_element(&mut self, element: Inline) { pub fn add_element(&mut self, element: Line) {
self.elements.push(element) self.elements.push(element)
} }
} }
@ -384,7 +384,7 @@ impl List {
} }
impl ListItem { impl ListItem {
pub fn new(text: Inline, level: u16, ordered: bool) -> Self { pub fn new(text: Line, level: u16, ordered: bool) -> Self {
Self { Self {
text, text,
level, level,
@ -398,14 +398,14 @@ impl ListItem {
} }
} }
impl Text { impl TextLine {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
subtext: Vec::new(), subtext: Vec::new(),
} }
} }
pub fn add_subtext(&mut self, subtext: SubText) { pub fn add_subtext(&mut self, subtext: Inline) {
self.subtext.push(subtext) self.subtext.push(subtext)
} }
} }
@ -447,7 +447,7 @@ impl Quote {
} }
} }
pub fn add_text(&mut self, text: Text) { pub fn add_text(&mut self, text: TextLine) {
self.text.push(text) self.text.push(text)
} }
} }

@ -2,4 +2,5 @@ pub mod charstate;
pub mod elements; pub mod elements;
pub mod parser; pub mod parser;
pub mod placeholders; pub mod placeholders;
pub mod subtext;
pub mod tokens; pub mod tokens;

@ -2,6 +2,7 @@ use super::elements::*;
use super::tokens::*; use super::tokens::*;
use crate::parsing::charstate::CharStateMachine; use crate::parsing::charstate::CharStateMachine;
use crate::parsing::placeholders::ProcessPlaceholders; use crate::parsing::placeholders::ProcessPlaceholders;
use crate::parsing::subtext::ParseInline;
use crossbeam_utils::sync::WaitGroup; use crossbeam_utils::sync::WaitGroup;
use std::collections::HashMap; use std::collections::HashMap;
use std::error::Error; use std::error::Error;
@ -100,7 +101,7 @@ pub struct Parser {
paths: Arc<Mutex<Vec<String>>>, paths: Arc<Mutex<Vec<String>>>,
wg: WaitGroup, wg: WaitGroup,
is_child: bool, is_child: bool,
subtext_break_at: Vec<char>, pub(crate) inline_break_at: Vec<char>,
document: Document, document: Document,
} }
@ -147,7 +148,7 @@ impl Parser {
paths, paths,
wg: WaitGroup::new(), wg: WaitGroup::new(),
is_child, is_child,
subtext_break_at: Vec::new(), inline_break_at: Vec::new(),
document: Document::new(!is_child), document: Document::new(!is_child),
} }
} }
@ -352,7 +353,7 @@ impl Parser {
/// parses the header of a section /// parses the header of a section
fn parse_header(&mut self) -> Result<Header, ParseError> { fn parse_header(&mut self) -> Result<Header, ParseError> {
let start_index = self.index; let start_index = self.index;
let line = self.parse_inline()?; let line = self.parse_line()?;
let mut anchor = String::new(); let mut anchor = String::new();
self.text[start_index..self.index] self.text[start_index..self.index]
.iter() .iter()
@ -399,7 +400,7 @@ impl Parser {
&& self.next_char() != None && self.next_char() != None
&& (self.check_seek_inline_whitespace() || self.check_special(&LB)) && (self.check_seek_inline_whitespace() || self.check_special(&LB))
{ {
if let Ok(text) = self.parse_text() { if let Ok(text) = self.parse_text_line() {
if text.subtext.len() > 0 { if text.subtext.len() > 0 {
quote.add_text(text); quote.add_text(text);
} }
@ -415,7 +416,7 @@ impl Parser {
} }
/// Parses metadata /// Parses metadata
fn parse_inline_metadata(&mut self) -> Result<InlineMetadata, ParseError> { pub(crate) fn parse_inline_metadata(&mut self) -> Result<InlineMetadata, ParseError> {
let start_index = self.index; let start_index = self.index;
self.assert_special(&META_OPEN, start_index)?; self.assert_special(&META_OPEN, start_index)?;
self.skip_char(); self.skip_char();
@ -523,7 +524,7 @@ impl Parser {
fn parse_paragraph(&mut self) -> Result<Paragraph, ParseError> { fn parse_paragraph(&mut self) -> Result<Paragraph, ParseError> {
self.seek_whitespace(); self.seek_whitespace();
let mut paragraph = Paragraph::new(); let mut paragraph = Paragraph::new();
while let Ok(token) = self.parse_inline() { while let Ok(token) = self.parse_line() {
paragraph.add_element(token); paragraph.add_element(token);
let start_index = self.index; let start_index = self.index;
if self.check_special_sequence_group(&BLOCK_SPECIAL_CHARS) { if self.check_special_sequence_group(&BLOCK_SPECIAL_CHARS) {
@ -623,7 +624,7 @@ impl Parser {
return Err(self.revert_with_error(start_index)); return Err(self.revert_with_error(start_index));
} }
let item = ListItem::new(self.parse_inline()?, level as u16, ordered); let item = ListItem::new(self.parse_line()?, level as u16, ordered);
Ok(item) Ok(item)
} }
@ -663,11 +664,11 @@ impl Parser {
self.seek_inline_whitespace(); self.seek_inline_whitespace();
self.assert_special(&PIPE, start_index)?; self.assert_special(&PIPE, start_index)?;
self.skip_char(); self.skip_char();
self.subtext_break_at.push(PIPE); self.inline_break_at.push(PIPE);
self.seek_inline_whitespace(); self.seek_inline_whitespace();
let mut row = Row::new(); let mut row = Row::new();
while let Ok(element) = self.parse_inline() { while let Ok(element) = self.parse_line() {
row.add_cell(Cell { text: element }); row.add_cell(Cell { text: element });
if self.check_special(&PIPE) { if self.check_special(&PIPE) {
if self.next_char() == None { if self.next_char() == None {
@ -679,7 +680,7 @@ impl Parser {
} }
self.seek_inline_whitespace(); self.seek_inline_whitespace();
} }
self.subtext_break_at.clear(); self.inline_break_at.clear();
if row.cells.len() > 0 { if row.cells.len() > 0 {
Ok(row) Ok(row)
@ -689,21 +690,21 @@ impl Parser {
} }
/// parses inline definitions /// parses inline definitions
fn parse_inline(&mut self) -> Result<Inline, ParseError> { fn parse_line(&mut self) -> Result<Line, ParseError> {
if self.index > self.text.len() { if self.index > self.text.len() {
Err(ParseError::new(self.index)) Err(ParseError::new(self.index))
} else { } else {
if let Ok(ruler) = self.parse_ruler() { if let Ok(ruler) = self.parse_ruler() {
return Ok(Inline::Ruler(ruler)); return Ok(Line::Ruler(ruler));
} else if let Ok(text) = self.parse_text() { } else if let Ok(text) = self.parse_text_line() {
return Ok(Inline::Text(text)); return Ok(Line::Text(text));
} }
return Err(ParseError::new(self.index)); return Err(ParseError::new(self.index));
} }
} }
/// parses a placeholder element /// parses a placeholder element
fn parse_placeholder(&mut self) -> Result<Arc<Mutex<Placeholder>>, ParseError> { pub(crate) fn parse_placeholder(&mut self) -> Result<Arc<Mutex<Placeholder>>, ParseError> {
let start_index = self.index; let start_index = self.index;
self.assert_special_sequence(&SQ_PHOLDER_START, self.index)?; self.assert_special_sequence(&SQ_PHOLDER_START, self.index)?;
self.skip_char(); self.skip_char();
@ -731,9 +732,9 @@ impl Parser {
} }
/// Parses a line of text /// Parses a line of text
fn parse_text(&mut self) -> Result<Text, ParseError> { fn parse_text_line(&mut self) -> Result<TextLine, ParseError> {
let mut text = Text::new(); let mut text = TextLine::new();
while let Ok(subtext) = self.parse_subtext() { while let Ok(subtext) = self.parse_inline() {
text.add_subtext(subtext); text.add_subtext(subtext);
let current_index = self.index; let current_index = self.index;
if self.next_char() == None { if self.next_char() == None {
@ -748,158 +749,4 @@ impl Parser {
Ok(text) Ok(text)
} }
/// parses subtext, the formatting parts of a line (Text)
fn parse_subtext(&mut self) -> Result<SubText, ParseError> {
if self.check_linebreak() {
return Err(ParseError::new(self.index));
}
if let Ok(image) = self.parse_image() {
return Ok(SubText::Image(image));
}
if let Ok(url) = self.parse_url(false) {
return Ok(SubText::Url(url));
}
if let Ok(pholder) = self.parse_placeholder() {
return Ok(SubText::Placeholder(pholder));
}
match self.current_char {
ASTERISK if !self.check_escaped() => {
parse_option!(self.next_char(), self.index);
if self.check_special(&ASTERISK) {
parse_option!(self.next_char(), self.index);
let subtext = self.parse_subtext()?;
if self.check_special(&ASTERISK) {
self.skip_char();
if self.check_special(&ASTERISK) {
self.skip_char();
}
}
Ok(SubText::Bold(BoldText {
value: Box::new(subtext),
}))
} else {
let subtext = self.parse_subtext()?;
if self.check_special(&ASTERISK) {
self.skip_char();
}
Ok(SubText::Italic(ItalicText {
value: Box::new(subtext),
}))
}
}
UNDERSCR if !self.check_escaped() => {
parse_option!(self.next_char(), self.index);
let subtext = self.parse_subtext()?;
parse_option!(self.next_char(), self.index);
Ok(SubText::Underlined(UnderlinedText {
value: Box::new(subtext),
}))
}
TILDE if !self.check_escaped() => {
parse_option!(self.next_char(), self.index);
let subtext = self.parse_subtext()?;
if self.check_special(&TILDE) {
parse_option!(self.next_char(), self.index);
}
Ok(SubText::Striked(StrikedText {
value: Box::new(subtext),
}))
}
BACKTICK if !self.check_escaped() => {
parse_option!(self.next_char(), self.index);
let content = self.get_string_until(&[BACKTICK, LB], &[])?;
if self.check_special(&BACKTICK) {
parse_option!(self.next_char(), self.index)
}
Ok(SubText::Monospace(MonospaceText { value: content }))
}
PIPE if !self.check_escaped() => Err(ParseError::new(self.index)), // handling of table cells
_ => Ok(SubText::Plain(self.parse_plain_text()?)),
}
}
/// parses an image url
fn parse_image(&mut self) -> Result<Image, ParseError> {
let start_index = self.index;
self.seek_inline_whitespace();
self.assert_special(&IMG_START, start_index)?;
self.skip_char();
if let Ok(url) = self.parse_url(true) {
let metadata = if let Ok(meta) = self.parse_inline_metadata() {
Some(meta)
} else {
None
};
Ok(Image { url, metadata })
} else {
Err(self.revert_with_error(start_index))
}
}
// parses an url
fn parse_url(&mut self, short_syntax: bool) -> Result<Url, ParseError> {
let start_index = self.index;
self.seek_inline_whitespace();
let mut description = String::new();
if self.check_special(&DESC_OPEN) {
self.skip_char();
description = if let Ok(desc) = self.get_string_until(&[DESC_CLOSE], &[LB]) {
desc
} else {
return Err(self.revert_with_error(start_index));
};
} else if !short_syntax {
return Err(self.revert_with_error(start_index));
}
self.skip_char();
self.assert_special(&URL_OPEN, start_index)?;
self.skip_char();
self.seek_inline_whitespace();
let url = if let Ok(url_str) = self.get_string_until(&[URL_CLOSE], &[LB]) {
url_str
} else {
return Err(self.revert_with_error(start_index));
};
self.skip_char();
if description.is_empty() {
Ok(Url::new(None, url))
} else {
Ok(Url::new(Some(description), url))
}
}
/// parses plain text as a string until it encounters an unescaped special inline char
fn parse_plain_text(&mut self) -> Result<PlainText, ParseError> {
let mut current_char = self.current_char;
let mut characters = String::new();
let mut count = 0;
loop {
if self.check_special_group(&INLINE_SPECIAL_CHARS)
|| (count > 0 && self.check_special_group(&INLINE_SPECIAL_CHARS_SECOND))
|| (count > 0 && self.check_special_group(&self.subtext_break_at))
{
break;
} else if !self.check_special(&SPECIAL_ESCAPE) {
characters.push(current_char)
}
if let Some(character) = self.next_char() {
current_char = character;
} else {
break;
}
count += 1;
}
if characters.len() > 0 {
Ok(PlainText { value: characters })
} else {
Err(ParseError::new(self.index))
}
}
} }

@ -8,15 +8,15 @@ macro_rules! block {
} }
#[allow(unused)] #[allow(unused)]
macro_rules! inline { macro_rules! line {
($inner:expr) => { ($inner:expr) => {
Element::Inline(Box::new($inner)) Element::Line(Box::new($inner))
}; };
} }
macro_rules! subtext { macro_rules! inline {
($inner:expr) => { ($inner:expr) => {
Element::SubText(Box::new($inner)) Element::Inline(Box::new($inner))
}; };
} }
@ -36,13 +36,13 @@ impl ProcessPlaceholders for Document {
let mut pholder = p.lock().unwrap(); let mut pholder = p.lock().unwrap();
match pholder.name.to_ascii_lowercase().as_str() { match pholder.name.to_ascii_lowercase().as_str() {
P_TOC => pholder.set_value(block!(Block::List(self.create_toc()))), P_TOC => pholder.set_value(block!(Block::List(self.create_toc()))),
P_DATE => pholder.set_value(subtext!(SubText::Plain(PlainText { P_DATE => pholder.set_value(inline!(Inline::Plain(PlainText {
value: get_date_string() value: get_date_string()
}))), }))),
P_TIME => pholder.set_value(subtext!(SubText::Plain(PlainText { P_TIME => pholder.set_value(inline!(Inline::Plain(PlainText {
value: get_time_string() value: get_time_string()
}))), }))),
P_DATETIME => pholder.set_value(subtext!(SubText::Plain(PlainText { P_DATETIME => pholder.set_value(inline!(Inline::Plain(PlainText {
value: format!("{} {}", get_date_string(), get_time_string()) value: format!("{} {}", get_date_string(), get_time_string())
}))), }))),
_ => {} _ => {}

@ -0,0 +1,178 @@
use super::charstate::CharStateMachine;
use super::elements::*;
use super::parser::ParseError;
use super::tokens::*;
use crate::Parser;
pub(crate) trait ParseInline {
fn parse_inline(&mut self) -> Result<Inline, ParseError>;
fn parse_image(&mut self) -> Result<Image, ParseError>;
fn parse_url(&mut self, short_syntax: bool) -> Result<Url, ParseError>;
fn parse_bold(&mut self) -> Result<BoldText, ParseError>;
fn parse_italic(&mut self) -> Result<ItalicText, ParseError>;
fn parse_striked(&mut self) -> Result<StrikedText, ParseError>;
fn parse_monospace(&mut self) -> Result<MonospaceText, ParseError>;
fn parse_underlined(&mut self) -> Result<UnderlinedText, ParseError>;
fn parse_plain(&mut self) -> Result<PlainText, ParseError>;
fn parse_surrounded(&mut self, surrounding: &char) -> Result<Inline, ParseError>;
}
impl ParseInline for Parser {
/// parses Inline, the formatting parts of a line (Text)
fn parse_inline(&mut self) -> Result<Inline, ParseError> {
if self.check_special(&PIPE) || self.check_linebreak() {
Err(ParseError::new(self.index))
} else if let Ok(image) = self.parse_image() {
Ok(Inline::Image(image))
} else if let Ok(url) = self.parse_url(false) {
Ok(Inline::Url(url))
} else if let Ok(pholder) = self.parse_placeholder() {
Ok(Inline::Placeholder(pholder))
} else if let Ok(bold) = self.parse_bold() {
Ok(Inline::Bold(bold))
} else if let Ok(italic) = self.parse_italic() {
Ok(Inline::Italic(italic))
} else if let Ok(under) = self.parse_underlined() {
Ok(Inline::Underlined(under))
} else if let Ok(mono) = self.parse_monospace() {
Ok(Inline::Monospace(mono))
} else if let Ok(striked) = self.parse_striked() {
Ok(Inline::Striked(striked))
} else {
Ok(Inline::Plain(self.parse_plain()?))
}
}
/// parses an image url
fn parse_image(&mut self) -> Result<Image, ParseError> {
let start_index = self.index;
self.seek_inline_whitespace();
self.assert_special(&IMG_START, start_index)?;
self.skip_char();
if let Ok(url) = self.parse_url(true) {
let metadata = if let Ok(meta) = self.parse_inline_metadata() {
Some(meta)
} else {
None
};
Ok(Image { url, metadata })
} else {
Err(self.revert_with_error(start_index))
}
}
// parses an url
fn parse_url(&mut self, short_syntax: bool) -> Result<Url, ParseError> {
let start_index = self.index;
self.seek_inline_whitespace();
let mut description = String::new();
if self.check_special(&DESC_OPEN) {
self.skip_char();
description = if let Ok(desc) = self.get_string_until(&[DESC_CLOSE], &[LB]) {
desc
} else {
return Err(self.revert_with_error(start_index));
};
} else if !short_syntax {
return Err(self.revert_with_error(start_index));
}
self.skip_char();
self.assert_special(&URL_OPEN, start_index)?;
self.skip_char();
self.seek_inline_whitespace();
let url = if let Ok(url_str) = self.get_string_until(&[URL_CLOSE], &[LB]) {
url_str
} else {
return Err(self.revert_with_error(start_index));
};
self.skip_char();
if description.is_empty() {
Ok(Url::new(None, url))
} else {
Ok(Url::new(Some(description), url))
}
}
/// parses bold text with must start with two asterisks
fn parse_bold(&mut self) -> Result<BoldText, ParseError> {
let start_index = self.index;
self.assert_special_sequence(&BOLD, start_index)?;
self.skip_char();
let inline = self.parse_inline()?;
self.assert_special_sequence(&BOLD, start_index)?;
self.skip_char();
Ok(BoldText {
value: Box::new(inline),
})
}
fn parse_italic(&mut self) -> Result<ItalicText, ParseError> {
Ok(ItalicText {
value: Box::new(self.parse_surrounded(&ITALIC)?),
})
}
fn parse_striked(&mut self) -> Result<StrikedText, ParseError> {
Ok(StrikedText {
value: Box::new(self.parse_surrounded(&STRIKED)?),
})
}
/// parses monospace text (inline-code) that isn't allowed to contain special characters
fn parse_monospace(&mut self) -> Result<MonospaceText, ParseError> {
let start_index = self.index;
self.assert_special(&BACKTICK, start_index)?;
self.skip_char();
let content = self.get_string_until(&[BACKTICK, LB], &[])?;
self.assert_special(&BACKTICK, start_index)?;
self.skip_char();
Ok(MonospaceText { value: content })
}
fn parse_underlined(&mut self) -> Result<UnderlinedText, ParseError> {
Ok(UnderlinedText {
value: Box::new(self.parse_surrounded(&UNDERLINED)?),
})
}
/// parses plain text as a string until it encounters an unescaped special inline char
fn parse_plain(&mut self) -> Result<PlainText, ParseError> {
if self.check_linebreak() {
return Err(ParseError::new(self.index));
}
let mut characters = String::new();
characters.push(self.current_char);
while let Some(ch) = self.next_char() {
if self.check_special_group(&INLINE_SPECIAL_CHARS)
|| self.check_special_group(&self.inline_break_at)
{
break;
}
characters.push(ch)
}
if characters.len() > 0 {
Ok(PlainText { value: characters })
} else {
Err(ParseError::new(self.index))
}
}
/// parses Inline surrounded by characters
fn parse_surrounded(&mut self, surrounding: &char) -> Result<Inline, ParseError> {
let start_index = self.index;
self.assert_special(surrounding, start_index)?;
self.skip_char();
let inline = self.parse_inline()?;
self.assert_special(surrounding, start_index)?;
self.skip_char();
Ok(inline)
}
}

@ -42,6 +42,12 @@ pub(crate) const IMPORT_CLOSE: char = L_BRACKET;
pub(crate) const PHOLDER_OPEN: char = R_BRACKET; pub(crate) const PHOLDER_OPEN: char = R_BRACKET;
pub(crate) const PHOLDER_CLOSE: char = L_BRACKET; pub(crate) const PHOLDER_CLOSE: char = L_BRACKET;
pub(crate) const ITALIC: char = ASTERISK;
pub(crate) const MONOSPACE: char = BACKTICK;
pub(crate) const STRIKED: char = TILDE;
pub(crate) const UNDERLINED: char = UNDERSCR;
pub(crate) const BOLD: [char; 2] = [ASTERISK, ASTERISK];
// groups // groups
pub(crate) const QUOTES: [char; 2] = [SINGLE_QUOTE, DOUBLE_QUOTE]; pub(crate) const QUOTES: [char; 2] = [SINGLE_QUOTE, DOUBLE_QUOTE];
@ -57,8 +63,9 @@ pub(crate) const BLOCK_SPECIAL_CHARS: [&[char]; 8] = [
&[IMPORT_START, IMPORT_OPEN], &[IMPORT_START, IMPORT_OPEN],
]; ];
pub(crate) const INLINE_SPECIAL_CHARS: [char; 5] = [LB, ASTERISK, UNDERSCR, TILDE, BACKTICK]; pub(crate) const INLINE_SPECIAL_CHARS: [char; 8] = [
pub(crate) const INLINE_SPECIAL_CHARS_SECOND: [char; 3] = [DESC_OPEN, IMG_START, URL_OPEN]; BACKTICK, TILDE, UNDERSCR, ASTERISK, DESC_OPEN, IMG_START, URL_OPEN, LB,
];
pub(crate) const LIST_SPECIAL_CHARS: [char; 14] = [ pub(crate) const LIST_SPECIAL_CHARS: [char; 14] = [
MINUS, PLUS, ASTERISK, O, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', MINUS, PLUS, ASTERISK, O, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0',

Loading…
Cancel
Save