Compact the status address list to one line per address

`tsunagi status` printed every local address as two lines: the address, then
an indented note holding the interface (and, for candidates, a priority rank).
On a host with many interfaces — common on macOS, where each VPN adds a utun
and every interface carries a link-local — that made the "local addresses"
section very long and hard to scan.

Each address is now a single line: the announce status stays the label
(announced / not announced / loopback) and the address and its interface share
the detail, as `<addr> · <iface>`. The per-row note and the candidate-priority
rank are dropped; ordering still reflects candidate priority. No other section
changes, and nothing but the presentation does.

Checks: cargo fmt --all --check, cargo clippy --locked --workspace
--all-targets -D warnings, and the tsunagi-cli tests all pass on macOS;
verified by eye against a live `tsunagi status`.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
UltradesuandClaude Opus 4.8 committed 2026-10-02 11:26:13 +01:00
1 parent c3a6201ee2
commit 4d2f8a54ec
1 file changed
+12 -14
+12 -14
View File
@@ -3061,18 +3061,19 @@ async fn addresses_section() -> report::Section {
iface_map.insert(item.addr, item.iface.clone());
}
// One line per address: the announce status is the label, and the address
// and its interface share the detail, so a host with many addresses stays
// compact instead of spending two lines on each.
let detail = |addr: std::net::IpAddr| match iface_map.get(&addr) {
Some(iface) => format!("{addr} · {iface}"),
None => addr.to_string(),
};
// 1. Announced peer candidate addresses (in candidate priority order)
let mut seen = std::collections::HashSet::new();
for (idx, &cand) in candidates.iter().enumerate() {
for &cand in &candidates {
if seen.insert(cand) {
let note = iface_map
.get(&cand)
.map(|iface| format!("{iface} · candidate #{}", idx + 1));
let row = Row::new(Health::Info, "announced", cand.to_string());
addresses.push(match note {
Some(n) => row.with_note(n),
None => row,
});
addresses.push(Row::new(Health::Info, "announced", detail(cand)));
}
}
@@ -3093,16 +3094,13 @@ async fn addresses_section() -> report::Section {
unannounced.sort_by_key(|item| item.addr);
for item in unannounced {
let note = format!("{} · not announced to peers", item.iface);
addresses
.push(Row::new(Health::Info, "not announced", item.addr.to_string()).with_note(note));
addresses.push(Row::new(Health::Info, "not announced", detail(item.addr)));
}
// 3. Loopback addresses
loopbacks.sort_by_key(|item| item.addr);
for item in loopbacks {
addresses
.push(Row::new(Health::Info, "loopback", item.addr.to_string()).with_note(&item.iface));
addresses.push(Row::new(Health::Info, "loopback", detail(item.addr)));
}
addresses