refactor(display): extract shared rendering logic into renderer.py
- Add renderer.py with parse_ansi(), get_default_font_path(), render_to_pil() - Update KittyDisplay and SixelDisplay to use shared renderer - Enhance parse_ansi to handle full ANSI color codes (4-bit, 256-color) - Update tests to use shared renderer functions
This commit is contained in:
@@ -4,6 +4,8 @@ Pygame display backend - renders to a native application window.
|
||||
|
||||
import time
|
||||
|
||||
from engine.display.renderer import parse_ansi
|
||||
|
||||
|
||||
class PygameDisplay:
|
||||
"""Pygame display backend - renders to native window.
|
||||
@@ -141,10 +143,10 @@ class PygameDisplay:
|
||||
if row_idx >= self.height:
|
||||
break
|
||||
|
||||
tokens = self._parse_ansi(line)
|
||||
tokens = parse_ansi(line)
|
||||
x_pos = 0
|
||||
|
||||
for text, fg, bg in tokens:
|
||||
for text, fg, bg, _bold in tokens:
|
||||
if not text:
|
||||
continue
|
||||
|
||||
@@ -168,72 +170,6 @@ class PygameDisplay:
|
||||
chars_in = sum(len(line) for line in buffer)
|
||||
monitor.record_effect("pygame_display", elapsed_ms, chars_in, chars_in)
|
||||
|
||||
def _parse_ansi(
|
||||
self, text: str
|
||||
) -> list[tuple[str, tuple[int, int, int], tuple[int, int, int]]]:
|
||||
"""Parse ANSI text into tokens with fg/bg colors."""
|
||||
tokens = []
|
||||
current_text = ""
|
||||
fg = (204, 204, 204)
|
||||
bg = (0, 0, 0)
|
||||
i = 0
|
||||
|
||||
ANSI_COLORS = {
|
||||
0: (0, 0, 0),
|
||||
1: (205, 49, 49),
|
||||
2: (13, 188, 121),
|
||||
3: (229, 229, 16),
|
||||
4: (36, 114, 200),
|
||||
5: (188, 63, 188),
|
||||
6: (17, 168, 205),
|
||||
7: (229, 229, 229),
|
||||
8: (102, 102, 102),
|
||||
9: (241, 76, 76),
|
||||
10: (35, 209, 139),
|
||||
11: (245, 245, 67),
|
||||
12: (59, 142, 234),
|
||||
13: (214, 112, 214),
|
||||
14: (41, 184, 219),
|
||||
15: (255, 255, 255),
|
||||
}
|
||||
|
||||
while i < len(text):
|
||||
char = text[i]
|
||||
|
||||
if char == "\x1b" and i + 1 < len(text) and text[i + 1] == "[":
|
||||
if current_text:
|
||||
tokens.append((current_text, fg, bg))
|
||||
current_text = ""
|
||||
|
||||
i += 2
|
||||
code = ""
|
||||
while i < len(text):
|
||||
c = text[i]
|
||||
if c.isalpha():
|
||||
break
|
||||
code += c
|
||||
i += 1
|
||||
|
||||
if code:
|
||||
codes = code.split(";")
|
||||
for c in codes:
|
||||
if c == "0":
|
||||
fg = (204, 204, 204)
|
||||
bg = (0, 0, 0)
|
||||
elif c.isdigit():
|
||||
color_idx = int(c)
|
||||
if color_idx in ANSI_COLORS:
|
||||
fg = ANSI_COLORS[color_idx]
|
||||
i += 1
|
||||
else:
|
||||
current_text += char
|
||||
i += 1
|
||||
|
||||
if current_text:
|
||||
tokens.append((current_text, fg, bg))
|
||||
|
||||
return tokens
|
||||
|
||||
def clear(self) -> None:
|
||||
if self._screen and self._pygame:
|
||||
self._screen.fill((0, 0, 0))
|
||||
|
||||
Reference in New Issue
Block a user