ratatui_toolkit/widgets/code_diff/widget/methods/helpers/
render_header.rs

1//! Render the file header bar for the diff widget.
2
3use ratatui::buffer::Buffer;
4use ratatui::layout::{Position, Rect};
5use ratatui::style::{Modifier, Style};
6
7use crate::widgets::code_diff::code_diff::CodeDiff;
8
9/// Renders the file header bar at the top of the diff widget.
10///
11/// The header shows:
12/// - File path (if available)
13/// - Stats (+N -M)
14///
15/// # Arguments
16///
17/// * `diff` - The diff widget to render
18/// * `area` - The area to render the header in
19/// * `buf` - The buffer to render to
20///
21/// # Returns
22///
23/// The number of rows used by the header (1 if rendered, 0 if no header needed)
24pub fn render_header(diff: &CodeDiff, area: Rect, buf: &mut Buffer) -> u16 {
25    if diff.file_path.is_none() && diff.hunks.is_empty() {
26        return 0;
27    }
28
29    if area.height == 0 {
30        return 0;
31    }
32
33    let theme = &diff.theme;
34    let header_bg = theme.background_panel;
35    let header_fg = theme.text;
36
37    let header_style = Style::default()
38        .bg(header_bg)
39        .fg(header_fg)
40        .add_modifier(Modifier::BOLD);
41
42    // Clear the header row
43    for x in area.x..area.x + area.width {
44        if let Some(cell) = buf.cell_mut(Position::new(x, area.y)) {
45            cell.set_style(header_style);
46            cell.set_char(' ');
47        }
48    }
49
50    // Render file path
51    let mut x = area.x + 1;
52    if let Some(ref path) = diff.file_path {
53        let path_style = Style::default()
54            .bg(header_bg)
55            .fg(theme.accent)
56            .add_modifier(Modifier::BOLD);
57
58        for ch in path.chars() {
59            if x >= area.x + area.width - 15 {
60                break;
61            }
62            if let Some(cell) = buf.cell_mut(Position::new(x, area.y)) {
63                cell.set_char(ch);
64                cell.set_style(path_style);
65            }
66            x += 1;
67        }
68    }
69
70    // Render stats on the right side
71    let stats = diff.stats_text();
72    let stats_x = area.x + area.width.saturating_sub(stats.len() as u16 + 2);
73
74    // Added count in success color (green)
75    let added_count = format!("+{}", diff.added_count());
76    let mut sx = stats_x;
77    for ch in added_count.chars() {
78        if sx < area.x + area.width {
79            if let Some(cell) = buf.cell_mut(Position::new(sx, area.y)) {
80                cell.set_char(ch);
81                cell.set_style(Style::default().bg(header_bg).fg(theme.diff.added));
82            }
83            sx += 1;
84        }
85    }
86
87    // Space
88    if sx < area.x + area.width {
89        if let Some(cell) = buf.cell_mut(Position::new(sx, area.y)) {
90            cell.set_char(' ');
91        }
92        sx += 1;
93    }
94
95    // Removed count in error color (red)
96    let removed_count = format!("-{}", diff.removed_count());
97    for ch in removed_count.chars() {
98        if sx < area.x + area.width {
99            if let Some(cell) = buf.cell_mut(Position::new(sx, area.y)) {
100                cell.set_char(ch);
101                cell.set_style(Style::default().bg(header_bg).fg(theme.diff.removed));
102            }
103            sx += 1;
104        }
105    }
106
107    1
108}