flake_edit/tui/components/confirm/
view.rs

1use ratatui::{
2    buffer::Buffer,
3    layout::Rect,
4    text::Span,
5    widgets::{Block, Borders, Paragraph, Widget, Wrap},
6};
7
8use crate::tui::components::footer::Footer;
9use crate::tui::helpers::{color_diff_lines, context_span, layouts};
10use crate::tui::style::{BORDER_STYLE, HIGHLIGHT_STYLE};
11
12/// Confirm widget that displays a diff and asks for confirmation
13pub struct Confirm<'a> {
14    diff: &'a str,
15    context: &'a str,
16}
17
18impl<'a> Confirm<'a> {
19    pub fn new(diff: &'a str, context: &'a str) -> Self {
20        Self { diff, context }
21    }
22}
23
24impl Widget for Confirm<'_> {
25    fn render(self, area: Rect, buf: &mut Buffer) {
26        let (content_area, footer_area) = layouts::content_with_footer(area);
27
28        let content = Paragraph::new(color_diff_lines(self.diff))
29            .block(
30                Block::default()
31                    .borders(Borders::TOP | Borders::BOTTOM)
32                    .border_style(BORDER_STYLE),
33            )
34            .wrap(Wrap { trim: false });
35        content.render(content_area, buf);
36
37        Footer::new(
38            vec![
39                context_span(self.context),
40                Span::raw(" Apply? "),
41                Span::styled(" y ", HIGHLIGHT_STYLE),
42                Span::raw("es "),
43                Span::styled(" n ", HIGHLIGHT_STYLE),
44                Span::raw("o "),
45                Span::styled(" b ", HIGHLIGHT_STYLE),
46                Span::raw("ack"),
47            ],
48            vec![],
49        )
50        .render(footer_area, buf);
51    }
52}
53
54#[cfg(test)]
55mod tests {
56    use super::*;
57    use ratatui::{Terminal, backend::TestBackend};
58
59    fn create_test_terminal(width: u16, height: u16) -> Terminal<TestBackend> {
60        let backend = TestBackend::new(width, height);
61        Terminal::new(backend).unwrap()
62    }
63
64    fn buffer_to_plain_text(terminal: &Terminal<TestBackend>) -> String {
65        let buffer = terminal.backend().buffer();
66        let mut lines = Vec::new();
67        for y in 0..buffer.area.height {
68            let mut line = String::new();
69            for x in 0..buffer.area.width {
70                line.push(buffer[(x, y)].symbol().chars().next().unwrap_or(' '));
71            }
72            lines.push(line.trim_end().to_string());
73        }
74        while lines.last().is_some_and(|l| l.is_empty()) {
75            lines.pop();
76        }
77        lines.join("\n")
78    }
79
80    #[test]
81    fn test_render_confirm() {
82        let mut terminal = create_test_terminal(80, 10);
83        let diff = r#"@@ -1,3 +1,3 @@
84 inputs = {
85-  nixpkgs.url = "github:nixos/nixpkgs";
86+  nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
87 };"#;
88
89        terminal
90            .draw(|frame| {
91                Confirm::new(diff, "Change").render(frame.area(), frame.buffer_mut());
92            })
93            .unwrap();
94
95        let output = buffer_to_plain_text(&terminal);
96        insta::assert_snapshot!(output);
97    }
98}