From 40c4bb30c16f52fd9ec4944482dbbb929386ab78 Mon Sep 17 00:00:00 2001 From: Qrius Date: Thu, 26 Sep 2024 00:11:05 +0200 Subject: Fix a bunch of things, add diferent syntax for strings --- src/macro_processor/error.rs | 8 ++++ src/macro_processor/macro_processor.rs | 88 +++++++++++++++++++++++++++------- 2 files changed, 80 insertions(+), 16 deletions(-) (limited to 'src/macro_processor') diff --git a/src/macro_processor/error.rs b/src/macro_processor/error.rs index cd94c4d..7661156 100644 --- a/src/macro_processor/error.rs +++ b/src/macro_processor/error.rs @@ -5,6 +5,7 @@ use std::fmt; pub enum SMPError { IncludeError(u8, std::io::Error, String), ShellCommandError(u8, Box), + MarkdownError(u8, markdown::message::Message), UnknownError(u8, Option>), } @@ -17,6 +18,13 @@ impl fmt::Display for SMPError { SMPError::ShellCommandError(code, e) => { write!(f, "[SMP{}] Error running shell command \"{:#?}\"", code, e) } + SMPError::MarkdownError(code, message) => { + write!( + f, + "[SMP{}] Error converting markdown \"{:#?}\"", + code, message + ) + } SMPError::UnknownError(code, e) => { write!( f, diff --git a/src/macro_processor/macro_processor.rs b/src/macro_processor/macro_processor.rs index ee7e269..ba28b15 100644 --- a/src/macro_processor/macro_processor.rs +++ b/src/macro_processor/macro_processor.rs @@ -443,6 +443,36 @@ fn smp_builtin_format_time( Ok(format!("{}", dt.format(&args[0]))) } +fn smp_builtin_html_from_markdown( + smp: &mut MacroProcessor, + macro_name: &str, + args: &mut [String], +) -> Result { + if args.len() < 1 { + smp.warnings + .push(MacroProcessorWarning::from_macro_invocation( + macro_name, + args, + format!("Wrong number of arguments, expected 1"), + )); + return Ok(macro_name.to_string()); + } + let content = smp.process_input(&args[0])?; + let content = smp.process_input(&content)?; + markdown::to_html_with_options( + &content, + &markdown::Options { + parse: markdown::ParseOptions::gfm(), + compile: markdown::CompileOptions { + allow_dangerous_html: true, + allow_dangerous_protocol: true, + ..markdown::CompileOptions::default() + }, + }, + ) + .map_err(|e| SMPError::MarkdownError(15, e)) +} + fn macro_is_whitespace_deleting(s: &str) -> bool { s.chars().nth(s.len() - 1) == Some('_') } @@ -607,6 +637,11 @@ impl MacroProcessor { String::from("format_time"), MacroType::Function(smp_builtin_format_time), ); + #[cfg(feature = "markdown")] + self.define_macro( + String::from("html_from_markdown"), + MacroType::Function(smp_builtin_html_from_markdown), + ); #[cfg(feature = "webring")] self.define_macro( String::from("webring_rss"), @@ -687,9 +722,6 @@ impl MacroProcessor { match macro_body { MacroType::String(body) => { let mut expanded = body.clone(); - // The expanded macro, should _probably_ be expanded again - // The below is a okay _idea_, but I am not sure if I want to have this syntax for - // functions defined in normal smp code for (i, arg) in args.iter().enumerate() { let placeholder = format!("${}", i); expanded = expanded.replace(&placeholder, arg); @@ -724,16 +756,22 @@ impl MacroProcessor { let mut skip_next_line_ending = false; - let mut in_quote_single = false; - let mut in_quote_double = false; + //let mut current_indent = 0; + //let mut line_text_seen = false; + + // We should keep track of filename, linenumber, and character number on line here + // So we can give sensible error messages - const QUOTE_START: char = '`'; - const QUOTE_END: char = '\''; let mut quote_level = 0; let mut parens_level = 0; - for (i, c) in input.char_indices() { + let mut chars = input.char_indices().peekable(); + while let Some((i, c)) = chars.next() { highlight_debug!(input, macro_name_start, i); + let peek = match chars.peek() { + Some((_, c)) => Some(c), + None => None, + }; match state { ParserState::DNL => { @@ -749,28 +787,31 @@ impl MacroProcessor { continue; } - if c.is_alphanumeric() { - state = ParserState::InMacro; - macro_name.push(c); - } else if c == QUOTE_START { + if c == '%' && peek == Some(&'"') { state = ParserState::InQuotes; quote_level += 1; + chars.next(); + } else if c.is_alphanumeric() { + state = ParserState::InMacro; + macro_name.push(c); } else { output.push(c); } } ParserState::InQuotes => match c { - QUOTE_START => { + '%' if peek == Some(&'"') => { quote_level += 1; - output.push(c); + chars.next(); + output.push_str(r#"%""#); } - QUOTE_END => { + '"' if peek == Some(&'%') => { quote_level -= 1; if quote_level == 0 { state = ParserState::Normal; } else { - output.push(c); + output.push_str(r#""%"#); } + chars.next(); } _ => { output.push(c); @@ -810,6 +851,21 @@ impl MacroProcessor { } } ParserState::InMacroArgs => { + if c == '%' && peek == Some(&'"') { + quote_level += 1; + chars.next(); + argument.push_str(r#"%""#); + continue; + } else if c == '"' && peek == Some(&'%') { + quote_level -= 1; + chars.next(); + argument.push_str(r#""%"#); + continue; + } else if quote_level > 0 { + argument.push(c); + continue; + } + if (c == ')') && (parens_level == 1) { if macro_is_whitespace_deleting(¯o_name) { if output.chars().last() == Some(' ') { -- cgit v1.2.3