Make box-drawing code more reusable

- Move it to 'pretty' module.
  - Have function work on colored strings titles and contents
This commit is contained in:
KtorZ 2022-12-20 15:15:11 +01:00 committed by Lucas
parent f26737ecb4
commit 2fc14c7c1f
5 changed files with 139 additions and 31 deletions

37
Cargo.lock generated
View File

@ -124,6 +124,7 @@ dependencies = [
"reqwest", "reqwest",
"serde", "serde",
"serde_json", "serde_json",
"strip-ansi-escapes",
"thiserror", "thiserror",
"tokio", "tokio",
"toml", "toml",
@ -1848,6 +1849,15 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "strip-ansi-escapes"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "011cbb39cf7c1f62871aea3cc46e5817b0937b49e9447370c93cacbe93a766d8"
dependencies = [
"vte",
]
[[package]] [[package]]
name = "strsim" name = "strsim"
version = "0.10.0" version = "0.10.0"
@ -2234,6 +2244,12 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "utf8parse"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "936e4b492acfd135421d8dca4b1aa80a7bfc26e702ef3af710e0752684df5372"
[[package]] [[package]]
name = "vcpkg" name = "vcpkg"
version = "0.2.15" version = "0.2.15"
@ -2252,6 +2268,27 @@ version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "vte"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6cbce692ab4ca2f1f3047fcf732430249c0e971bfdd2b234cf2c47ad93af5983"
dependencies = [
"arrayvec",
"utf8parse",
"vte_generate_state_changes",
]
[[package]]
name = "vte_generate_state_changes"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d257817081c7dffcdbab24b9e62d2def62e2ff7d00b1c20062551e6cccc145ff"
dependencies = [
"proc-macro2",
"quote",
]
[[package]] [[package]]
name = "wait-timeout" name = "wait-timeout"
version = "0.2.0" version = "0.2.0"

View File

@ -125,28 +125,24 @@ impl telemetry::EventListener for Terminal {
let (max_mem, max_cpu) = find_max_execution_units(&tests); let (max_mem, max_cpu) = find_max_execution_units(&tests);
for (module, infos) in &group_by_module(&tests) { for (module, infos) in &group_by_module(&tests) {
let first = fmt_test(infos.first().unwrap(), max_mem, max_cpu, false).len(); let title = module.bold().blue().to_string();
let tests = infos
.iter()
.map(|eval_info| fmt_test(eval_info, max_mem, max_cpu, true))
.collect::<Vec<String>>()
.join("\n");
let summary = fmt_test_summary(infos, true);
println!( println!(
"{} {} {}", "{}\n",
" ┌──".bright_black(), pretty::indent(
module.bold().blue(), &pretty::open_box(&title, &tests, &summary, |border| border
pretty::pad_left("".to_string(), first - module.len() - 3, "") .bright_black()
.bright_black() .to_string()),
); 4
for eval_info in infos {
println!(
" {} {}",
"".bright_black(),
fmt_test(eval_info, max_mem, max_cpu, true)
) )
}
let last = fmt_test(infos.last().unwrap(), max_mem, max_cpu, false).len();
let summary = fmt_test_summary(infos, false).len();
println!(
"{} {}\n",
pretty::pad_right("".to_string(), last - summary + 5, "")
.bright_black(),
fmt_test_summary(infos, true),
); );
} }
} }

View File

@ -26,6 +26,7 @@ regex = "1.6.0"
reqwest = "0.11.13" reqwest = "0.11.13"
serde = { version = "1.0.144", features = ["derive"] } serde = { version = "1.0.144", features = ["derive"] }
serde_json = { version = "1.0.85", features = ["preserve_order"] } serde_json = { version = "1.0.85", features = ["preserve_order"] }
strip-ansi-escapes = "0.1.1"
thiserror = "1.0.37" thiserror = "1.0.37"
tokio = { version = "1.23.0", features = ["full"] } tokio = { version = "1.23.0", features = ["full"] }
toml = "0.5.9" toml = "0.5.9"

View File

@ -286,11 +286,11 @@ impl Diagnostic for Error {
None => None, None => None,
Some(hint) => { Some(hint) => {
let budget = ExBudget { mem: i64::MAX, cpu: i64::MAX, }; let budget = ExBudget { mem: i64::MAX, cpu: i64::MAX, };
let left = pretty::boxed("left", match hint.left.eval(budget) { let left = pretty::boxed("left", &match hint.left.eval(budget) {
(Ok(term), _, _) => format!("{term}"), (Ok(term), _, _) => format!("{term}"),
(Err(err), _, _) => format!("{err}"), (Err(err), _, _) => format!("{err}"),
}); });
let right = pretty::boxed("right", match hint.right.eval(budget) { let right = pretty::boxed("right", &match hint.right.eval(budget) {
(Ok(term), _, _) => format!("{term}"), (Ok(term), _, _) => format!("{term}"),
(Err(err), _, _) => format!("{err}"), (Err(err), _, _) => format!("{err}"),
}); });

View File

@ -1,26 +1,100 @@
pub fn boxed(title: &str, content: String) -> String { pub fn ansi_len(s: &str) -> usize {
let n = content.lines().fold(0, |max, l| { String::from_utf8(strip_ansi_escapes::strip(s).unwrap())
let n = l.len(); .unwrap()
.chars()
.count()
}
pub fn len_longest_line(s: &str) -> usize {
s.lines().fold(0, |max, l| {
let n = ansi_len(l);
if n > max { if n > max {
n n
} else { } else {
max max
} }
}); })
}
pub fn boxed(title: &str, content: &str) -> String {
boxed_with(title, content, |s| s.to_string())
}
pub fn boxed_with(title: &str, content: &str, border_style: fn(&str) -> String) -> String {
let n = len_longest_line(content);
let content = content let content = content
.lines() .lines()
.map(|line| format!("{}", pad_right(line.to_string(), n, " "))) .map(|line| {
format!(
"{} {} {}",
border_style(""),
pad_right(line.to_string(), n, " "),
border_style(""),
)
})
.collect::<Vec<String>>() .collect::<Vec<String>>()
.join("\n"); .join("\n");
let top = format!("┍━ {}", pad_right(format!("{title} "), n, "")); let top = format!(
let bottom = format!("{}", pad_right(String::new(), n + 2, "")); "{} {}{}",
border_style("┍━"),
pad_right(format!("{title} "), n, &border_style("")),
border_style(""),
);
let bottom = format!(
"{}{}{}",
border_style(""),
pad_right(String::new(), n + 2, &border_style("")),
border_style("")
);
format!("{top}\n{content}\n{bottom}") format!("{top}\n{content}\n{bottom}")
} }
pub fn open_box(
title: &str,
content: &str,
footer: &str,
border_style: fn(&str) -> String,
) -> String {
let i = ansi_len(content.lines().collect::<Vec<_>>().first().unwrap());
let j = len_longest_line(content);
let k = ansi_len(footer);
let content = content
.lines()
.map(|line| format!("{} {line}", border_style(""),))
.collect::<Vec<String>>()
.join("\n");
let top = format!(
"{} {}",
border_style("┍━"),
pad_right(format!("{title} "), i - 1, &border_style("")),
);
let bottom = format!(
"{} {}",
pad_right(border_style(""), j - k + 1, &border_style("")),
footer
);
format!("{top}\n{content}\n{bottom}")
}
pub fn indent(lines: &str, n: usize) -> String {
let tab = pad_left(String::new(), n, " ");
lines
.lines()
.map(|line| format!("{tab}{line}"))
.collect::<Vec<_>>()
.join("\n")
}
pub fn pad_left(mut text: String, n: usize, delimiter: &str) -> String { pub fn pad_left(mut text: String, n: usize, delimiter: &str) -> String {
let diff = n as i32 - text.len() as i32; let diff = n as i32 - ansi_len(&text) as i32;
if diff.is_positive() { if diff.is_positive() {
for _ in 0..diff { for _ in 0..diff {
text.insert_str(0, delimiter); text.insert_str(0, delimiter);
@ -30,7 +104,7 @@ pub fn pad_left(mut text: String, n: usize, delimiter: &str) -> String {
} }
pub fn pad_right(mut text: String, n: usize, delimiter: &str) -> String { pub fn pad_right(mut text: String, n: usize, delimiter: &str) -> String {
let diff = n as i32 - text.len() as i32; let diff = n as i32 - ansi_len(&text) as i32;
if diff.is_positive() { if diff.is_positive() {
for _ in 0..diff { for _ in 0..diff {
text.push_str(delimiter); text.push_str(delimiter);