Private
Public Access
0
0

feat(gui): add _install_default_layout_if_empty helpers for install-on-empty-INI

Module-level _install_default_layout_if_empty(src, dst) reads the
bundled layout from src, decides if dst is missing/empty/small
(< 1000 bytes or no [Window][ header), copies src -> dst on true,
and returns Result[bool]. On OSError reading/writing, returns
Result[data=False, errors=[ErrorInfo]] so App._post_init can drain
to _startup_timeline_errors per the data-oriented convention.

_install_default_layout_if_empty_result(app, src, dst) is the
drain-plane passthrough that mirrors _post_init_callback_result.

Wiring into App._post_init lands in the next commit.
This commit is contained in:
2026-06-29 14:48:22 -04:00
parent b1632f4602
commit f3cd7bc2ff
+51
View File
@@ -1466,7 +1466,58 @@ def _post_init_callback_result(app: "App") -> Result[None]:
message=f"on_warmup_complete callback registration failed: {e}", message=f"on_warmup_complete callback registration failed: {e}",
source="gui_2._post_init_callback_result", source="gui_2._post_init_callback_result",
original=e, original=e,
)])
def _install_default_layout_if_empty(src_ini: Path, dst_ini: Path) -> Result[bool]:
"""Install bundled layout to cwd when the user's INI is missing/empty/small.
Decision rule: dst_ini is "empty" when its content is fewer than 1000
bytes OR has no [Window][ header. On empty, copies src_ini -> dst_ini
and returns Result(data=True). On non-empty (user customized), returns
Result(data=False) without overwriting. On OSError reading src or
writing dst, returns Result(data=False, errors=[ErrorInfo]) so the
legacy wrapper in App._post_init can drain to _startup_timeline_errors.
[C: src/gui_2.py:_install_default_layout_if_empty_result,
src/gui_2.py:App._post_init]"""
try:
dst_text: str = dst_ini.read_text(encoding="utf-8", errors="replace") if dst_ini.exists() else ""
except OSError:
dst_text = ""
is_dst_empty: bool = len(dst_text) < 1000 or "[Window][" not in dst_text
if not is_dst_empty:
return Result(data=False)
try:
src_text: str = src_ini.read_text(encoding="utf-8", errors="replace")
except OSError as e:
return Result(data=False, errors=[ErrorInfo(
kind=ErrorKind.INTERNAL,
message=f"Could not read bundled layout {src_ini}: {e}",
source="gui_2._install_default_layout_if_empty",
original=e,
)]) )])
try:
dst_ini.parent.mkdir(parents=True, exist_ok=True)
dst_ini.write_text(src_text, encoding="utf-8")
except OSError as e:
return Result(data=False, errors=[ErrorInfo(
kind=ErrorKind.INTERNAL,
message=f"Could not write layout {dst_ini}: {e}",
source="gui_2._install_default_layout_if_empty",
original=e,
)])
sys.stderr.write(f"[GUI] installed default layout: {src_ini} -> {dst_ini}\n")
return Result(data=True)
def _install_default_layout_if_empty_result(app: "App", src: Path, dst: Path) -> Result[bool]:
"""Drain-aware variant of _install_default_layout_if_empty.
Passthrough wrapper so App._post_init can call the install via the
drain-plane naming convention (mirrors _post_init_callback_result).
The wrapped function already returns Result[bool] and catches OSError
internally; this wrapper exists for naming consistency and to give
any future exception-logging policy a single hook point.
[C: src/gui_2.py:_install_default_layout_if_empty, src/gui_2.py:App._post_init]"""
return _install_default_layout_if_empty(src, dst)
def _run_immapp_result(app: "App") -> Result[None]: def _run_immapp_result(app: "App") -> Result[None]:
"""Drain-aware variant of App.run immapp.run() call (L728 INTERNAL_SILENT_SWALLOW). """Drain-aware variant of App.run immapp.run() call (L728 INTERNAL_SILENT_SWALLOW).