flexar/compile_error/
compile_error_display.rs

1use super::CompileError;
2use std::fmt::{self, Display};
3pub use crate::colour_format;
4
5pub const LINE_LIMIT: u8 = 24;
6
7impl Display for CompileError {
8    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
9        let ln = self.position.0.ln.to_string();
10        let (line, arrw) = if self.position.0.ln == self.position.1.ln {
11            sample(
12                self.position.0.get_ln().unwrap(), // Position should be valid
13                self.position.0.ln_idx,
14                self.position.1.ln_idx,
15                &self.msg,
16                false,
17            )
18        } else {
19            sample(
20                self.position.0.get_ln().unwrap(), // Position should be valid
21                self.position.0.ln_idx,
22                self.position.0.get_ln().unwrap().len() as u16, // Position should be valid
23                &self.msg,
24                true,
25            )
26        };
27
28        let out = colour_format![
29            red("\nerror["), yellow(self.id), red("]: "), none(self.error_type),
30            blue("\n --> "), cyan(&self.position.0.file_name),
31            blue(":"), yellow(&ln), blue(":"), yellow(&self.position.0.ln_idx.to_string()),
32            none("\n"), yellow(&ln), blue(" | "), none(&line),
33            none("\n"), none(&" ".repeat(ln.len())), blue(" | ") red(&arrw),
34            blue("\n <--"),
35        ];
36
37        write!(f, "{}", out)
38    }
39}
40
41fn sample(line: &str, start_idx: u16, end_idx: u16, msg: &str, multi_line: bool) -> (String, String) {
42    let start_trim = cal_trim(start_idx, 0);
43    let end_trim = cal_trim(line.len() as u16, end_idx);
44
45    let mut sample = line[start_trim as usize..line.len() - end_trim as usize].to_string();
46
47    if start_trim != 0 { sample = colour_format![cyan("..."), none(&sample)]; }
48    if end_trim != 0 { sample = colour_format![none(&sample), cyan("...")]; }
49
50    if multi_line { sample = colour_format![none(&sample), cyan("\\n"), red("...")]; }
51
52    (sample, gen_arrw(start_idx, end_idx, msg, start_trim, 5 * multi_line as u16))
53}
54
55#[inline]
56fn cal_trim(actual: u16, desired: u16) -> u16 {
57    let dif = actual.saturating_sub(desired);
58    if dif > LINE_LIMIT as u16 { dif - LINE_LIMIT as u16 + 3 } // accounts for the `...`
59    else { 0 }
60}
61
62#[inline]
63fn gen_arrw(start_idx: u16, end_idx: u16, msg: &str, start_trim: u16, offset: u16) -> String {
64    let spaces_since_start = if start_trim > 0 {
65        start_idx - start_trim + 2 // acounts for the `...` and padding
66    } else { start_idx -1 };
67
68    let inbetween = end_idx - start_idx + 1 + offset; // even if it's the same character you still need a pointer
69
70    let mut out = " ".repeat(spaces_since_start as usize);
71    out.push_str(&"^".repeat(inbetween as usize));
72    out.push(' ');
73    out.push_str(&msg.replace('\n', "\x1b[36m\\n\x1b[31m"));
74    
75    out
76}
77
78/// Used to format text with colour
79/// # Examples
80/// ```rust
81/// flexar::colour_format![pink("["), none("Logger"), pink("] "), none("Example Log")];
82/// // outputs: [Logger] Example Log
83/// // but with colour
84/// ```
85#[macro_export]
86macro_rules! colour_format { // Verbose ugly stuff I can't read
87    ($(
88        $(none($none:expr))?
89        $(blue($blue:expr))?
90        $(pink($pink:expr))?
91        $(white($white:expr))?
92        $(green($green:expr))?
93        $(cyan($cyan:expr))?
94        $(red($red:expr))?
95        $(black($black:expr))?
96        $(yellow($yellow:expr))?
97    ),*) => {{
98        let mut string = String::new();
99        $(
100            $(string.push_str("\x1b[0m"); string.push_str($none);)?
101            $(string.push_str("\x1b[34m"); string.push_str($blue);)?
102            $(string.push_str("\x1b[35m"); string.push_str($pink);)?
103            $(string.push_str("\x1b[37m"); string.push_str($white);)?
104            $(string.push_str("\x1b[32m"); string.push_str($green);)?
105            $(string.push_str("\x1b[36m"); string.push_str($cyan);)?
106            $(string.push_str("\x1b[31m"); string.push_str($red);)?
107            $(string.push_str("\x1b[30m"); string.push_str($black);)?
108            $(string.push_str("\x1b[33m"); string.push_str($yellow);)?
109        )* string.push_str("\x1b[0m");
110        string
111    }}
112}