Format the Rust code with rustfmt

The code was formatted by hand, and `cargo fmt --check` differed in 866
places. rustfmt.toml keeps the house's long lines (120) and short
expressions on one line, which halves what changes; this commit is only
what rustfmt does with it, and is named in .git-blame-ignore-revs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-17 21:55:41 +00:00
parent 2c4ba7896e
commit 692a510217
26 changed files with 1710 additions and 1114 deletions

View File

@@ -9,11 +9,11 @@
use std::collections::BTreeMap;
use std::fmt::Write;
use axum::Router;
use axum::extract::{Path, Query, State};
use axum::http::{HeaderValue, StatusCode, header};
use axum::response::{IntoResponse, Response};
use axum::routing::get;
use axum::Router;
use crate::{Listing, Shared};
@@ -63,7 +63,9 @@ async fn home(State(dir): State<Shared>) -> Response {
Err(e) => return failed(e),
};
let mut top = all.clone();
top.sort_by(|a, b| b.subscribers.cmp(&a.subscribers).then_with(|| name(a).to_lowercase().cmp(&name(b).to_lowercase())));
top.sort_by(|a, b| {
b.subscribers.cmp(&a.subscribers).then_with(|| name(a).to_lowercase().cmp(&name(b).to_lowercase()))
});
top.truncate(10);
let mut cats: BTreeMap<&str, Vec<&Listing>> = BTreeMap::new();
for l in &all {
@@ -75,12 +77,25 @@ async fn home(State(dir): State<Shared>) -> Response {
} else {
b.push_str("<h2>Most subscribed</h2><ol class=chart>");
for (i, l) in top.iter().enumerate() {
let _ = write!(b, "<li><a href=\"/feed/{}\"><span class=no>{}</span>{}<span class=txt><b>{}</b><small>{}</small></span></a></li>",
esc(&l.id), i + 1, art(l, "art sm"), esc(name(l)), subscribers(l.subscribers));
let _ = write!(
b,
"<li><a href=\"/feed/{}\"><span class=no>{}</span>{}<span class=txt><b>{}</b><small>{}</small></span></a></li>",
esc(&l.id),
i + 1,
art(l, "art sm"),
esc(name(l)),
subscribers(l.subscribers)
);
}
b.push_str("</ol><h2>Categories</h2><div class=cats>");
for (c, ls) in &cats {
let _ = write!(b, "<a class=cat href=\"/category/{}\"><b>{}</b><small>{}</small></a>", seg(c), esc(c), ls.len());
let _ = write!(
b,
"<a class=cat href=\"/category/{}\"><b>{}</b><small>{}</small></a>",
seg(c),
esc(c),
ls.len()
);
}
let _ = write!(b, "</div><p><a class=more href=\"/all\">All {} feeds, A to Z</a></p>", all.len());
}
@@ -115,10 +130,11 @@ async fn listed(dir: &Shared, title: &str, here: &str, f: &Filter, pick: impl Fn
if ls.is_empty() && here.starts_with("/category/") {
return not_found("That category has nothing in it.");
}
let subs: BTreeMap<String, usize> = ls.iter().filter_map(|l| l.subcategory.clone()).fold(BTreeMap::new(), |mut m, s| {
*m.entry(s).or_default() += 1;
m
});
let subs: BTreeMap<String, usize> =
ls.iter().filter_map(|l| l.subcategory.clone()).fold(BTreeMap::new(), |mut m, s| {
*m.entry(s).or_default() += 1;
m
});
ls.retain(|l| f.keep(l) && f.sub.as_ref().is_none_or(|s| l.subcategory.as_ref() == Some(s)));
ls.sort_by_key(|l| name(l).to_lowercase());
@@ -138,18 +154,38 @@ async fn listed(dir: &Shared, title: &str, here: &str, f: &Filter, pick: impl Fn
if q.is_empty() { here.to_owned() } else { format!("{here}?{q}") }
};
let mut b = String::new();
let _ = write!(b, "<p class=back><a href=\"/\">Directory</a></p><h2>{}</h2><nav class=tabs aria-label=Kind>", esc(title));
let _ = write!(
b,
"<p class=back><a href=\"/\">Directory</a></p><h2>{}</h2><nav class=tabs aria-label=Kind>",
esc(title)
);
for (k, label) in [(None, "All"), (Some("podcasts"), "Podcasts"), (Some("blogs"), "Blogs")] {
let on = f.kind.as_deref() == k;
let _ = write!(b, "<a href=\"{}\"{}>{label}</a>", esc(&link(k, f.sub.as_deref())), if on { " aria-current=page" } else { "" });
let _ = write!(
b,
"<a href=\"{}\"{}>{label}</a>",
esc(&link(k, f.sub.as_deref())),
if on { " aria-current=page" } else { "" }
);
}
b.push_str("</nav>");
if !subs.is_empty() {
b.push_str("<nav class=pills aria-label=Subcategory>");
let _ = write!(b, "<a href=\"{}\"{}>All</a>", esc(&link(f.kind.as_deref(), None)), if f.sub.is_none() { " aria-current=page" } else { "" });
let _ = write!(
b,
"<a href=\"{}\"{}>All</a>",
esc(&link(f.kind.as_deref(), None)),
if f.sub.is_none() { " aria-current=page" } else { "" }
);
for (s, n) in &subs {
let on = f.sub.as_deref() == Some(s.as_str());
let _ = write!(b, "<a href=\"{}\"{}>{} <small>{n}</small></a>", esc(&link(f.kind.as_deref(), Some(s))), if on { " aria-current=page" } else { "" }, esc(s));
let _ = write!(
b,
"<a href=\"{}\"{}>{} <small>{n}</small></a>",
esc(&link(f.kind.as_deref(), Some(s))),
if on { " aria-current=page" } else { "" },
esc(s)
);
}
b.push_str("</nav>");
}
@@ -158,7 +194,14 @@ async fn listed(dir: &Shared, title: &str, here: &str, f: &Filter, pick: impl Fn
} else {
let _ = write!(b, "<p class=count>{}</p><div class=tiles>", plural(ls.len(), "feed"));
for l in &ls {
let _ = write!(b, "<a class=tile href=\"/feed/{}\">{}<b>{}</b><small>{}</small></a>", esc(&l.id), art(l, "art"), esc(name(l)), subscribers(l.subscribers));
let _ = write!(
b,
"<a class=tile href=\"/feed/{}\">{}<b>{}</b><small>{}</small></a>",
esc(&l.id),
art(l, "art"),
esc(name(l)),
subscribers(l.subscribers)
);
}
b.push_str("</div>");
}
@@ -177,11 +220,21 @@ async fn feed(State(dir): State<Shared>, Path(id): Path<String>) -> Response {
if let Some(c) = &l.category {
let _ = write!(b, " <span aria-hidden=true>/</span> <a href=\"/category/{}\">{}</a>", seg(c), esc(c));
}
let _ = write!(b, "</p><div class=show>{}<div class=meta><h2>{}</h2><p class=sub>{}{}</p>", art(l, "art lg"), esc(name(l)),
subscribers(l.subscribers), l.subcategory.as_deref().map(|s| format!(" &middot; {}", esc(s))).unwrap_or_default());
let _ = write!(b, "<div class=addr><label for=addr>Feed address</label><span class=row><input id=addr readonly value=\"{}\" spellcheck=false>\
let _ = write!(
b,
"</p><div class=show>{}<div class=meta><h2>{}</h2><p class=sub>{}{}</p>",
art(l, "art lg"),
esc(name(l)),
subscribers(l.subscribers),
l.subcategory.as_deref().map(|s| format!(" &middot; {}", esc(s))).unwrap_or_default()
);
let _ = write!(
b,
"<div class=addr><label for=addr>Feed address</label><span class=row><input id=addr readonly value=\"{}\" spellcheck=false>\
<button type=button data-copy=\"{}\">Copy</button></span><small>Paste it into any podcast app or feed reader to subscribe.</small></div></div></div>",
esc(&l.url), esc(&l.url));
esc(&l.url),
esc(&l.url)
);
if let Some(d) = p.description.as_deref().map(text).filter(|d| !d.is_empty() && d != name(l)) {
let _ = write!(b, "<p class=about>{}</p>", esc(&d));
}
@@ -199,17 +252,26 @@ async fn feed(State(dir): State<Shared>, Path(id): Path<String>) -> Response {
None => esc(&title),
};
let blurb: String = e.description.as_deref().map(text).unwrap_or_default().chars().take(400).collect();
let when = [e.published.map(date), e.duration.filter(|d| *d > 0).map(clock)].into_iter().flatten().collect::<Vec<_>>().join(" &middot; ");
let _ = write!(b, "<article><b>{head}</b>{}{}</article>",
let when = [e.published.map(date), e.duration.filter(|d| *d > 0).map(clock)]
.into_iter()
.flatten()
.collect::<Vec<_>>()
.join(" &middot; ");
let _ = write!(
b,
"<article><b>{head}</b>{}{}</article>",
if blurb.is_empty() { String::new() } else { format!("<p>{}</p>", esc(&blurb)) },
if when.is_empty() { String::new() } else { format!("<small>{when}</small>") });
if when.is_empty() { String::new() } else { format!("<small>{when}</small>") }
);
}
page(name(l), Some(&text(p.description.as_deref().unwrap_or(""))), &b)
}
fn page(title: &str, description: Option<&str>, body: &str) -> Response {
let full = if title == "iPX Directory" { title.to_owned() } else { format!("{title} | iPX Directory") };
let desc = description.filter(|d| !d.is_empty()).map(|d| d.chars().take(200).collect::<String>())
let desc = description
.filter(|d| !d.is_empty())
.map(|d| d.chars().take(200).collect::<String>())
.unwrap_or_else(|| "Public podcasts and blogs that iPX servers share.".into());
let html = format!(
"<!doctype html><html lang=en><head><meta charset=utf-8><meta name=viewport content=\"width=device-width,initial-scale=1\">\
@@ -234,14 +296,22 @@ fn page(title: &str, description: Option<&str>, body: &str) -> Response {
}
fn not_found(why: &str) -> Response {
let mut r = page("Not found", None, &format!("<p class=back><a href=\"/\">Directory</a></p><h2>Not found</h2><p class=hint>{}</p>", esc(why)));
let mut r = page(
"Not found",
None,
&format!("<p class=back><a href=\"/\">Directory</a></p><h2>Not found</h2><p class=hint>{}</p>", esc(why)),
);
*r.status_mut() = StatusCode::NOT_FOUND;
r
}
fn failed(e: anyhow::Error) -> Response {
tracing::error!(error = %format!("{e:#}"), "a directory page failed");
let mut r = page("Unavailable", None, "<h2>Unavailable</h2><p class=hint>The directory could not read its list just now. Try again in a minute.</p>");
let mut r = page(
"Unavailable",
None,
"<h2>Unavailable</h2><p class=hint>The directory could not read its list just now. Try again in a minute.</p>",
);
*r.status_mut() = StatusCode::SERVICE_UNAVAILABLE;
r
}
@@ -253,8 +323,12 @@ fn redirect(to: &'static str) -> Response {
/// A cover from its publisher, over the feed's initials, which show where it has none or it fails.
fn art(l: &Listing, class: &str) -> String {
// The first letter of each of the first two words that have one: `<antirez>` is A, not nothing.
let initials: String = name(l).split_whitespace().filter_map(|w| w.chars().find(|c| c.is_alphanumeric())).take(2).collect();
let img = l.image.as_deref().filter(|u| u.starts_with("https://") || u.starts_with("http://"))
let initials: String =
name(l).split_whitespace().filter_map(|w| w.chars().find(|c| c.is_alphanumeric())).take(2).collect();
let img = l
.image
.as_deref()
.filter(|u| u.starts_with("https://") || u.starts_with("http://"))
.map(|u| format!("<img src=\"{}\" alt=\"\" loading=lazy referrerpolicy=no-referrer>", esc(u)))
.unwrap_or_default();
format!("<span class=\"{class}\" aria-hidden=true><i>{}</i>{img}</span>", esc(&initials.to_uppercase()))
@@ -301,7 +375,13 @@ fn clock(secs: i64) -> String {
fn text(html: &str) -> String {
// A space where each tag was, or two paragraphs run together: "drives.For over".
let stripped = ammonia::Builder::empty().clean(&html.replace('<', " <")).to_string();
let decoded = stripped.replace("&lt;", "<").replace("&gt;", ">").replace("&quot;", "\"").replace("&#39;", "'").replace("&nbsp;", " ").replace("&amp;", "&");
let decoded = stripped
.replace("&lt;", "<")
.replace("&gt;", ">")
.replace("&quot;", "\"")
.replace("&#39;", "'")
.replace("&nbsp;", " ")
.replace("&amp;", "&");
decoded.split_whitespace().collect::<Vec<_>>().join(" ")
}