mirror of
https://github.com/l0ng-ai/tty7.git
synced 2026-09-24 00:02:24 +00:00
fix(doctor): name the config keys tty7 does not read
Mistyping a setting name is the likeliest thing to go wrong in a
hand-edited `config.json`, and the quietest. The file still parses, so
config ok
while the setting does nothing. `note_unknown_keys` has found these all
along — it says so with `log::warn!` behind a `log_enabled!` guard, and
per `docs/reference/privacy.mdx` there is no log at all unless `TTY7_LOG`
is set. Measured on a config carrying `font_siz`, `scrollback_limitt` and
one real key: nothing anywhere named the two that did nothing.
Unlike the keybindings map, this one `doctor` can ask: `unknown_keys` is
already in the crate the CLI shares, and already guarded by a test that
no real field may ever be reported as a typo. It only needed a way in.
config keys not settings tty7 reads, so they do nothing:
font_siz, scrollback_limitt — check the spelling
against the reference page
Only when the config parsed, and only when there is something to say. A
quarantined config is running on defaults and *every* key in it is
unread; naming them all would bury the row that matters. A clean config
prints no row at all, so this reads as news.
The test asks the pure function rather than the file-reading wrapper.
`unknown_config_keys` reads `TTY7_CONFIG_DIR`, and setting that from a
test steers every other test in the process — the first draft did, and
failed three runs out of three under the parallel suite.
This commit is contained in:
@@ -1806,6 +1806,28 @@ fn doctor(ctx: &Context, backend: &mut dyn Backend) -> Result<Outcome> {
|
||||
vec![address::ENV_PANE.to_string(), mark(&ctx.pane)],
|
||||
vec!["config".to_string(), config_state.clone()],
|
||||
];
|
||||
// A key tty7 does not read is the likeliest thing to go wrong in a
|
||||
// hand-edited config, and the quietest: the file parses, so the row above
|
||||
// says `ok`, and the setting simply does nothing. `note_unknown_keys`
|
||||
// already finds these — it just says so into a log that is not written
|
||||
// unless `TTY7_LOG` is set.
|
||||
//
|
||||
// Only when the config parsed. A quarantined one is running on defaults
|
||||
// and every key in it is unread; naming them all would bury the row that
|
||||
// matters.
|
||||
let unread_keys = config_ok
|
||||
.then(tty7_core::core::config::unknown_config_keys)
|
||||
.filter(|keys| !keys.is_empty());
|
||||
if let Some(keys) = &unread_keys {
|
||||
rows.push(vec![
|
||||
"config keys".to_string(),
|
||||
format!(
|
||||
"not settings tty7 reads, so they do nothing: {} — check the spelling against \
|
||||
the reference page",
|
||||
keys.join(", ")
|
||||
),
|
||||
]);
|
||||
}
|
||||
if let Some(kept) = &quarantined_tree {
|
||||
let newest = kept
|
||||
.last()
|
||||
|
||||
@@ -1136,6 +1136,29 @@ fn note_unknown_keys(text: &str) {
|
||||
}
|
||||
}
|
||||
|
||||
/// The keys in the user's `config.json` that tty7 does not read, or an empty
|
||||
/// list when the file is absent or does not parse.
|
||||
///
|
||||
/// [`note_unknown_keys`] already finds these and says so with `log::warn!`,
|
||||
/// behind a `log_enabled!` guard — and per `docs/reference/privacy.mdx` there
|
||||
/// is no log at all unless `TTY7_LOG` is set. Mistyping a setting name is the
|
||||
/// likeliest thing to go wrong in a hand-edited config, and on a default
|
||||
/// install it is answered with silence: the file parses, so `doctor` reports
|
||||
/// the config `ok` while the setting does nothing.
|
||||
///
|
||||
/// A file that does not parse answers empty on purpose. It is already
|
||||
/// quarantined and reported as such, and every key in it is unread — naming
|
||||
/// them all would bury the one thing worth saying.
|
||||
pub fn unknown_config_keys() -> Vec<String> {
|
||||
let Some(path) = config_path("config.json") else {
|
||||
return Vec::new();
|
||||
};
|
||||
let Ok(text) = std::fs::read_to_string(&path) else {
|
||||
return Vec::new();
|
||||
};
|
||||
unknown_keys(strip_bom(&text))
|
||||
}
|
||||
|
||||
/// The comparison behind [`note_unknown_keys`], separated so the property that
|
||||
/// matters can be tested: no real field may ever be named here.
|
||||
fn unknown_keys(text: &str) -> Vec<String> {
|
||||
@@ -1682,6 +1705,39 @@ mod tests {
|
||||
assert!(!back.dim_inactive_panes);
|
||||
}
|
||||
|
||||
/// What a reader can be told about a hand-edited config.
|
||||
///
|
||||
/// `note_unknown_keys` has found these all along and said so with
|
||||
/// `log::warn!` behind a `log_enabled!` guard, so on a default install —
|
||||
/// where no log is written at all — mistyping a setting name is answered
|
||||
/// with silence: the file parses, `doctor` calls the config `ok`, and the
|
||||
/// setting does nothing. This is the question `doctor` asks instead.
|
||||
///
|
||||
/// Asked of the text rather than through `unknown_config_keys`, which
|
||||
/// reads `TTY7_CONFIG_DIR`: setting that from a test steers every other
|
||||
/// test in the process, and the suite runs them in parallel. The wrapper
|
||||
/// adds only "no file is not a typo" to what is checked here.
|
||||
#[test]
|
||||
fn the_keys_a_config_file_wastes_can_be_named() {
|
||||
assert!(
|
||||
unknown_keys(r#"{"font_size": 13.0}"#).is_empty(),
|
||||
"a real setting is not a typo"
|
||||
);
|
||||
assert_eq!(
|
||||
unknown_keys(r#"{"font_siz": 13.0, "font_size": 13.0}"#),
|
||||
vec!["font_siz".to_string()],
|
||||
"the typo is named and its correct neighbour is not"
|
||||
);
|
||||
assert!(
|
||||
unknown_keys(r#"{"font_size": "#).is_empty(),
|
||||
"a file that does not parse is the quarantine's news, not this one's"
|
||||
);
|
||||
assert!(
|
||||
unknown_keys("").is_empty(),
|
||||
"and nothing at all says nothing"
|
||||
);
|
||||
}
|
||||
|
||||
/// Every field the struct has must be recognised, and only those.
|
||||
///
|
||||
/// The known set comes from serialising the default, so this is really
|
||||
|
||||
Reference in New Issue
Block a user