datui_lib/widgets/ui/
section_rule.rs1use crate::render::context::RenderContext;
5use ratatui::buffer::Buffer;
6use ratatui::layout::Rect;
7use ratatui::style::{Modifier, Style};
8use ratatui::text::{Line, Span};
9use ratatui::widgets::{Paragraph, Widget};
10
11pub struct SectionRule<'a> {
14 pub title: &'a str,
15 pub chip: Option<&'a str>,
17}
18
19impl SectionRule<'_> {
20 pub fn render(&self, area: Rect, buf: &mut Buffer, ctx: &RenderContext) {
21 if area.height == 0 || area.width == 0 {
22 return;
23 }
24 let g = crate::glyphs::get();
25 let title_style = Style::default().fg(ctx.accent).add_modifier(Modifier::BOLD);
26 let rule_glyph = g.rule_h;
27 let rule_style = Style::default().fg(ctx.column_separator);
28
29 let mut spans = vec![Span::styled(self.title, title_style), Span::raw(" ")];
30 let mut used = crate::glyphs::display_width(self.title) + 1;
31 if let Some(chip) = self.chip {
32 let chip = format!(" {chip} ");
33 used += crate::glyphs::display_width(&chip) + 1;
34 spans.push(Span::styled(
35 chip,
36 Style::default().bg(ctx.controls_bg).fg(ctx.text_primary),
37 ));
38 spans.push(Span::raw(" "));
39 }
40 let rule_w = (area.width as usize).saturating_sub(used);
41 spans.push(Span::styled(rule_glyph.repeat(rule_w), rule_style));
42 Paragraph::new(Line::from(spans)).render(area, buf);
43 }
44}
45
46#[cfg(test)]
47mod tests {
48 use super::*;
49
50 fn render(rule: &SectionRule, width: u16) -> String {
51 let ctx = RenderContext::for_test();
52 let area = Rect::new(0, 0, width, 1);
53 let mut buf = Buffer::empty(area);
54 rule.render(area, &mut buf, &ctx);
55 (0..width)
56 .map(|x| buf[(x, 0)].symbol().to_string())
57 .collect()
58 }
59
60 #[test]
61 fn the_rule_runs_from_the_title_to_the_edge() {
62 let g = crate::glyphs::get();
63 let out = render(
64 &SectionRule {
65 title: "Format",
66 chip: None,
67 },
68 20,
69 );
70 assert_eq!(out, format!("Format {}", g.rule_h.repeat(13)));
71 }
72
73 #[test]
74 fn a_chip_sits_between_title_and_rule() {
75 let out = render(
76 &SectionRule {
77 title: "Format",
78 chip: Some("6"),
79 },
80 20,
81 );
82 assert!(out.starts_with("Format 6 "), "got {out:?}");
83 }
84
85 #[test]
88 fn the_rule_never_signals_focus() {
89 let g = crate::glyphs::get();
90 let ctx = RenderContext::for_test();
91 let area = Rect::new(0, 0, 20, 1);
92 let mut buf = Buffer::empty(area);
93 SectionRule {
94 title: "Sort",
95 chip: None,
96 }
97 .render(area, &mut buf, &ctx);
98 assert_eq!(buf[(0, 0)].fg, ctx.accent);
99 assert_eq!(buf[(19, 0)].symbol(), g.rule_h);
100 assert_eq!(buf[(19, 0)].fg, ctx.column_separator);
101 }
102}