#![allow(
clippy::enum_glob_use,
clippy::needless_pass_by_value,
clippy::wildcard_imports
)]
use std::path::Path;
use termcolor::{Color, StandardStream, WriteColor};
use crate::output::ColorMode;
use crate::traits::{ParserTrait, Search};
use crate::checker::Checker;
use crate::getter::Getter;
use crate::tools::{color, intense_color};
#[derive(Debug)]
pub struct FunctionSpan {
pub name: Option<String>,
pub start_line: usize,
pub end_line: usize,
}
impl FunctionSpan {
#[must_use]
pub fn to_wire(&self) -> crate::wire::FunctionSpan {
crate::wire::FunctionSpan::from(self)
}
}
pub(crate) fn function<T: ParserTrait>(parser: &T) -> Vec<FunctionSpan> {
let root = parser.root();
let code = parser.code();
let mut spans = Vec::new();
root.act_on_node(&mut |n| {
if T::Checker::is_func(n) {
let start_line = n.start_row() + 1;
let end_line = n.end_row() + 1;
spans.push(FunctionSpan {
name: T::Getter::get_func_name(n, code).map(str::to_string),
start_line,
end_line,
});
}
});
spans
}
fn dump_span(span: FunctionSpan, stdout: &mut dyn WriteColor, last: bool) -> std::io::Result<()> {
let prefix = if last { " `- " } else { " |- " };
let (label_color, label) = match &span.name {
Some(name) => (Color::Magenta, Seg::NameColon(name)),
None => (Color::Red, Seg::Text("error: ")),
};
let segments: [(Color, bool, Seg<'_>); 6] = [
(Color::Blue, false, Seg::Text(prefix)),
(label_color, true, label),
(Color::Green, false, Seg::Text("from line ")),
(Color::White, false, Seg::Int(span.start_line)),
(Color::Green, false, Seg::Text(" to line ")),
(Color::White, false, Seg::IntDot(span.end_line)),
];
for (col, intense, seg) in segments {
write_seg(stdout, col, intense, seg)?;
}
Ok(())
}
#[derive(Clone, Copy)]
enum Seg<'a> {
Text(&'a str),
Int(usize),
IntDot(usize),
NameColon(&'a str),
}
fn write_seg(
stdout: &mut dyn WriteColor,
col: Color,
intense: bool,
seg: Seg<'_>,
) -> std::io::Result<()> {
if intense {
intense_color(stdout, col)?;
} else {
color(stdout, col)?;
}
match seg {
Seg::Text(s) => stdout.write_all(s.as_bytes()),
Seg::Int(n) => write!(stdout, "{n}"),
Seg::IntDot(n) => writeln!(stdout, "{n}."),
Seg::NameColon(s) => write!(stdout, "{s}: "),
}
}
fn dump_spans(
spans: Vec<FunctionSpan>,
path: &Path,
stdout: &mut dyn WriteColor,
) -> std::io::Result<()> {
if spans.is_empty() {
return Ok(());
}
intense_color(stdout, Color::Yellow)?;
writeln!(stdout, "In file {}", path.display())?;
let last_idx = spans.len() - 1;
for (i, span) in spans.into_iter().enumerate() {
dump_span(span, stdout, i == last_idx)?;
}
color(stdout, Color::White)
}
pub fn dump_function_spans(spans: Vec<FunctionSpan>, path: &Path) -> std::io::Result<()> {
dump_function_spans_with_color(spans, path, ColorMode::Always)
}
pub fn dump_function_spans_with_color(
spans: Vec<FunctionSpan>,
path: &Path,
color_mode: ColorMode,
) -> std::io::Result<()> {
if spans.is_empty() {
return Ok(());
}
let stdout = StandardStream::stdout(color_mode.to_color_choice());
let mut stdout = stdout.lock();
dump_spans(spans, path, &mut stdout)
}
#[cfg(test)]
#[path = "function_tests.rs"]
mod tests;