text_to_ascii_art/
lib.rs

1pub mod fonts;
2use fonts::get_font;
3
4// You need to specially concat ascii art because of how line brakes work,
5// otherwise you would have just
6// everything vertically
7pub fn join_art(s1: &str, s2: &str, gap: usize) -> String {
8    // handles edge cases, with simple match
9    match (s1.is_empty(), s2.is_empty()) {
10        (true, true) => "".to_string(),
11        (true, false) => s2.to_string(),
12        (false, true) => s1.to_string(),
13        (false, false) => {
14            // case when both string are something
15            // each line has to have the same amount of characters, or other art will be shifted
16            // TODO: handle each line with different amount of characters
17
18            // you get all lines of the &str
19            let lines1: Vec<&str> = s1.split('\n').collect();
20            let lines2: Vec<&str> = s2.split('\n').collect();
21
22            // concat each line of the 2 ascii arts
23            let s3: Vec<String> = lines1
24                .into_iter()
25                .zip(lines2)
26                .map(|(str1, str2)| str1.to_owned() + &" ".repeat(gap) + str2)
27                .collect();
28
29            s3.join("\n")
30        }
31    }
32}
33
34fn add_spaces(art: &str, leading: usize, trailing: usize) -> String {
35    let lines: Vec<&str> = art.split('\n').collect();
36
37    let spaces_added: Vec<String> = lines
38        .into_iter()
39        .map(|line| " ".repeat(leading).to_owned() + line + &" ".repeat(trailing))
40        .collect();
41
42    spaces_added.join("\n")
43}
44
45fn align_center(art: &str, width: usize) -> String {
46    let art_length: usize = get_art_length(art);
47    let spaces = (width - art_length) / 2;
48
49    add_spaces(art, spaces, spaces)
50}
51
52fn align_left(art: &str, width: usize) -> String {
53    let art_length: usize = get_art_length(art);
54    let spaces = width - art_length;
55
56    add_spaces(art, 0, spaces)
57}
58
59fn align_right(art: &str, width: usize) -> String {
60    let art_length: usize = get_art_length(art);
61    let spaces = width - art_length;
62
63    add_spaces(art, spaces, 0)
64}
65
66fn get_art_length(art: &str) -> usize {
67    let lines: Vec<&str> = art.split('\n').collect();
68    lines[0].len()
69}
70
71pub enum Alignment {
72    Left,
73    Center,
74    Right,
75}
76
77pub fn align(art: &str, alignment: Alignment, width: usize) -> String {
78    match alignment {
79        Alignment::Left => align_left(art, width),
80        Alignment::Center => align_center(art, width),
81        Alignment::Right => align_right(art, width),
82    }
83}
84
85pub fn to_art(
86    input: String,
87    font: &str,
88    leading: usize,
89    gap: usize,
90    trailing: usize,
91) -> Result<String, String> {
92    // substitutes everything with the equivalent in ascii art, or an empty string instead
93    let arts = input
94        .chars()
95        .map(|ch| get_font(font).get(ch as usize).unwrap_or(&"").to_owned())
96        .collect::<Vec<&str>>();
97
98    // function to go through all the entered characters
99    let mut final_string = "".to_string();
100    let mut bad_char = false;
101    for art in &arts {
102        if art.is_empty() && !bad_char {
103            bad_char = true
104        }
105    }
106    // happens if you pass unhandled characters
107    if bad_char {
108        Err("Error: Some not allowed characters, you can use: a..=Z, 0..=9 ,`; : . , < > ( ) ! * # @ ^`".to_string())
109    } else {
110        for art in arts {
111            final_string = join_art(&final_string, art, gap);
112        }
113
114        Ok(add_spaces(&final_string, leading, trailing))
115    }
116}