summaryrefslogtreecommitdiff
path: root/src/render.rs
blob: a0cb2345a44fbfc8cc8b2e7db8c854a092921c48 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
use std::io;
use ratatui::{
    layout::{Constraint, Direction, Layout},
    style::{Color, Style},
    text::{Line, Span},
    widgets::{Block, Borders, Paragraph},
    Terminal,
    prelude::Alignment,
};

pub fn draw(terminal: &mut Terminal<impl ratatui::backend::Backend>, data: &[u8], cursor: usize, filename: &str) -> io::Result<()> {
    terminal.draw(|frame| {
        let size = frame.size();
        let layout = Layout::default()
            .direction(Direction::Vertical)
            .constraints([Constraint::Min(1), Constraint::Length(1)])
            .split(size);

        let lines: Vec<Line> = data.chunks(16).enumerate().map(|(i, chunk)| {
            let addr = Span::raw(format!("{:08x} │ ", i * 16));
            let mut hex: Vec<Span> = Vec::new();
            let mut ascii_repr = String::new();

            for (j, &byte) in chunk.iter().enumerate() {
                let hex_str = format!("{:02x}", byte);
                let index = i * 32 + j * 2;

                for (k, ch) in hex_str.chars().enumerate() {
                    let cur_idx = index + k;
                    let style = if cur_idx == cursor {
                        Style::default().bg(Color::White).fg(Color::Black)
                    } else {
                        Style::default()
                    };
                    hex.push(Span::styled(ch.to_string(), style));
                }

                if j < 15 {
                    let space = if j % 4 == 3 { "   " } else { " " };
                    hex.push(Span::raw(space));
                }

                ascii_repr.push(if byte.is_ascii_graphic() || byte == b' ' { byte as char } else { '.' });
            }

            let missing_bytes = 16 - chunk.len();
            let padding = missing_bytes * 3;
            let spaces = " ".repeat(padding);

            let ascii = Span::raw(format!("{} │ {}", spaces, ascii_repr));

            Line::from(vec![addr]
                .into_iter()
                .chain(hex)
                .chain(std::iter::once(ascii))
                .collect::<Vec<_>>())
        }).collect();

        frame.render_widget(Paragraph::new(lines).block(Block::default().borders(Borders::ALL)), layout[0]);

        let progress = if data.is_empty() { 100 } else { (cursor / 2 * 100) / data.len() };
        let status_text = format!("{} \t 0x{:08x} \t {:3}%", filename, cursor / 2, progress);
        let status_bar = Paragraph::new(Line::from(Span::raw(status_text))).alignment(Alignment::Center);
        frame.render_widget(status_bar, layout[1]);
    })?;
    Ok(())
}