diff --git a/src/bin/lychee/main.rs b/src/bin/lychee/main.rs
index 28a14e7..9d54eef 100644
--- a/src/bin/lychee/main.rs
+++ b/src/bin/lychee/main.rs
@@ -175,7 +175,12 @@ async fn run(cfg: &Config, inputs: Vec) -> Result {
if let Some(output) = &cfg.output {
fs::write(output, stats_formatted).context("Cannot write status output to file")?;
} else {
- println!("\n{}", stats_formatted);
+ if cfg.verbose && !stats.is_empty() {
+ // separate summary from the verbose list of links above
+ println!();
+ }
+ // we assume that the formatted stats don't have a final newline
+ println!("{}", stats_formatted);
}
match stats.is_success() {
diff --git a/src/bin/lychee/stats.rs b/src/bin/lychee/stats.rs
index 5e0446d..09cc71a 100644
--- a/src/bin/lychee/stats.rs
+++ b/src/bin/lychee/stats.rs
@@ -74,9 +74,13 @@ impl ResponseStats {
pub fn is_success(&self) -> bool {
self.total == self.successful + self.excludes
}
+
+ pub fn is_empty(&self) -> bool {
+ self.total == 0
+ }
}
-fn write_stat(f: &mut fmt::Formatter, title: &str, stat: usize) -> fmt::Result {
+fn write_stat(f: &mut fmt::Formatter, title: &str, stat: usize, newline: bool) -> fmt::Result {
let fill = title.chars().count();
f.write_str(title)?;
f.write_str(
@@ -84,7 +88,12 @@ fn write_stat(f: &mut fmt::Formatter, title: &str, stat: usize) -> fmt::Result {
.to_string()
.pad(MAX_PADDING - fill, '.', Alignment::Right, false),
)?;
- f.write_str("\n")
+
+ if newline {
+ f.write_str("\n")?;
+ }
+
+ Ok(())
}
impl Display for ResponseStats {
@@ -93,24 +102,23 @@ impl Display for ResponseStats {
writeln!(f, "📝 Summary")?;
writeln!(f, "{}", separator)?;
- write_stat(f, "🔍 Total", self.total)?;
- write_stat(f, "✅ Successful", self.successful)?;
- write_stat(f, "⏳ Timeouts", self.timeouts)?;
- write_stat(f, "🔀 Redirected", self.redirects)?;
- write_stat(f, "👻 Excluded", self.excludes)?;
- write_stat(f, "🚫 Errors", self.errors + self.failures)?;
+ write_stat(f, "🔍 Total", self.total, true)?;
+ write_stat(f, "✅ Successful", self.successful, true)?;
+ write_stat(f, "⏳ Timeouts", self.timeouts, true)?;
+ write_stat(f, "🔀 Redirected", self.redirects, true)?;
+ write_stat(f, "👻 Excluded", self.excludes, true)?;
+ write_stat(f, "🚫 Errors", self.errors + self.failures, false)?;
- if !&self.fail_map.is_empty() {
- writeln!(f)?;
- }
for (input, responses) in &self.fail_map {
- writeln!(f, "Errors in {}", input)?;
+ // Using leading newlines over trailing ones (e.g. `writeln!`)
+ // lets us avoid extra newlines without any additional logic.
+ write!(f, "\n\nErrors in {}", input)?;
for response in responses {
- writeln!(f, "{}", color_response(response))?
+ write!(f, "\n{}", color_response(response))?
}
- writeln!(f)?;
}
- writeln!(f)
+
+ Ok(())
}
}
@@ -120,6 +128,20 @@ mod test_super {
use super::*;
+ #[test]
+ fn test_stats_is_empty() {
+ let mut stats = ResponseStats::new();
+ assert!(stats.is_empty());
+
+ stats.add(Response {
+ uri: website("http://example.org/ok"),
+ status: Status::Ok(http::StatusCode::OK),
+ source: Input::Stdin,
+ });
+
+ assert!(!stats.is_empty());
+ }
+
#[test]
fn test_stats() {
let mut stats = ResponseStats::new();