1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
|
mod file_error;
mod merge_error;
mod resolver_error;
pub use file_error::*;
pub use merge_error::*;
pub use resolver_error::*;
use crate::*;
use ansi::*;
use log::LogLevel;
pub fn report_source_issue(level: LogLevel, context: &Context, message: &str) {
// Prepare variables.
let in_merged = &context.source.in_merged;
let line_num = in_merged.start.line + 1;
let digits = line_num.to_string().len();
let w = digits + 3;
let arrow = "-->";
let mut string = message.to_string();
macro_rules! push {
($($tokens:tt)*) => { string.push_str(&format!($($tokens)*)) };
}
// Format message and locations.
push!("{NORMAL}\n");
push!("{BLUE}{arrow:>w$}{NORMAL} {in_merged}\n", w=w);
if let Some(in_source) = &context.source.in_source {
push!("{BLUE}{arrow:>w$}{NORMAL} {in_source}\n", w=w);
}
// Format source context.
let left = in_merged.start.column;
let right = in_merged.end.column + 1;
let source_line = context.source_code.split('\n').nth(in_merged.start.line)
.unwrap_or("<error reading line from source>");
let space = " ";
let colour = match level {
LogLevel::Info => BLUE,
LogLevel::Warn => YELLOW,
LogLevel::Error => RED,
LogLevel::Fatal => RED,
};
// Print source code line.
push!("{BLUE} {line_num} | {NORMAL}");
for (i, c) in source_line.chars().enumerate() {
if i == left { push!("{colour}") }
if i == right { push!("{NORMAL}") }
push!("{c}");
}
push!("{NORMAL}\n");
// Print source code underline.
push!("{BLUE} {space:>w$} | {NORMAL}", w=digits);
for _ in 0..left { push!(" "); }
push!("{colour}");
for _ in left..right { push!("^"); }
push!("{NORMAL}");
// Print the completed message.
match level {
LogLevel::Info => log::info!( "{}", string),
LogLevel::Warn => log::warn!( "{}", string),
LogLevel::Error => log::error!("{}", string),
LogLevel::Fatal => log::fatal!("{}", string),
}
}
|