From 902c1852a99a1e82175fcbc0fd0271bdfc25ce41 Mon Sep 17 00:00:00 2001 From: l0ng-ai <24760907+l0ng-ai@users.noreply.github.com> Date: Sun, 16 Aug 2026 09:28:39 +0800 Subject: [PATCH] fix(config): say when a setting is not the one being used MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A hand-edited `config.json` asking for `ui_font_size: 8`, `font_size: 999` and `scrollback_limit: 5` runs at 12, 256 and 100. Both halves of that are right — clamping beats refusing the whole file over one silly number, and the file is deliberately not rewritten, the same restraint the loader already shows toward a config it cannot read. What was missing is that nothing said so. The file keeps claiming 8 and the app keeps running at 12, and the two never meet. Each correction now names the field, what was asked for and what is in force. The `FontFeatures` parser in this same file has always logged a tag it could not use; a value quietly replaced is no easier to work out than a tag quietly dropped. Logging is off unless `TTY7_LOG` asks for it, so this is silent for everyone who is not looking — which is what makes it safe to put on a path that reloads per pane spawn. Verified against a running server: three warnings, one per clamped field, each with both numbers, and `config.json` untouched afterwards. --- crates/tty7-core/src/core/config.rs | 43 ++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/crates/tty7-core/src/core/config.rs b/crates/tty7-core/src/core/config.rs index 727fdb1a..e00fc09f 100644 --- a/crates/tty7-core/src/core/config.rs +++ b/crates/tty7-core/src/core/config.rs @@ -740,23 +740,48 @@ impl Config { self.link_file_open.unwrap_or_default() } + /// Bring the file's values into the ranges the app can actually run at. + /// + /// Clamping, not rejecting: one silly number should not cost someone their + /// whole config. The file is deliberately **not** rewritten — what cannot + /// be read must not be overwritten, and the same restraint applies to what + /// merely disagrees with us — so a hand-edited `ui_font_size: 8` stays 8 on + /// disk while the app runs at 12. + /// + /// That divergence is invisible from the file, so each correction says so + /// in the log. The `FontFeatures` parser a few hundred lines down already + /// works this way for a tag it cannot use, and a value quietly replaced is + /// no easier to work out than a tag quietly dropped. Logging is off unless + /// `TTY7_LOG` asks for it, so this costs nothing until someone is looking. fn sanitize(&mut self) { if !self.font_size.is_finite() || self.font_size <= 0.0 { self.font_size = Config::default().font_size; } - self.font_size = self.font_size.clamp(FONT_SIZE_MIN, FONT_SIZE_MAX); + clamped_note("font_size", self.font_size, { + self.font_size = self.font_size.clamp(FONT_SIZE_MIN, FONT_SIZE_MAX); + self.font_size + }); if !self.line_height.is_finite() || self.line_height <= 0.0 { self.line_height = Config::default().line_height; } - self.line_height = self.line_height.clamp(LINE_HEIGHT_MIN, LINE_HEIGHT_MAX); + clamped_note("line_height", self.line_height, { + self.line_height = self.line_height.clamp(LINE_HEIGHT_MIN, LINE_HEIGHT_MAX); + self.line_height + }); if !self.ui_font_size.is_finite() || self.ui_font_size <= 0.0 { self.ui_font_size = default_ui_font_size(); } // The whole chrome is a multiple of this, so a wild value does not // shrink one label — it makes the window unusable. Keep the range to // sizes the layout still holds together at. - self.ui_font_size = self.ui_font_size.clamp(UI_FONT_SIZE_MIN, UI_FONT_SIZE_MAX); - self.scrollback_limit = self.scrollback_limit.clamp(100, MAX_SCROLLBACK); + clamped_note("ui_font_size", self.ui_font_size, { + self.ui_font_size = self.ui_font_size.clamp(UI_FONT_SIZE_MIN, UI_FONT_SIZE_MAX); + self.ui_font_size + }); + clamped_note("scrollback_limit", self.scrollback_limit as f32, { + self.scrollback_limit = self.scrollback_limit.clamp(100, MAX_SCROLLBACK); + self.scrollback_limit as f32 + }); if !self.mouse_scroll_multiplier.is_finite() || self.mouse_scroll_multiplier <= 0.0 { self.mouse_scroll_multiplier = Config::default().mouse_scroll_multiplier; } @@ -1009,6 +1034,16 @@ pub(crate) fn shell_command() -> Option<(String, Vec)> { Config::load().shell.map(|s| (s.program, s.args)) } +/// Say when a configured value was not the one used. +/// +/// Only when it actually moved: a file already inside the range is the normal +/// case and has nothing to report. +fn clamped_note(field: &str, before: f32, after: f32) { + if (before - after).abs() > f32::EPSILON { + log::warn!("config {field}: {before} is out of range; running at {after}"); + } +} + pub(crate) fn working_directory_base() -> Option { let wd = Config::load().working_directory; let home = || std::env::var_os("HOME").map(PathBuf::from);