diff --git a/src/gui_2.py b/src/gui_2.py index 974151e7..43aed784 100644 --- a/src/gui_2.py +++ b/src/gui_2.py @@ -5738,12 +5738,12 @@ def render_text_viewer_window(app: App) -> None: elif tv_type in renderer._lang_map: if app._text_viewer_editor is None: app._text_viewer_editor = ced.TextEditor(); app._text_viewer_editor.set_read_only_enabled(True); app._text_viewer_editor.set_show_line_numbers_enabled(True) - try: - app._text_viewer_editor.set_text(app.text_viewer_content) - if app.perf_profiling_enabled: app.perf_monitor.start_component("_render_text_viewer_ced") - app._text_viewer_editor.render(f"##ced_{app.text_viewer_title}", imgui.ImVec2(-1, -1)) - if app.perf_profiling_enabled: app.perf_monitor.end_component("_render_text_viewer_ced") - except Exception as e: imgui.text_colored(theme.get_color("status_error"), f"CED Error: {e}"); imgui.text_unformatted(app.text_viewer_content) + ced_result = _render_text_viewer_window_ced_result(app) + if not ced_result.ok: + if not hasattr(app, '_last_request_errors'): app._last_request_errors = [] + app._last_request_errors.append(("_render_text_viewer_window_ced", ced_result.errors[0])) + imgui.text_colored(theme.get_color("status_error"), f"CED Error: {ced_result.errors[0].message}") + imgui.text_unformatted(app.text_viewer_content) else: with imscope.child("tv_scroll", -1, -1, True): if app.text_viewer_wrap: imgui.push_text_wrap_pos(imgui.get_content_region_avail().x) @@ -7988,6 +7988,34 @@ def _render_operations_hub_external_editor_panel_result(app: "App") -> Result[bo original=e, )]) + +def _render_text_viewer_window_ced_result(app: "App") -> Result[bool]: + """Drain-aware variant of L5786 render_text_viewer_window CED branch. + + Extracts the TextEditor set_text/render try/except from + render_text_viewer_window CED branch into a Result-returning helper. On + success, returns Result(data=True). On exception, converts the exception + to ErrorInfo and returns Result(data=False, errors=[ErrorInfo]). + + The legacy wrapper drains errors to app._last_request_errors (per FR-BC-4 + event-handler drain pattern; data plane attribute). + + [C: src/gui_2.py:render_text_viewer_window (L5786 legacy wrapper)] + """ + try: + app._text_viewer_editor.set_text(app.text_viewer_content) + if app.perf_profiling_enabled: app.perf_monitor.start_component("_render_text_viewer_ced") + app._text_viewer_editor.render(f"##ced_{app.text_viewer_title}", imgui.ImVec2(-1, -1)) + if app.perf_profiling_enabled: app.perf_monitor.end_component("_render_text_viewer_ced") + return Result(data=True) + except Exception as e: + return Result(data=False, errors=[ErrorInfo( + kind=ErrorKind.INTERNAL, + message=f"Text viewer CED render failed: {e}", + source="gui_2._render_text_viewer_window_ced_result", + original=e, + )]) + #endregion: Phase 5 Event Handler Result Helpers #endregion: MMA diff --git a/tests/test_gui_2_result.py b/tests/test_gui_2_result.py index 1c624790..35555105 100644 --- a/tests/test_gui_2_result.py +++ b/tests/test_gui_2_result.py @@ -1142,3 +1142,46 @@ def test_phase_5_l5380_render_operations_hub_external_editor_panel_result_failur err = result.errors[0] assert err.source == "gui_2._render_operations_hub_external_editor_panel_result" assert "ext editor render blew up" in err.message + + +def test_phase_5_l5786_render_text_viewer_window_ced_result_success(): + """ + L5786 _render_text_viewer_window_ced_result returns Result.ok=True on success. + + The helper wraps the TextEditor set_text/render try/except in + render_text_viewer_window. On success, returns Result(data=True). + """ + from src import gui_2 + from unittest.mock import MagicMock, patch + app = MagicMock() + app.perf_profiling_enabled = False + app.text_viewer_content = "line1\nline2\n" + app.text_viewer_title = "test.txt" + app._text_viewer_editor = MagicMock() + result = gui_2._render_text_viewer_window_ced_result(app) + assert result.ok, f"Expected ok=True on success, got errors: {result.errors}" + assert result.data is True + + +def test_phase_5_l5786_render_text_viewer_window_ced_result_failure(): + """ + L5786 _render_text_viewer_window_ced_result returns Result.ok=False with ErrorInfo on failure. + + When TextEditor render raises, the helper converts the exception to ErrorInfo + and returns Result(data=False, errors=[ErrorInfo]). + """ + from src import gui_2 + from unittest.mock import MagicMock, patch + app = MagicMock() + app.perf_profiling_enabled = False + app.text_viewer_content = "line1\nline2\n" + app.text_viewer_title = "test.txt" + mock_editor = MagicMock() + mock_editor.set_text.side_effect = RuntimeError("ced set_text failed") + app._text_viewer_editor = mock_editor + result = gui_2._render_text_viewer_window_ced_result(app) + assert not result.ok, f"Expected ok=False on failure, got data: {result.data}" + assert result.errors, "Expected at least one error on failure" + err = result.errors[0] + assert err.source == "gui_2._render_text_viewer_window_ced_result" + assert "ced set_text failed" in err.message