use rat_widget::msgdialog::MsgDialogState;
use ratatui_core::text::Line;
use crate::dialog::TEXT_WIDTH;
const TITLE: &str = "Error";
pub(crate) fn open(message: &str) -> MsgDialogState {
MsgDialogState::new_active(TITLE, wrap(message, TEXT_WIDTH))
}
fn wrap(text: &str, max_width: usize) -> String {
let mut wrapped = Vec::new();
for paragraph in text.split('\n') {
let mut current = String::new();
let mut current_width = 0;
for word in paragraph.split_whitespace() {
let word_width = Line::from(word).width();
if current.is_empty() {
current.push_str(word);
current_width = word_width;
} else if current_width + 1 + word_width <= max_width {
current.push(' ');
current.push_str(word);
current_width += 1 + word_width;
} else {
wrapped.push(current);
current = word.to_string();
current_width = word_width;
}
}
wrapped.push(current);
}
wrapped.join("\n")
}
#[cfg(test)]
mod tests {
use super::*;
use crate::dialog::testing::{REGION, picture, theme};
use crate::overlay::Overlay;
use ratatui_core::buffer::Buffer;
use ratatui_core::layout::Rect;
fn opened_over(dialog: &mut Overlay<MsgDialogState>) -> String {
let mut buffer = Buffer::empty(REGION);
crate::dialog::draw(REGION, &mut buffer, dialog, &theme());
picture(&buffer)
}
#[test]
fn the_error_dialog_carries_the_title_and_the_message() {
let mut dialog = Overlay::up(open("The file could not be read"));
let frame = opened_over(&mut dialog);
assert!(dialog.is_up(), "opening the error left the dialog down");
assert!(frame.contains(TITLE), "the dialog has no title: {frame:?}");
assert!(
frame.contains("The file could not be read"),
"the dialog does not carry the message: {frame:?}"
);
assert!(frame.contains("Ok"), "the dialog has no way out: {frame:?}");
}
#[test]
fn a_second_error_replaces_the_first() {
let mut dialog = Overlay::up(open("first failure"));
dialog.show(open("second failure"));
let frame = opened_over(&mut dialog);
assert!(
frame.contains("second failure"),
"the second message is not shown: {frame:?}"
);
assert!(
!frame.contains("first failure"),
"the first message is still shown: {frame:?}"
);
}
#[test]
fn a_long_error_is_wrapped_across_lines_without_horizontal_scrolling() {
let tall = Rect::new(0, 0, 40, 20);
let mut dialog = Overlay::up(open("This is a demonstration error, raised by Ctrl+E."));
let mut buffer = Buffer::empty(tall);
crate::dialog::draw(tall, &mut buffer, &mut dialog, &theme());
let frame = picture(&buffer);
assert!(
frame.contains("This is a demonstration error,"),
"the first wrapped line is missing: {frame:?}"
);
assert!(
frame.contains("raised by Ctrl+E."),
"the second wrapped line is missing: {frame:?}"
);
assert!(
!frame.contains('◄') && !frame.contains('►'),
"the dialog drew a horizontal scroll bar: {frame:?}"
);
}
}