git_tailor/views/
dialog.rs1use ratatui::{
18 Frame,
19 layout::{Alignment, Rect},
20 style::{Color, Style},
21 text::Line,
22 widgets::{Block, Borders, Clear, Paragraph, Wrap},
23};
24
25pub fn render_centered_dialog(
30 frame: &mut Frame,
31 title: &str,
32 border_color: Color,
33 preferred_width: u16,
34 lines: Vec<Line>,
35) {
36 let area = frame.area();
37 let dialog_width = preferred_width.min(area.width.saturating_sub(4));
38 let dialog_height = (lines.len() as u16 + 2).min(area.height.saturating_sub(2));
39 let dialog_x = area.x + (area.width.saturating_sub(dialog_width)) / 2;
40 let dialog_y = area.y + (area.height.saturating_sub(dialog_height)) / 2;
41 let dialog_area = Rect {
42 x: dialog_x,
43 y: dialog_y,
44 width: dialog_width,
45 height: dialog_height,
46 };
47
48 frame.render_widget(Clear, dialog_area);
49 frame.render_widget(
50 Paragraph::new(lines)
51 .block(
52 Block::default()
53 .title(title)
54 .borders(Borders::ALL)
55 .border_style(Style::default().fg(border_color))
56 .style(Style::default().bg(Color::Black)),
57 )
58 .alignment(Alignment::Left)
59 .wrap(Wrap { trim: false }),
60 dialog_area,
61 );
62}
63
64pub fn inner_width(preferred_width: u16, area_width: u16) -> usize {
69 preferred_width
70 .min(area_width.saturating_sub(4))
71 .saturating_sub(2) as usize
72}
73
74pub fn wrap_text(text: &str, width: usize) -> Vec<String> {
80 if width == 0 || text.is_empty() {
81 return vec![text.to_string()];
82 }
83 let mut result = Vec::new();
84 let mut remaining = text;
85 while remaining.chars().count() > width {
86 let byte_limit = remaining
87 .char_indices()
88 .nth(width)
89 .map(|(i, _)| i)
90 .unwrap_or(remaining.len());
91 let break_at = remaining[..byte_limit]
92 .rfind(' ')
93 .filter(|&p| p > 0)
94 .unwrap_or(byte_limit);
95 result.push(remaining[..break_at].to_string());
96 remaining = remaining[break_at..].trim_start_matches(' ');
97 }
98 result.push(remaining.to_string());
99 result
100}
101
102pub fn wrap_text_indent(text: &str, width: usize) -> Vec<String> {
106 let indent: String = text.chars().take_while(|c| *c == ' ').collect();
107 let chunks = wrap_text(text, width);
108 if chunks.len() <= 1 || indent.is_empty() {
109 return chunks;
110 }
111 let mut result = vec![chunks[0].clone()];
112 for chunk in &chunks[1..] {
113 result.push(format!("{indent}{chunk}"));
114 }
115 result
116}