Move colorization to the display layer

Color output isn't necessarily always going to be a terminal output
thing, and terminals don't always support the same escape codes (e.g. on
Windows). Thus, all colorization efforts are done in the Display rather
than in the Game.

Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
2021-11-28 17:37:37 -08:00
parent 2357757b23
commit c71077a8f3
4 changed files with 43 additions and 46 deletions

View File

@@ -1,7 +1,7 @@
import re
import sys
import termios
from typing import Optional, Sequence, TextIO, Tuple, TYPE_CHECKING
from agame.color import colorize
from agame.action import Action
from agame.dialog import DialogOption
from .display import Display
@@ -9,8 +9,44 @@ from .display import Display
if TYPE_CHECKING:
from agame.game import Game
__all__ = ("ANSIDisplay",)
ESC = "\u001b"
ANSI_MOVE_BOTTOM = f"{ESC}[999;0f"
ANSI_BOLD_COL = f"{ESC}[1m"
ANSI_ITALIC_COL = f"{ESC}[3m"
ANSI_INTEREST_COL = f"{ESC}[34;1m"
ANSI_SHADOW_COL = f"{ESC}[30;1m"
ANSI_RESET_COL = f"{ESC}[0m"
BOLD_PAT = re.compile(r"\*\*(.+?)\*\*", re.MULTILINE)
ITALIC_PAT = re.compile(r"//(.+?)//", re.MULTILINE)
INTEREST_PAT = re.compile(r"\(\((.+?)\)\)", re.MULTILINE)
SHADOW_PAT = re.compile(r"\{\{(.+?)\}\}", re.MULTILINE)
def colorize(text: str) -> str:
"""
Colorizes text for output on an ANSI terminal.
This will use escape codes to replace things.
Style guide:
((This)) is "interest" styling. This will make the text blue.
{{This}} is "shadow" styling. This will make the text a dark grey (or at
least, more subtle.)
"""
replacements = [
(INTEREST_PAT, ANSI_INTEREST_COL),
(SHADOW_PAT, ANSI_SHADOW_COL),
(BOLD_PAT, ANSI_BOLD_COL),
(ITALIC_PAT, ANSI_ITALIC_COL),
]
for (pat, col) in replacements:
text = pat.sub(col + r"\1" + ANSI_RESET_COL, text)
return text
class ANSIDisplay(Display):
@@ -47,6 +83,7 @@ class ANSIDisplay(Display):
self.clear()
def line(self, line: str = ""):
line = colorize(line)
self.stdout.write(line)
self.stdout.write("\n")