use pyo3::prelude::*; use crate::parser::parse_with_limits; const DUAL_TAGS: &[(&'static str, (&'static str, &'static str))] = &[ ("_", ("", "")), ("*", ("", "")), ("~", ("", "")), ("`", ("", "")), ("```", ("
", "
")), ("```language", ("
", "
")), (">", ("
", "
")), ("||", ("", "")), ]; const SINGLE_TAGS: &[(&'static str, &'static str)] = &[ (">>", ""), ("```>", ""), ("\\", ""), ("<", "<"), (">", ">"), ]; #[pyfunction] pub fn format_for_matrix(body: String, mentions: Option>) -> PyResult { let mut chars: Vec = body.chars().collect(); if chars.len() < 1 { return Ok(body); } let mentions = mentions.unwrap_or(Vec::with_capacity(0)); let styles: Vec<(String, usize, usize, usize, usize)> = parse_with_limits(&chars, 0, chars.len() - 1, 0); let mut tags: Vec<(usize, String, usize)> = Vec::with_capacity(styles.len() * 2); for (keyword, start, remove_start, end, remove_end) in styles { if DUAL_TAGS.iter().any(|&(k, _)| k == keyword) { let opening_tag = if keyword == "```language" { DUAL_TAGS.iter().find(|&&(k, _)| k == keyword).unwrap().1.0 .replace("{}", &chars[start+3..remove_start-1] .into_iter() .collect::()) } else { DUAL_TAGS.iter().find(|&&(k, _)| k == keyword).unwrap().1.0.to_owned() }; tags.push((start, opening_tag, remove_start)); tags.push((end, DUAL_TAGS.iter().find(|&&(k, _)| k == keyword).unwrap().1.1.to_owned(), remove_end)); } else if SINGLE_TAGS.iter().any(|&(k, _)| k == keyword) { tags.push((start, SINGLE_TAGS.iter().find(|&&(k, _)| k == keyword).unwrap().1.to_owned(), start+1)); } } for (mxid, start, end) in mentions { tags.push((start, "", start)); tags.push((end, "".to_owned(), end)); } tags.sort_by(|a, b| b.0.cmp(&a.0)); let mut replace_newlines_to = chars.len(); for (index, tag, end) in tags { if tag == "" { // index is at \n, add 1 to skip that one let substring = chars[index + 1..replace_newlines_to].into_iter().collect::(); chars = [&chars[..index + 1], &substring.replace('\n', "
").chars().collect::>()[..], &chars[replace_newlines_to..]].concat(); } else if tag.starts_with("
") {
            replace_newlines_to = index;
        }

        let tag: Vec = tag.chars().collect();
        chars = [chars[..index].to_vec(), tag.clone(), chars[end..].to_vec()].concat();
        
        let offset: isize = index as isize - end as isize + tag.len() as isize;
        replace_newlines_to = if offset > 0 {
            replace_newlines_to + offset as usize
        } else {
            replace_newlines_to - offset.abs() as usize
        };
    }
    let substring = chars[..replace_newlines_to].into_iter().collect::();
    let text = [substring.replace('\n', "
"), chars[replace_newlines_to..].into_iter().collect::()].concat(); Ok(text) }