""" Null/headless display backend. """ import time class NullDisplay: """Headless/null display - discards all output. This display does nothing - useful for headless benchmarking or when no display output is needed. Captures last buffer for testing purposes. """ width: int = 80 height: int = 24 _last_buffer: list[str] | None = None def __init__(self): self._last_buffer = None def init(self, width: int, height: int, reuse: bool = False) -> None: """Initialize display with dimensions. Args: width: Terminal width in characters height: Terminal height in rows reuse: Ignored for NullDisplay (no resources to reuse) """ self.width = width self.height = height self._last_buffer = None def show(self, buffer: list[str], border: bool = False) -> None: import sys from engine.display import get_monitor, render_border # Get FPS for border (if available) fps = 0.0 frame_time = 0.0 monitor = get_monitor() if monitor: stats = monitor.get_stats() avg_ms = stats.get("pipeline", {}).get("avg_ms", 0) if stats else 0 frame_count = stats.get("frame_count", 0) if stats else 0 if avg_ms and frame_count > 0: fps = 1000.0 / avg_ms frame_time = avg_ms # Apply border if requested (same as terminal display) if border: buffer = render_border(buffer, self.width, self.height, fps, frame_time) self._last_buffer = buffer # For debugging: print first few frames to stdout if hasattr(self, "_frame_count"): self._frame_count += 1 else: self._frame_count = 0 # Only print first 5 frames or every 10th frame if self._frame_count <= 5 or self._frame_count % 10 == 0: sys.stdout.write("\n" + "=" * 80 + "\n") sys.stdout.write( f"Frame {self._frame_count} (buffer height: {len(buffer)})\n" ) sys.stdout.write("=" * 80 + "\n") for i, line in enumerate(buffer[:30]): # Show first 30 lines sys.stdout.write(f"{i:2}: {line}\n") if len(buffer) > 30: sys.stdout.write(f"... ({len(buffer) - 30} more lines)\n") sys.stdout.flush() 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 def get_dimensions(self) -> tuple[int, int]: """Get current dimensions. Returns: (width, height) in character cells """ return (self.width, self.height) def is_quit_requested(self) -> bool: """Check if quit was requested (optional protocol method).""" return False def clear_quit_request(self) -> None: """Clear quit request (optional protocol method).""" pass