fix: doctor lists errors on one line with the hint last

This commit is contained in:
elwrcl committed 2026-09-29 23:30:04 +03:00
1 parent 272f2d30ab
commit 77ae14ed1d
2 files changed
+56 -3

No files matched your search

+27 -3
View File
@@ -4,6 +4,7 @@ use std::path::Path;
use anyhow::{Result, bail};
use crate::config;
use crate::error::one_line;
use crate::niri;
use crate::wayland::Wayland;
@@ -96,7 +97,10 @@ pub fn check_niri(version: Result<String>) -> Check {
match version {
Err(e) => check(
Level::Warn,
format!("niri IPC unavailable ({e:#}); using the first output for `screen`"),
format!(
"niri IPC unavailable ({}); using the first output for `screen`",
one_line(&e)
),
),
Ok(v) => match niri::parse_version(&v) {
Some(found) if found == niri::IPC_VERSION => check(Level::Ok, format!("niri {v}")),
@@ -117,7 +121,7 @@ pub fn check_config(path: &Path) -> Check {
Level::Ok,
format!("config {} not found, using defaults", path.display()),
),
Err(e) => check(Level::Fail, format!("config: {e:#}")),
Err(e) => check(Level::Fail, format!("config: {}", one_line(&e))),
}
}
@@ -155,7 +159,7 @@ pub fn run() -> Result<()> {
));
}
}
Err(e) => checks.push(check(Level::Fail, format!("wayland: {e:#}"))),
Err(e) => checks.push(check(Level::Fail, format!("wayland: {}", one_line(&e)))),
}
checks.push(check_niri(niri::version()));
let config_path = config::default_path();
@@ -246,6 +250,26 @@ mod tests {
);
}
#[test]
fn broken_config_fails_with_hint_last() {
let dir = tempfile::tempdir().unwrap();
let path = dir.path().join("config.toml");
std::fs::write(&path, "[save]\ndirectory = \n").unwrap();
let c = check_config(&path);
assert_eq!(c.level, Level::Fail);
assert!(
c.text.starts_with("config: invalid config file"),
"{}",
c.text
);
assert!(
c.text
.ends_with("(hint: fix the file or delete it to use the defaults)"),
"{}",
c.text
);
}
#[test]
fn save_dir_checks() {
let dir = tempfile::tempdir().unwrap();
+29
View File
@@ -58,6 +58,22 @@ pub fn render(err: &anyhow::Error, log: Option<&Path>) -> String {
out
}
/// The error on one line, hint last: `msg: cause (hint: ...)`. For places
/// that list several results, like `valw doctor`.
pub fn one_line(err: &anyhow::Error) -> String {
let hint = err.downcast_ref::<Hint>().map(|h| h.0.as_str());
let messages: Vec<String> = err
.chain()
.map(|e| e.to_string())
.filter(|m| Some(m.as_str()) != hint)
.collect();
let mut out = messages.join(": ");
if let Some(hint) = hint {
out.push_str(&format!(" (hint: {hint})"));
}
out
}
#[cfg(test)]
mod tests {
use super::*;
@@ -101,6 +117,19 @@ mod tests {
);
}
#[test]
fn one_line_puts_hint_last() {
let err = Err::<(), _>(anyhow!("Could not find wayland compositor"))
.context("could not connect to the Wayland compositor")
.hint("valw needs a Wayland session; is WAYLAND_DISPLAY set?")
.unwrap_err();
assert_eq!(
one_line(&err),
"could not connect to the Wayland compositor: Could not find wayland compositor \
(hint: valw needs a Wayland session; is WAYLAND_DISPLAY set?)"
);
}
#[test]
fn cancelled_is_detectable() {
let err = anyhow::Error::new(Cancelled).context("region selection");