use std::fs::File;
use std::io::{BufRead, BufReader};
use std::path::Path;
use crate::sudoers::Span;
pub(crate) fn cited_error(message: &str, span: Span, path: impl AsRef<Path>) {
let path_str = path.as_ref().display();
let Span {
start: (line, col),
end: (end_line, mut end_col),
} = span;
eprintln_ignore_io_error!("{path_str}:{line}:{col}: {message}");
if line != end_line {
end_col = col;
}
let citation = || {
let inp = BufReader::new(File::open(path).ok()?);
let line = inp.lines().nth(line - 1)?.ok()?;
let padding = line
.chars()
.take(col - 1)
.map(|c| if c.is_whitespace() { c } else { ' ' })
.collect::<String>();
let lineunder = std::iter::repeat_n('~', end_col - col)
.skip(1)
.collect::<String>();
eprintln_ignore_io_error!("{line}");
eprintln_ignore_io_error!("{padding}^{lineunder}");
Some(())
};
let _ = citation();
}
macro_rules! diagnostic {
($str:expr, $path:tt @ $pos:ident) => {
if let Some(range) = $pos {
$crate::sudo::diagnostic::cited_error(&format!($str), range, $path);
} else {
for line in format!($str).split('\n') {
eprintln_ignore_io_error!("sudo: {}", line);
}
}
};
($str:expr) => {{
for line in format!($str).split('\n') {
eprintln_ignore_io_error!("sudo: {}", line);
}
}};
}
pub(crate) use diagnostic;