use codesnake::{Block, CodeWidth, Label, LineIndex};
use core::fmt::{self, Display, Formatter};
use yansi::{Color, Paint};
const SRC: &str = r#"(defun factorial (n) (if (zerop n) 1
(* n (factorial (1- n)))))"#;
fn paint_html(f: &mut Formatter, color: &Color, s: &dyn Display) -> fmt::Result {
if *color == Color::default() {
write!(f, "{s}")
} else {
let mut color = format!("{color:?}");
color.make_ascii_lowercase();
write!(f, "<span class={color}>{s}</span>")
}
}
fn paint_ansi(f: &mut Formatter, color: &Color, s: &dyn Display) -> fmt::Result {
s.fg(*color).fmt(f)
}
fn main() {
let html = std::env::args().skip(1).any(|arg| arg == "--html");
let idx = LineIndex::new(SRC);
let paint = if html { paint_html } else { paint_ansi };
let labels = [
Label::new(1..6).with_style(Color::Red),
Label::new(7..16)
.with_text("this function ...")
.with_style(Color::Green),
Label::new(21..70)
.with_text("... is defined by this")
.with_style(Color::Blue),
Label::new(71..71)
.with_text("(and here is EOF)")
.with_style(Color::Yellow),
];
let block = Block::new(&idx, labels).unwrap();
let block = block.with_paint(paint).map_code(|s| {
let s = s.replace('\t', " ");
let w = unicode_width::UnicodeWidthStr::width(&*s);
CodeWidth::new(s, core::cmp::max(w, 1))
});
let filename = from_fn(|f| paint(f, &Color::Red, &"[fac.lisp]"));
println!("{}{filename}", block.prologue());
println!("{}", block.space_vert());
print!("{block}");
println!("{}", block.epilogue());
}
fn from_fn<F: Fn(&mut Formatter) -> fmt::Result>(f: F) -> FromFn<F> {
FromFn(f)
}
struct FromFn<F>(F);
impl<F: Fn(&mut Formatter) -> fmt::Result> Display for FromFn<F> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
(self.0)(f)
}
}