use crate::consts::*;
use crate::markdown::icon::get_icon;
use crate::markdown::line::{Line, LineType};
use crate::markdown::colors::COLOR_NAMES;
use crate::utils::*;
use std::str::FromStr;
pub fn render_independent_tag(lines: &Vec<Line>) -> Vec<Line> {
let mut result = Vec::with_capacity(lines.len());
for ln in lines.iter() {
if ln.line_type == LineType::Tag {
let mut new_line = ln.clone();
match parse_tag(&ln.content, 0) {
Err(_) => {new_line.line_type = LineType::Paragraph;}
Ok(c) => {new_line.content = c;}
}
result.push(new_line);
}
else {
result.push(ln.clone());
}
}
result
}
pub fn render_tag(content: &Vec<u16>) -> Vec<u16> {
let mut result = vec![];
let mut curr_index = 0;
let mut last_index = 0;
while curr_index < content.len() {
if is_tag(content, curr_index) {
let tag = parse_tag(content, curr_index);
if tag.is_ok() {
result.push(content[last_index..curr_index].to_vec());
result.push(tag.unwrap());
last_index = get_bracket_end_index(content, curr_index).unwrap() + 1;
curr_index = last_index;
continue;
}
}
curr_index += 1;
}
if last_index < curr_index {
result.push(content[last_index..].to_vec());
}
result.concat()
}
pub fn is_tag(content: &[u16], index: usize) -> bool {
content[index] == U16_LEFT_SQUARE_BRACKET && index + 1 < content.len() && content[index + 1] == U16_LEFT_SQUARE_BRACKET && {
let end1 = match get_bracket_end_index(content, index) {
None => {return false;}
Some(i) => i
};
let end2 = match get_bracket_end_index(content, index + 1) {
None => {return false;}
Some(i) => i
};
end2 + 1 == end1
}
}
fn parse_tag(content: &Vec<u16>, index: usize) -> Result<Vec<u16>, ()> {
let end_index = get_bracket_end_index(content, index + 1).unwrap();
let content = lowercase_and_remove_spaces(&content[index + 2..end_index]);
if content.len() == 0 {
return Err(());
}
if is_color_name(&content) {
return Ok(vec![
into_v16("<span class=\"color_"),
content,
into_v16("\">")
].concat());
}
if is_size_name(&content) {
return Ok(vec![
into_v16("<span class=\"size_"),
content,
into_v16("\">")
].concat());
}
if is_alignment_name(&content) {
return Ok(vec![
into_v16("<div class=\"align_"),
content,
into_v16("\">")
].concat());
}
if is_box_name(&content) {
return Ok(into_v16("<div class=\"box\">"));
}
if is_blank_name(&content) {
return Ok(into_v16(" "));
}
if is_icon(&content) {
match parse_icon(&content) {
Some(s) => {return Ok(s);}
_ => {}
}
}
if is_char(&content) {
match parse_char(&content) {
Some(s) => {return Ok(s);}
_ => {}
}
}
if content[0] == U16_SLASH {
if is_color_name(&content[1..]) || is_size_name(&content[1..]) {
return Ok(into_v16("</span>"));
}
if is_alignment_name(&content[1..]) || is_box_name(&content[1..]) {
return Ok(into_v16("</div>"));
}
}
Err(())
}
fn is_color_name(string: &[u16]) -> bool {
COLOR_NAMES.contains(&string.to_vec())
}
fn is_size_name(string: &[u16]) -> bool {
string == &into_v16("giant") ||
string == &into_v16("big") ||
string == &into_v16("small") ||
string == &into_v16("medium")
}
fn is_alignment_name(string: &[u16]) -> bool {
string == &into_v16("left") ||
string == &into_v16("right") ||
string == &into_v16("center")
}
fn is_box_name(string: &[u16]) -> bool {
string.len() == 3 && string[0] == U16_SMALL_B && string[1] == U16_SMALL_O && string[2] == U16_SMALL_X
}
fn is_blank_name(string: &[u16]) -> bool {
string.len() == 5 && string[0] == U16_SMALL_B && string[1] == U16_SMALL_L && string[2] == U16_SMALL_A && string[3] == U16_SMALL_N && string[4] == U16_SMALL_K
}
fn is_icon(string: &[u16]) -> bool {
string.len() > 5 && string[0] == U16_SMALL_I && string[1] == U16_SMALL_C && string[2] == U16_SMALL_O && string[3] == U16_SMALL_N && string[4] == U16_EQUAL
}
fn parse_icon(content: &[u16]) -> Option<Vec<u16>> {
let mut curr_icon = None;
let mut curr_size = None;
let args = parse_arguments(content);
for (key, value) in args.iter() {
if key == &into_v16("icon") {
curr_icon = Some(value.clone());
}
else if key == &into_v16("size") {
curr_size = Some(value.clone());
}
else {
return None;
}
}
let curr_icon = if curr_icon.is_none() {
return None
} else {
curr_icon.unwrap()
};
let curr_size = if curr_size.is_none() {
24
} else {
match usize::from_str(&String::from_utf16_lossy(&curr_size.unwrap())) {
Err(_) => {return None}
Ok(n) => n
}
};
get_icon(&curr_icon, curr_size, None, false)
}
fn is_char(string: &[u16]) -> bool {
string.len() > 5 && string[0] == U16_SMALL_C && string[1] == U16_SMALL_H && string[2] == U16_SMALL_A && string[3] == U16_SMALL_R && string[4] == U16_EQUAL
}
fn parse_char(content: &[u16]) -> Option<Vec<u16>> {
let args = parse_arguments(content);
if args.len() != 1 {
return None;
}
let num = &args[0].1;
match u16::from_str(&String::from_utf16_lossy(num)) {
Err(_) => None,
Ok(n) => Some(into_v16(&format!("&#{};", n) ))
}
}
fn parse_arguments(content: &[u16]) -> Vec<(Vec<u16>, Vec<u16>)> { content.split(
|c|
*c == U16_COMMA
).filter_map(
|arg| {
let arg_split = arg.split(
|c|
*c == U16_EQUAL
).map(
|word|
word.to_vec()
).collect::<Vec<Vec<u16>>>();
if arg_split.len() == 2 {
Some((arg_split[0].clone(), arg_split[1].clone()))
} else {
None
}
}
).collect()
}