Skip to main content

hh_cli/cli/tui/
debug.rs

1use std::fs::{self, File};
2use std::io::Write;
3use std::path::PathBuf;
4
5use ratatui::{Terminal, backend::TestBackend};
6
7use super::app::ChatApp;
8use super::ui;
9
10const DEBUG_WIDTH: u16 = 120;
11const DEBUG_HEIGHT: u16 = 40;
12
13pub struct DebugRenderer {
14    terminal: Terminal<TestBackend>,
15    output_dir: PathBuf,
16    frame_count: usize,
17    last_buffer: Option<String>,
18}
19
20impl DebugRenderer {
21    pub fn new(output_dir: PathBuf) -> anyhow::Result<Self> {
22        fs::create_dir_all(&output_dir)?;
23        let backend = TestBackend::new(DEBUG_WIDTH, DEBUG_HEIGHT);
24        let terminal = Terminal::new(backend)?;
25        Ok(Self {
26            terminal,
27            output_dir,
28            frame_count: 0,
29            last_buffer: None,
30        })
31    }
32
33    pub fn render(&mut self, app: &ChatApp) -> anyhow::Result<()> {
34        self.terminal.draw(|f| {
35            ui::render_app(f, app);
36        })?;
37
38        // Get current buffer content
39        let current = self.buffer_to_string();
40
41        // Only dump if content changed
42        if self.last_buffer.as_ref() != Some(&current) {
43            self.dump_screen(&current)?;
44            self.frame_count += 1;
45            self.last_buffer = Some(current);
46        }
47
48        Ok(())
49    }
50
51    fn buffer_to_string(&self) -> String {
52        let buffer = self.terminal.backend().buffer();
53        let mut result = String::new();
54
55        for y in 0..DEBUG_HEIGHT {
56            let mut line = String::new();
57            for x in 0..DEBUG_WIDTH {
58                let cell = &buffer[(x, y)];
59                line.push_str(cell.symbol());
60            }
61            result.push_str(line.trim_end());
62            result.push('\n');
63        }
64
65        result
66    }
67
68    fn dump_screen(&self, content: &str) -> anyhow::Result<()> {
69        let filename = format!("screen-{:03}.txt", self.frame_count);
70        let path = self.output_dir.join(filename);
71
72        let mut file = File::create(&path)?;
73        write!(file, "{}", content)?;
74
75        Ok(())
76    }
77
78    pub fn output_dir(&self) -> &std::path::Path {
79        &self.output_dir
80    }
81
82    pub fn frame_count(&self) -> usize {
83        self.frame_count
84    }
85}