From d0ff550b264206109349f0385c145f340ddf992b Mon Sep 17 00:00:00 2001 From: Ben Bridle Date: Sun, 19 Jan 2025 18:49:36 +1300 Subject: Change syntax Internal links are now delimited with braces, and external links are now delimited with angle brackets. A label is separated from a path in an external link with two consecutive colons. Embed blocks are now delimited with angle brackets in the same manner as external links, with label separated from path with two consecutive colons. Embed blocks still begin with a single exclamation mark. Bold line elements are now delimited with only a single * character, instead of two. This is to match the other delimiters, which each use only a single character. --- src/block.rs | 2 +- src/lib.rs | 31 ++++++++++++++----------------- src/line.rs | 36 ++++++++++++++++-------------------- src/token.rs | 7 +++++-- 4 files changed, 36 insertions(+), 40 deletions(-) (limited to 'src') diff --git a/src/block.rs b/src/block.rs index a11d356..1d6ac60 100644 --- a/src/block.rs +++ b/src/block.rs @@ -15,6 +15,6 @@ pub enum Block { Note(Vec), Table(Table), Break, - Embedded { label: String, path: String }, + Embed { label: String, path: String }, Fragment { language: String, content: String }, } diff --git a/src/lib.rs b/src/lib.rs index f5a1207..e75221c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -108,8 +108,8 @@ impl MarkdownDocument { Block::Heading { level, line: Line::from_str(&line) }), BlockLine::Break => blocks.push(Block::Break), BlockLine::BlankLine => (), - BlockLine::Paragraph(line) => match parse_embedded(&line) { - Some(embedded) => blocks.push(embedded), + BlockLine::Paragraph(line) => match parse_embed(&line) { + Some(embed) => blocks.push(embed), None => blocks.push(Block::Paragraph(Line::from_str(&line))), } } @@ -139,24 +139,21 @@ enum BlockMultiline<'a> { Fragment { language: &'a str, content: Vec<&'a str> }, } -fn parse_embedded(line: &str) -> Option { +fn parse_embed(line: &str) -> Option { let line = line.trim(); - if let Some(("", line)) = line.split_once("![") { - if let Some((line, "")) = line.rsplit_once(")") { - let parts: Vec<&str> = line.split("](").collect(); - if parts.len() == 2 { - let label = parts[0].to_string(); - let path = parts[1].to_string(); - return Some(Block::Embedded { label, path }) + if let Some(stripped) = line.strip_prefix("!<") { + if let Some(stripped) = stripped.strip_suffix(">") { + if let Some((label, path)) = stripped.split_once("::") { + let label = label.trim().to_string(); + let path = path.trim().to_string(); + return Some(Block::Embed { label, path }) + } else { + let label = String::new(); + let path = stripped.trim().to_string(); + return Some(Block::Embed { label, path }) } } } - if let Some(("", line)) = line.split_once("![[") { - if let Some((line, "")) = line.rsplit_once("]]") { - let label = line.to_string(); - let path = line.to_string(); - return Some(Block::Embedded { label, path }) - } - } return None; } + diff --git a/src/line.rs b/src/line.rs index fce628c..b60b55c 100644 --- a/src/line.rs +++ b/src/line.rs @@ -82,31 +82,27 @@ impl ToString for Line { } -fn unlabeled_extern_link(path: String) -> Option { - Some( Token::ExternalLink { path, label:String::new() } ) -} - -fn labelled_extern_link(s: String) -> Option { - let (label, path) = match s.split_once("](") { - Some((l, t)) => (l.to_string(), t.to_string()), - None => return None, - }; - if label.contains("]") || path.contains("]") { return None } - Some( Token::ExternalLink { label, path } ) +fn external_link(inside: String) -> Option { + if let Some((label, path)) = inside.split_once("::") { + let label = label.trim().to_string(); + let path = path.trim().to_string(); + Some( Token::ExternalLink { label, path } ) + } else { + Some( Token::ExternalLink { label: String::new(), path: inside }) + } } -macro_rules! con { +macro_rules! make { ($v:expr) => {|s| Some($v(s)) }; } -const DELIMITERS: [(fn(String)->Option, &str, &str, &str); 7] = [ - ( con!(Token::Bold), "**", "**", "*" ), - ( con!(Token::Italic), "_", "_", "_" ), - ( con!(Token::Monospace), "`", "`", "`" ), - ( con!(Token::Math), "$", "$", "$" ), - ( con!(Token::InternalLink), "[[", "]]", "[]" ), - ( labelled_extern_link, "[", ")", "[]()" ), - ( unlabeled_extern_link, "<", ">", "<>" ), +const DELIMITERS: [(fn(String)->Option, &str, &str, &str); 6] = [ + ( make!(Token::Bold), "*", "*", "*" ), + ( make!(Token::Italic), "_", "_", "_" ), + ( make!(Token::Monospace), "`", "`", "`" ), + ( make!(Token::Math), "$", "$", "$" ), + ( make!(Token::InternalLink), "{", "}", "{}" ), + ( external_link, "<", ">", "<>" ), ]; fn is_whitespace(c: &char) -> bool { diff --git a/src/token.rs b/src/token.rs index c2b1179..f1f8288 100644 --- a/src/token.rs +++ b/src/token.rs @@ -17,8 +17,11 @@ impl AsRef for Token { Token::Italic(text) => text, Token::Monospace(text) => text, Token::Math(text) => text, - Token::InternalLink(label) => label, - Token::ExternalLink { label, ..} => label, + Token::InternalLink(name) => name, + Token::ExternalLink { label, path } => match !label.is_empty() { + true => label, + false => path, + }, } } } -- cgit v1.2.3-70-g09d2