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

1//! Render a single diff line.
2
3use ratatui::buffer::Buffer;
4use ratatui::layout::Position;
5use ratatui::style::Style;
6
7use crate::services::theme::AppTheme;
8use crate::widgets::code_diff::diff_config::DiffConfig;
9use crate::widgets::code_diff::diff_line::DiffLine;
10use crate::widgets::code_diff::enums::DiffLineKind;
11
12/// Renders a single diff line content.
13///
14/// # Arguments
15///
16/// * `line` - The diff line to render (None for empty filler)
17/// * `config` - Display configuration
18/// * `theme` - Application theme for colors
19/// * `x` - Starting x position (after line number)
20/// * `y` - Y position
21/// * `width` - Available width for content
22/// * `buf` - The buffer to render to
23/// * `is_left` - Whether this is the left (old) or right (new) panel
24pub fn render_line(
25    line: Option<&DiffLine>,
26    config: &DiffConfig,
27    theme: &AppTheme,
28    x: u16,
29    y: u16,
30    width: u16,
31    buf: &mut Buffer,
32    is_left: bool,
33) {
34    let (bg_color, fg_color, prefix) = match line.map(|l| l.kind) {
35        Some(DiffLineKind::Added) => (theme.diff.added_bg, theme.diff.added, '+'),
36        Some(DiffLineKind::Removed) => (theme.diff.removed_bg, theme.diff.removed, '-'),
37        Some(DiffLineKind::Context) => (theme.background, theme.text, ' '),
38        Some(DiffLineKind::HunkHeader) => (theme.background_panel, theme.text_muted, '@'),
39        None => {
40            // Empty filler - use the diff background colors
41            let filler_bg = if is_left {
42                theme.diff.removed_bg
43            } else {
44                theme.diff.added_bg
45            };
46            (filler_bg, theme.text_muted, ' ')
47        }
48    };
49
50    let style = Style::default().bg(bg_color).fg(fg_color);
51
52    // Clear the line area with background
53    for col in x..x + width {
54        if let Some(cell) = buf.cell_mut(Position::new(col, y)) {
55            cell.set_char(' ');
56            cell.set_style(style);
57        }
58    }
59
60    // Render gutter prefix
61    let mut current_x = x;
62    if config.gutter_width > 0 {
63        if let Some(cell) = buf.cell_mut(Position::new(current_x, y)) {
64            cell.set_char(prefix);
65            cell.set_style(style);
66        }
67        current_x += 1;
68
69        // Padding after prefix
70        for _ in 1..config.gutter_width {
71            if current_x < x + width {
72                if let Some(cell) = buf.cell_mut(Position::new(current_x, y)) {
73                    cell.set_char(' ');
74                    cell.set_style(style);
75                }
76                current_x += 1;
77            }
78        }
79    }
80
81    // Render content
82    if let Some(line) = line {
83        for ch in line.content.chars() {
84            if current_x >= x + width {
85                break;
86            }
87            if let Some(cell) = buf.cell_mut(Position::new(current_x, y)) {
88                cell.set_char(ch);
89                cell.set_style(style);
90            }
91            current_x += 1;
92        }
93    }
94}