Skip to content

v0.1.2

@DrXOps DrXOps tagged this 26 Jul 12:06
Root causes found via Textual internals analysis:

1. Theme freeze — OptionCycler fired refresh_css() on EVERY click (no debounce).
   Each click → app.theme = x → _watch_theme → call_next(refresh_css) →
   stylesheet.reparse() + _refresh_layout on full widget tree (500+ nodes).
   Fix: 150ms set_timer debounce in _apply_theme_debounced; rapid clicks
   collapse into a single refresh_css call.

2. Sync file IO in main event loop — cfg.save() (yaml.dump + file.write)
   was called directly inside every Settings Save handler, blocking the
   Textual event loop for ~5-10ms (longer on slow disks).
   Fix: all cfg.save() moved to run_in_executor via _async_save_config worker.

3. Theme double-render — app.theme was set both in _apply_theme AND again
   in on_config_changed when ConfigChanged arrived from the observer.
   Fix: app.py guards with 'if current != new', screen.py saves config
   only on Save button (not on live preview).

4. Timer race on interval change — _setup_auto_save called timer.stop()
   then set_interval() in the same dispatch cycle.
   Fix: call_after_refresh(_setup_auto_save) + timer.pause() before stop().

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Assets 2
Loading