diff options
Diffstat (limited to 'alacritty_terminal/src/message_bar.rs')
-rw-r--r-- | alacritty_terminal/src/message_bar.rs | 433 |
1 files changed, 0 insertions, 433 deletions
diff --git a/alacritty_terminal/src/message_bar.rs b/alacritty_terminal/src/message_bar.rs deleted file mode 100644 index 240581ff..00000000 --- a/alacritty_terminal/src/message_bar.rs +++ /dev/null @@ -1,433 +0,0 @@ -use std::collections::VecDeque; - -use crate::term::color::Rgb; -use crate::term::SizeInfo; - -pub const CLOSE_BUTTON_TEXT: &str = "[X]"; -const CLOSE_BUTTON_PADDING: usize = 1; -const MIN_FREE_LINES: usize = 3; -const TRUNCATED_MESSAGE: &str = "[MESSAGE TRUNCATED]"; - -/// Message for display in the MessageBuffer. -#[derive(Debug, Eq, PartialEq, Clone)] -pub struct Message { - text: String, - color: Rgb, - target: Option<String>, -} - -impl Message { - /// Create a new message. - pub fn new(text: String, color: Rgb) -> Message { - Message { text, color, target: None } - } - - /// Formatted message text lines. - pub fn text(&self, size_info: &SizeInfo) -> Vec<String> { - let num_cols = size_info.cols().0; - let max_lines = size_info.lines().saturating_sub(MIN_FREE_LINES); - let button_len = CLOSE_BUTTON_TEXT.len(); - - // Split line to fit the screen. - let mut lines = Vec::new(); - let mut line = String::new(); - for c in self.text.trim().chars() { - if c == '\n' - || line.len() == num_cols - // Keep space in first line for button. - || (lines.is_empty() - && num_cols >= button_len - && line.len() == num_cols.saturating_sub(button_len + CLOSE_BUTTON_PADDING)) - { - // Attempt to wrap on word boundaries. - if let (Some(index), true) = (line.rfind(char::is_whitespace), c != '\n') { - let split = line.split_off(index + 1); - line.pop(); - lines.push(Self::pad_text(line, num_cols)); - line = split - } else { - lines.push(Self::pad_text(line, num_cols)); - line = String::new(); - } - } - - if c != '\n' { - line.push(c); - } - } - lines.push(Self::pad_text(line, num_cols)); - - // Truncate output if it's too long. - if lines.len() > max_lines { - lines.truncate(max_lines); - if TRUNCATED_MESSAGE.len() <= num_cols { - if let Some(line) = lines.iter_mut().last() { - *line = Self::pad_text(TRUNCATED_MESSAGE.into(), num_cols); - } - } - } - - // Append close button to first line. - if button_len <= num_cols { - if let Some(line) = lines.get_mut(0) { - line.truncate(num_cols - button_len); - line.push_str(CLOSE_BUTTON_TEXT); - } - } - - lines - } - - /// Message color. - #[inline] - pub fn color(&self) -> Rgb { - self.color - } - - /// Message target. - #[inline] - pub fn target(&self) -> Option<&String> { - self.target.as_ref() - } - - /// Update the message target. - #[inline] - pub fn set_target(&mut self, target: String) { - self.target = Some(target); - } - - /// Right-pad text to fit a specific number of columns. - #[inline] - fn pad_text(mut text: String, num_cols: usize) -> String { - let padding_len = num_cols.saturating_sub(text.len()); - text.extend(vec![' '; padding_len]); - text - } -} - -/// Storage for message bar. -#[derive(Debug, Default)] -pub struct MessageBuffer { - messages: VecDeque<Message>, -} - -impl MessageBuffer { - /// Create new message buffer. - pub fn new() -> MessageBuffer { - MessageBuffer { messages: VecDeque::new() } - } - - /// Check if there are any messages queued. - #[inline] - pub fn is_empty(&self) -> bool { - self.messages.is_empty() - } - - /// Current message. - #[inline] - pub fn message(&self) -> Option<&Message> { - self.messages.front() - } - - /// Remove the currently visible message. - #[inline] - pub fn pop(&mut self) { - // Remove the message itself. - let msg = self.messages.pop_front(); - - // Remove all duplicates. - if let Some(msg) = msg { - self.messages = self.messages.drain(..).filter(|m| m != &msg).collect(); - } - } - - /// Remove all messages with a specific target. - #[inline] - pub fn remove_target(&mut self, target: &str) { - self.messages = self - .messages - .drain(..) - .filter(|m| m.target().map(String::as_str) != Some(target)) - .collect(); - } - - /// Add a new message to the queue. - #[inline] - pub fn push(&mut self, message: Message) { - self.messages.push_back(message); - } -} - -#[cfg(test)] -mod tests { - use super::{Message, MessageBuffer, MIN_FREE_LINES}; - use crate::term::{color, SizeInfo}; - - #[test] - fn appends_close_button() { - let input = "a"; - let mut message_buffer = MessageBuffer::new(); - message_buffer.push(Message::new(input.into(), color::RED)); - let size = SizeInfo { - width: 7., - height: 10., - cell_width: 1., - cell_height: 1., - padding_x: 0., - padding_y: 0., - dpr: 0., - }; - - let lines = message_buffer.message().unwrap().text(&size); - - assert_eq!(lines, vec![String::from("a [X]")]); - } - - #[test] - fn multiline_close_button_first_line() { - let input = "fo\nbar"; - let mut message_buffer = MessageBuffer::new(); - message_buffer.push(Message::new(input.into(), color::RED)); - let size = SizeInfo { - width: 6., - height: 10., - cell_width: 1., - cell_height: 1., - padding_x: 0., - padding_y: 0., - dpr: 0., - }; - - let lines = message_buffer.message().unwrap().text(&size); - - assert_eq!(lines, vec![String::from("fo [X]"), String::from("bar ")]); - } - - #[test] - fn splits_on_newline() { - let input = "a\nb"; - let mut message_buffer = MessageBuffer::new(); - message_buffer.push(Message::new(input.into(), color::RED)); - let size = SizeInfo { - width: 6., - height: 10., - cell_width: 1., - cell_height: 1., - padding_x: 0., - padding_y: 0., - dpr: 0., - }; - - let lines = message_buffer.message().unwrap().text(&size); - - assert_eq!(lines.len(), 2); - } - - #[test] - fn splits_on_length() { - let input = "foobar1"; - let mut message_buffer = MessageBuffer::new(); - message_buffer.push(Message::new(input.into(), color::RED)); - let size = SizeInfo { - width: 6., - height: 10., - cell_width: 1., - cell_height: 1., - padding_x: 0., - padding_y: 0., - dpr: 0., - }; - - let lines = message_buffer.message().unwrap().text(&size); - - assert_eq!(lines.len(), 2); - } - - #[test] - fn empty_with_shortterm() { - let input = "foobar"; - let mut message_buffer = MessageBuffer::new(); - message_buffer.push(Message::new(input.into(), color::RED)); - let size = SizeInfo { - width: 6., - height: 0., - cell_width: 1., - cell_height: 1., - padding_x: 0., - padding_y: 0., - dpr: 0., - }; - - let lines = message_buffer.message().unwrap().text(&size); - - assert_eq!(lines.len(), 0); - } - - #[test] - fn truncates_long_messages() { - let input = "hahahahahahahahahahaha truncate this because it's too long for the term"; - let mut message_buffer = MessageBuffer::new(); - message_buffer.push(Message::new(input.into(), color::RED)); - let size = SizeInfo { - width: 22., - height: (MIN_FREE_LINES + 2) as f32, - cell_width: 1., - cell_height: 1., - padding_x: 0., - padding_y: 0., - dpr: 0., - }; - - let lines = message_buffer.message().unwrap().text(&size); - - assert_eq!(lines, vec![ - String::from("hahahahahahahahaha [X]"), - String::from("[MESSAGE TRUNCATED] ") - ]); - } - - #[test] - fn hide_button_when_too_narrow() { - let input = "ha"; - let mut message_buffer = MessageBuffer::new(); - message_buffer.push(Message::new(input.into(), color::RED)); - let size = SizeInfo { - width: 2., - height: 10., - cell_width: 1., - cell_height: 1., - padding_x: 0., - padding_y: 0., - dpr: 0., - }; - - let lines = message_buffer.message().unwrap().text(&size); - - assert_eq!(lines, vec![String::from("ha")]); - } - - #[test] - fn hide_truncated_when_too_narrow() { - let input = "hahahahahahahahaha"; - let mut message_buffer = MessageBuffer::new(); - message_buffer.push(Message::new(input.into(), color::RED)); - let size = SizeInfo { - width: 2., - height: (MIN_FREE_LINES + 2) as f32, - cell_width: 1., - cell_height: 1., - padding_x: 0., - padding_y: 0., - dpr: 0., - }; - - let lines = message_buffer.message().unwrap().text(&size); - - assert_eq!(lines, vec![String::from("ha"), String::from("ha")]); - } - - #[test] - fn add_newline_for_button() { - let input = "test"; - let mut message_buffer = MessageBuffer::new(); - message_buffer.push(Message::new(input.into(), color::RED)); - let size = SizeInfo { - width: 5., - height: 10., - cell_width: 1., - cell_height: 1., - padding_x: 0., - padding_y: 0., - dpr: 0., - }; - - let lines = message_buffer.message().unwrap().text(&size); - - assert_eq!(lines, vec![String::from("t [X]"), String::from("est ")]); - } - - #[test] - fn remove_target() { - let mut message_buffer = MessageBuffer::new(); - for i in 0..10 { - let mut msg = Message::new(i.to_string(), color::RED); - if i % 2 == 0 && i < 5 { - msg.set_target("target".into()); - } - message_buffer.push(msg); - } - - message_buffer.remove_target("target"); - - // Count number of messages. - let mut num_messages = 0; - while message_buffer.message().is_some() { - num_messages += 1; - message_buffer.pop(); - } - - assert_eq!(num_messages, 7); - } - - #[test] - fn pop() { - let mut message_buffer = MessageBuffer::new(); - let one = Message::new(String::from("one"), color::RED); - message_buffer.push(one.clone()); - let two = Message::new(String::from("two"), color::YELLOW); - message_buffer.push(two.clone()); - - assert_eq!(message_buffer.message(), Some(&one)); - - message_buffer.pop(); - - assert_eq!(message_buffer.message(), Some(&two)); - } - - #[test] - fn wrap_on_words() { - let input = "a\nbc defg"; - let mut message_buffer = MessageBuffer::new(); - message_buffer.push(Message::new(input.into(), color::RED)); - let size = SizeInfo { - width: 5., - height: 10., - cell_width: 1., - cell_height: 1., - padding_x: 0., - padding_y: 0., - dpr: 0., - }; - - let lines = message_buffer.message().unwrap().text(&size); - - assert_eq!(lines, vec![ - String::from("a [X]"), - String::from("bc "), - String::from("defg ") - ]); - } - - #[test] - fn remove_duplicates() { - let mut message_buffer = MessageBuffer::new(); - for _ in 0..10 { - let msg = Message::new(String::from("test"), color::RED); - message_buffer.push(msg); - } - message_buffer.push(Message::new(String::from("other"), color::RED)); - message_buffer.push(Message::new(String::from("test"), color::YELLOW)); - let _ = message_buffer.message(); - - message_buffer.pop(); - - // Count number of messages. - let mut num_messages = 0; - while message_buffer.message().is_some() { - num_messages += 1; - message_buffer.pop(); - } - - assert_eq!(num_messages, 2); - } -} |