diff options
Diffstat (limited to 'src/macro_processor')
| -rw-r--r-- | src/macro_processor/error.rs | 8 | ||||
| -rw-r--r-- | src/macro_processor/macro_processor.rs | 88 | 
2 files changed, 80 insertions, 16 deletions
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<dyn Error>), +    MarkdownError(u8, markdown::message::Message),      UnknownError(u8, Option<Box<dyn Error>>),  } @@ -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<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(¯o_name) {                              if output.chars().last() == Some(' ') {  | 
