Skip to main content

manabrew_engine/
game_log_formatter.rs

1use crate::game_log_entry::GameLogEntry;
2use crate::game_log_entry_type::GameLogEntryType;
3
4/// Log formatter interface.
5/// Mirrors Java `GameLogFormatter`.
6pub trait GameLogFormatter: Send + Sync {
7    fn format(&self, entry: &GameLogEntry) -> String;
8}
9
10/// Console-oriented formatter with stable indentation and category labels.
11pub struct ConsoleGameLogFormatter;
12
13impl ConsoleGameLogFormatter {
14    const ANSI_RESET: &'static str = "\x1b[0m";
15    const ANSI_WHITE: &'static str = "\x1b[37m";
16    const ANSI_GREY: &'static str = "\x1b[90m";
17    const ANSI_LIGHT_GREY: &'static str = "\x1b[37m";
18    const ANSI_GREEN: &'static str = "\x1b[32m";
19    const ANSI_YELLOW: &'static str = "\x1b[33m";
20    const ANSI_BLUE: &'static str = "\x1b[34m";
21
22    fn indent_prefix(level: usize) -> String {
23        let mut out = String::new();
24        for ancestor_depth in 0..level {
25            out.push_str(Self::color_for_depth(ancestor_depth));
26            out.push('|');
27            out.push_str(Self::ANSI_RESET);
28            out.push_str("  ");
29        }
30        out
31    }
32
33    fn label(entry_type: GameLogEntryType) -> &'static str {
34        match entry_type {
35            GameLogEntryType::TurnBegin => "TURN",
36            GameLogEntryType::TurnSkip => "TURN",
37            GameLogEntryType::PhaseBegin => "PHASE",
38            GameLogEntryType::PriorityWaiting => "WAIT",
39            GameLogEntryType::PriorityResponse => "RESP",
40            GameLogEntryType::PriorityPass => "PASS",
41            GameLogEntryType::StackPush => "STACK",
42            GameLogEntryType::StackResolve => "STACK",
43            GameLogEntryType::Mulligan => "MULL",
44            GameLogEntryType::Info => "INFO",
45        }
46    }
47
48    fn color_for_depth(depth: usize) -> &'static str {
49        match depth % 4 {
50            0 => Self::ANSI_WHITE,
51            1 => Self::ANSI_YELLOW,
52            2 => Self::ANSI_BLUE,
53            _ => Self::ANSI_GREY,
54        }
55    }
56
57    fn color_for_entry(entry_type: GameLogEntryType) -> &'static str {
58        match entry_type {
59            GameLogEntryType::TurnBegin | GameLogEntryType::TurnSkip => Self::ANSI_WHITE,
60            GameLogEntryType::PhaseBegin => Self::ANSI_YELLOW,
61            GameLogEntryType::PriorityPass => Self::ANSI_GREY,
62            GameLogEntryType::PriorityResponse => Self::ANSI_GREEN,
63            GameLogEntryType::StackPush | GameLogEntryType::StackResolve => Self::ANSI_BLUE,
64            GameLogEntryType::Info => Self::ANSI_LIGHT_GREY,
65            _ => Self::ANSI_GREEN,
66        }
67    }
68}
69
70impl GameLogFormatter for ConsoleGameLogFormatter {
71    fn format(&self, entry: &GameLogEntry) -> String {
72        let indent = Self::indent_prefix(entry.indent);
73        let line_color = Self::color_for_entry(entry.entry_type);
74        let payload = format!("-- [{}] {}", Self::label(entry.entry_type), entry.message);
75        format!("{indent}{line_color}{payload}{}", Self::ANSI_RESET)
76    }
77}