Add Image parsing

Images have the syntax ![description](url)[metadata]
with [description] and [metadata] being optional.
So the shortest syntax is !(url).
Similar to the short url syntax (url)
pull/1/head
trivernis 5 years ago
parent f532865fc6
commit 8896ea27b3

@ -106,6 +106,7 @@ pub enum SubText {
Striked(StrikedText), Striked(StrikedText),
Monospace(MonospaceText), Monospace(MonospaceText),
Url(Url), Url(Url),
Image(Image),
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -146,7 +147,8 @@ pub struct Url {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Image { pub struct Image {
url: Url, pub(crate) url: Url,
pub(crate) metadata: Option<InlineMetadata>,
} }
// implementations // implementations

@ -339,7 +339,6 @@ impl Parser {
while let Ok(token) = self.parse_inline() { while let Ok(token) = self.parse_inline() {
paragraph.add_element(token); paragraph.add_element(token);
let start_index = self.index; let start_index = self.index;
self.seek_inline_whitespace();
if self.check_special_group(&BLOCK_SPECIAL_CHARS) { if self.check_special_group(&BLOCK_SPECIAL_CHARS) {
self.revert_to(start_index)?; self.revert_to(start_index)?;
break; break;
@ -441,6 +440,7 @@ impl Parser {
Ok(item) Ok(item)
} }
/// parses a markdown table
fn parse_table(&mut self) -> Result<Table, ParseError> { fn parse_table(&mut self) -> Result<Table, ParseError> {
let header = self.parse_row()?; let header = self.parse_row()?;
let start_index = self.index; let start_index = self.index;
@ -531,6 +531,9 @@ impl Parser {
if self.check_linebreak() { if self.check_linebreak() {
return Err(ParseError::new(self.index)); 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() { if let Ok(url) = self.parse_url() {
return Ok(SubText::Url(url)); return Ok(SubText::Url(url));
} }
@ -589,40 +592,61 @@ impl Parser {
} }
} }
/// parses an image url
fn parse_image(&mut self) -> Result<Image, ParseError> {
let start_index = self.index;
self.seek_inline_whitespace();
if !self.check_special(&IMG_START) || self.next_char() == None {
return Err(self.revert_with_error(start_index));
}
if let Ok(url) = self.parse_url() {
let metadata = if let Ok(meta) = self.parse_inline_metadata() {
if self.check_special(&META_CLOSE) && self.next_char() == None {
return Err(self.revert_with_error(start_index));
}
Some(meta)
} else {
None
};
Ok(Image { url, metadata })
} else {
Err(self.revert_with_error(start_index))
}
}
// parses an url // parses an url
fn parse_url(&mut self) -> Result<Url, ParseError> { fn parse_url(&mut self) -> Result<Url, ParseError> {
let start_index = self.index; let start_index = self.index;
self.seek_inline_whitespace(); self.seek_inline_whitespace();
let mut description = String::new(); let mut description = String::new();
if self.check_special(&R_BRACKET) { if self.check_special(&DESC_OPEN) {
while let Some(character) = self.next_char() { while let Some(character) = self.next_char() {
if self.check_special(&L_BRACKET) || self.check_linebreak() { if self.check_special(&DESC_CLOSE) || self.check_linebreak() {
break; break;
} }
description.push(character); description.push(character);
} }
if !self.check_special(&L_BRACKET) { if !self.check_special(&DESC_CLOSE) || self.next_char() == None {
// it stopped at a linebreak or EOF // it stopped at a linebreak or EOF
return Err(self.revert_with_error(start_index)); return Err(self.revert_with_error(start_index));
} }
} }
if let Some(_) = self.next_char() { if !self.check_special(&URL_OPEN) {
if !self.check_special(&R_PARENTH) { // the next char isn't the start of the encased url
// the next char isn't the start of the encased url return Err(self.revert_with_error(start_index));
return Err(self.revert_with_error(start_index));
}
} }
self.seek_inline_whitespace(); self.seek_inline_whitespace();
let mut url = String::new(); let mut url = String::new();
while let Some(character) = self.next_char() { while let Some(character) = self.next_char() {
if self.check_special(&L_PARENTH) || self.check_linebreak() { if self.check_special(&URL_CLOSE) || self.check_linebreak() {
break; break;
} }
url.push(character); url.push(character);
} }
if !self.check_special(&L_PARENTH) || url.is_empty() { if !self.check_special(&URL_CLOSE) || url.is_empty() {
return Err(self.revert_with_error(start_index)); return Err(self.revert_with_error(start_index));
} }
parse_option!(self.next_char(), self.index); parse_option!(self.next_char(), self.index);
@ -645,7 +669,7 @@ impl Parser {
let mut count = 0; let mut count = 0;
loop { loop {
if self.check_special_group(&INLINE_SPECIAL_CHARS) if self.check_special_group(&INLINE_SPECIAL_CHARS)
|| (count > 0 && self.check_special(&R_BRACKET)) || (count > 0 && self.check_special_group(&INLINE_SPECIAL_CHARS_SECOND))
{ {
break; break;
} else { } else {

@ -17,6 +17,7 @@ pub(crate) const HASH: char = '#';
pub(crate) const O: char = 'o'; pub(crate) const O: char = 'o';
pub(crate) const X: char = 'x'; pub(crate) const X: char = 'x';
pub(crate) const GT: char = '>'; pub(crate) const GT: char = '>';
pub(crate) const BANG: char = '!';
// aliases // aliases
@ -26,12 +27,16 @@ pub(crate) const META_CLOSE: char = L_BRACKET;
pub(crate) const QUOTE_START: char = GT; pub(crate) const QUOTE_START: char = GT;
pub(crate) const DESC_OPEN: char = R_BRACKET; pub(crate) const DESC_OPEN: char = R_BRACKET;
pub(crate) const DESC_CLOSE: char = L_BRACKET; pub(crate) const DESC_CLOSE: char = L_BRACKET;
pub(crate) const IMG_START: char = BANG;
pub(crate) const URL_OPEN: char = R_PARENTH;
pub(crate) const URL_CLOSE: char = L_PARENTH;
// groups // groups
pub(crate) const BLOCK_SPECIAL_CHARS: [char; 6] = pub(crate) const BLOCK_SPECIAL_CHARS: [char; 6] =
[HASH, MINUS, BACKTICK, PIPE, QUOTE_START, META_OPEN]; [HASH, MINUS, BACKTICK, PIPE, QUOTE_START, META_OPEN];
pub(crate) const INLINE_SPECIAL_CHARS: [char; 6] = [LB, ASTERISK, UNDERSCR, TILDE, PIPE, BACKTICK]; pub(crate) const INLINE_SPECIAL_CHARS: [char; 6] = [LB, ASTERISK, UNDERSCR, TILDE, PIPE, BACKTICK];
pub(crate) const INLINE_SPECIAL_CHARS_SECOND: [char; 3] = [DESC_OPEN, IMG_START, URL_OPEN];
pub(crate) const LIST_SPECIAL_CHARS: [char; 4] = [MINUS, PLUS, ASTERISK, O]; pub(crate) const LIST_SPECIAL_CHARS: [char; 4] = [MINUS, PLUS, ASTERISK, O];
@ -41,4 +46,5 @@ pub(crate) const SQ_CODE_BLOCK: [char; 3] = [BACKTICK, BACKTICK, BACKTICK];
// expressions // expressions
pub(crate) const EXPR_URI: &str = r"^(https?://)?\w+\.\w+(.\w+)?$|^([\w, -.]+|\w:)?(/[\w, -.]+)+$"; pub(crate) const EXPR_URI: &str =
r"^(https?://)?\w+\.\w+(\.\w+|)?(/[\w, -.%&]+)*/?$|^([\w, -.]+|\w:)?(/[\w, -.]+)+$";

Loading…
Cancel
Save