use std::env;
use std::io::Write;
use std::process::{Command, Stdio};
use mapm::problem::Problem;
use ansi_term::Colour::*;
use ansi_term::Style;
pub fn problems_to_string(problems: &[Problem]) -> String {
let mut problem_display = String::new();
let color: bool = env::var("NO_COLOR").is_err();
let g_bold_style: Option<Style> = Some(Green.bold());
let b_style: Option<Style> = Some(Blue.normal());
let b_bold_style: Option<Style> = Some(Blue.bold());
let r_style: Option<Style> = Some(Red.normal());
let r_bold_style: Option<Style> = Some(Red.bold());
let mut append_str = |s: &str, sty_opt: Option<Style>| {
if color {
match sty_opt {
Some(sty) => {
problem_display.push_str(&sty.paint(s).to_string());
}
None => {
problem_display.push_str(s);
}
}
} else {
problem_display.push_str(s);
}
};
for (
problem_idx,
Problem {
name,
vars,
solutions,
choices,
},
) in problems.iter().enumerate()
{
if problem_idx > 0 {
append_str("\n\n", None);
}
append_str(&format!("-- {} --", name), g_bold_style);
for (key, val) in vars {
append_str("\n", None);
append_str(key, b_style);
append_str(": ", None);
for (idx, string) in val.lines().enumerate() {
if idx == 0 {
append_str(string, None);
} else {
append_str("\n ", None);
append_str(&str::repeat(" ", key.chars().count()), None);
append_str(string, None);
}
}
}
if let Some(choices) = choices {
append_str("\n", None);
append_str("choices", b_bold_style);
append_str(": ", None);
if choices.is_empty() {
append_str("empty", r_bold_style);
} else {
for (idx, choice) in choices.iter().enumerate() {
append_str("\n ", None);
append_str(&((idx + 1).to_string() + "."), r_style);
append_str(" ", None);
append_str(choice, None);
}
}
append_str("\n", None);
}
if let Some(solutions) = solutions {
append_str("\n", None);
append_str("solutions", b_bold_style);
append_str(": ", None);
if solutions.is_empty() {
append_str("empty", r_bold_style);
} else {
for (idx, solution) in solutions.iter().enumerate() {
append_str("\n ", None);
append_str(&((idx + 1).to_string() + "."), r_style);
for (key_idx, (key, val)) in solution.iter().enumerate() {
if key_idx == 0 {
append_str(" ", None);
} else {
append_str("\n", None);
append_str(&str::repeat(" ", 5), None);
}
append_str(key, b_style);
append_str(": ", None);
for (idx, string) in val.lines().enumerate() {
if idx > 0 {
append_str("\n", None);
append_str(
&str::repeat(
" ",
(idx + 1).to_string().len() + key.chars().count() + 6,
),
None,
);
}
append_str(string, None);
}
}
}
}
}
}
problem_display
}
pub fn display(string: &str) {
match env::var("PAGER") {
Ok(pager) => {
let mut process = match Command::new(&pager).stdin(Stdio::piped()).spawn() {
Err(msg) => panic!("Couldn't spawn {pager}: {msg}"),
Ok(process) => process,
};
if let Err(e) = process.stdin.as_ref().unwrap().write_all(string.as_bytes()) {
if e.kind() == std::io::ErrorKind::BrokenPipe {
if matches!(std::env::var("NO_BROKEN_PIPE"), Err(_)) {
println!("The pipe from stdin to your pager was broken.");
println!("This is nothing to be concerned about and is absolutely normal if you didn't load the entire file into your pager.");
println!("The error message is reproduced below:");
println!("\t{}", e);
println!("If you would like to never see this input again, set the `NO_BROKEN_PIPE` environment variable.");
println!("(It doesn't matter what value you give it.)");
}
} else {
panic!("Couldn't write to `{pager}` stdin: {e}");
}
}
process.wait().expect("`wait` failed");
}
Err(_) => {
println!("{}", string);
}
}
}