""" Display output abstraction - allows swapping output backends. Protocol: - init(width, height): Initialize display with terminal dimensions - show(buffer): Render buffer (list of strings) to display - clear(): Clear the display - cleanup(): Shutdown display """ import time from typing import Protocol class Display(Protocol): """Protocol for display backends.""" def init(self, width: int, height: int) -> None: """Initialize display with dimensions.""" ... def show(self, buffer: list[str]) -> None: """Show buffer on display.""" ... def clear(self) -> None: """Clear display.""" ... def cleanup(self) -> None: """Shutdown display.""" ... def get_monitor(): """Get the performance monitor.""" try: from engine.effects.performance import get_monitor as _get_monitor return _get_monitor() except Exception: return None class TerminalDisplay: """ANSI terminal display backend.""" def __init__(self): self.width = 80 self.height = 24 def init(self, width: int, height: int) -> None: from engine.terminal import CURSOR_OFF self.width = width self.height = height print(CURSOR_OFF, end="", flush=True) def show(self, buffer: list[str]) -> None: import sys t0 = time.perf_counter() sys.stdout.buffer.write("".join(buffer).encode()) sys.stdout.flush() elapsed_ms = (time.perf_counter() - t0) * 1000 monitor = get_monitor() if monitor: chars_in = sum(len(line) for line in buffer) monitor.record_effect("terminal_display", elapsed_ms, chars_in, chars_in) def clear(self) -> None: from engine.terminal import CLR print(CLR, end="", flush=True) def cleanup(self) -> None: from engine.terminal import CURSOR_ON print(CURSOR_ON, end="", flush=True) class NullDisplay: """Headless/null display - discards all output.""" def init(self, width: int, height: int) -> None: self.width = width self.height = height def show(self, buffer: list[str]) -> None: monitor = get_monitor() if monitor: t0 = time.perf_counter() chars_in = sum(len(line) for line in buffer) elapsed_ms = (time.perf_counter() - t0) * 1000 monitor.record_effect("null_display", elapsed_ms, chars_in, chars_in) def clear(self) -> None: pass def cleanup(self) -> None: pass class MultiDisplay: """Display that forwards to multiple displays.""" def __init__(self, displays: list[Display]): self.displays = displays self.width = 80 self.height = 24 def init(self, width: int, height: int) -> None: self.width = width self.height = height for d in self.displays: d.init(width, height) def show(self, buffer: list[str]) -> None: for d in self.displays: d.show(buffer) def clear(self) -> None: for d in self.displays: d.clear() def cleanup(self) -> None: for d in self.displays: d.cleanup()