fix(ui): explain the io errors that build their own message

`explain_io` exists because "Permission denied (os error 13)" answers a
developer's question and not the reader's — its own doc says so. Every
failure routed through `HostOps::notify_err` gets it. Four that build
their notification string by hand did not, and printed the raw error.

The clearest symptom was inside one file: saving a file in the editor
went through `notify_err` and explained itself, while opening the same
file, denied for the same reason, said `os error 13`. Both file-link
openers are changed together — the file tree's opener deliberately shares
its wording with the terminal's (#542), so explaining one and not the
other would have split a pairing that was on purpose.

The `log::warn!` next to each call keeps the exact error. A developer
reading a log and a person who just lost a save want different things,
so both are written rather than one chosen — noted on `explain_io` along
with the rule, since it was the absence of a stated rule that let four
callers drift.
This commit is contained in:
l0ng-ai
2026-08-16 00:52:02 +08:00
parent 4a41dbd747
commit 005efee058
4 changed files with 22 additions and 4 deletions
+8 -2
View File
@@ -494,7 +494,10 @@ impl Tty7App {
Err(e) => {
return Err(t_fmt(
L10nKey::EditorCantOpen,
&[("path", &path.display().to_string()), ("e", &e.to_string())],
&[
("path", &path.display().to_string()),
("e", &crate::ui::host_ops::explain_io(&e)),
],
));
}
};
@@ -512,7 +515,10 @@ impl Tty7App {
Err(e) => {
return Err(t_fmt(
L10nKey::EditorCantRead,
&[("path", &path.display().to_string()), ("e", &e.to_string())],
&[
("path", &path.display().to_string()),
("e", &crate::ui::host_ops::explain_io(&e)),
],
));
}
};