summaryrefslogtreecommitdiff
path: root/src/macro_processor/macro_processor.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/macro_processor/macro_processor.rs')
-rw-r--r--src/macro_processor/macro_processor.rs88
1 files changed, 72 insertions, 16 deletions
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<String, SMPError> {
+ 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(&macro_name) {
if output.chars().last() == Some(' ') {