diff options
author | Theodore Dubois <tblodt@icloud.com> | 2019-04-28 06:24:58 -0700 |
---|---|---|
committer | Christian Duerr <chrisduerr@users.noreply.github.com> | 2019-04-28 13:24:58 +0000 |
commit | dbd8538762ef8968a493e1bf996e8693479ca783 (patch) | |
tree | 32ac2a6a5e01238a272d4ba534551d2e42903c7a /src/message_bar.rs | |
parent | 9c6d12ea2c863ba76015bdedc00db13b7307725a (diff) | |
download | alacritty-dbd8538762ef8968a493e1bf996e8693479ca783.tar.gz alacritty-dbd8538762ef8968a493e1bf996e8693479ca783.zip |
Split alacritty into a separate crates
The crate containing the entry point is called alacritty, and the crate
containing everything else is called alacritty_terminal.
Diffstat (limited to 'src/message_bar.rs')
-rw-r--r-- | src/message_bar.rs | 473 |
1 files changed, 0 insertions, 473 deletions
diff --git a/src/message_bar.rs b/src/message_bar.rs deleted file mode 100644 index 8883dcb0..00000000 --- a/src/message_bar.rs +++ /dev/null @@ -1,473 +0,0 @@ -// Copyright 2016 Joe Wilm, The Alacritty Project Contributors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crossbeam_channel::{Receiver, Sender}; - -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, - topic: Option<String>, -} - -impl Message { - /// Create a new message - pub fn new(text: String, color: Rgb) -> Message { - Message { text, color, topic: 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 topic - #[inline] - pub fn topic(&self) -> Option<&String> { - self.topic.as_ref() - } - - /// Update the message topic - #[inline] - pub fn set_topic(&mut self, topic: String) { - self.topic = Some(topic); - } - - /// 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)] -pub struct MessageBuffer { - current: Option<Message>, - messages: Receiver<Message>, - tx: Sender<Message>, -} - -impl MessageBuffer { - /// Create new message buffer - pub fn new() -> MessageBuffer { - let (tx, messages) = crossbeam_channel::unbounded(); - MessageBuffer { current: None, messages, tx } - } - - /// Check if there are any messages queued - #[inline] - pub fn is_empty(&self) -> bool { - self.current.is_none() - } - - /// Current message - #[inline] - pub fn message(&mut self) -> Option<Message> { - if let Some(current) = &self.current { - Some(current.clone()) - } else { - self.current = self.messages.try_recv().ok(); - self.current.clone() - } - } - - /// Channel for adding new messages - #[inline] - pub fn tx(&self) -> Sender<Message> { - self.tx.clone() - } - - /// Remove the currently visible message - #[inline] - pub fn pop(&mut self) { - // Remove all duplicates - for msg in self - .messages - .try_iter() - .take(self.messages.len()) - .filter(|m| Some(m) != self.current.as_ref()) - { - let _ = self.tx.send(msg); - } - - // Remove the message itself - self.current = self.messages.try_recv().ok(); - } - - /// Remove all messages with a specific topic - #[inline] - pub fn remove_topic(&mut self, topic: &str) { - // Filter messages currently pending - for msg in self - .messages - .try_iter() - .take(self.messages.len()) - .filter(|m| m.topic().map(String::as_str) != Some(topic)) - { - let _ = self.tx.send(msg); - } - - // Remove the currently active message - self.current = self.messages.try_recv().ok(); - } -} - -impl Default for MessageBuffer { - fn default() -> MessageBuffer { - MessageBuffer::new() - } -} - -#[cfg(test)] -mod test { - 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.tx().send(Message::new(input.into(), color::RED)).unwrap(); - 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.tx().send(Message::new(input.into(), color::RED)).unwrap(); - 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.tx().send(Message::new(input.into(), color::RED)).unwrap(); - 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.tx().send(Message::new(input.into(), color::RED)).unwrap(); - 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.tx().send(Message::new(input.into(), color::RED)).unwrap(); - 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.tx().send(Message::new(input.into(), color::RED)).unwrap(); - 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.tx().send(Message::new(input.into(), color::RED)).unwrap(); - 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.tx().send(Message::new(input.into(), color::RED)).unwrap(); - 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.tx().send(Message::new(input.into(), color::RED)).unwrap(); - 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_topic() { - 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_topic("topic".into()); - } - message_buffer.tx().send(msg).unwrap(); - } - - message_buffer.remove_topic("topic"); - - // 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.tx().send(one.clone()).unwrap(); - let two = Message::new(String::from("two"), color::YELLOW); - message_buffer.tx().send(two.clone()).unwrap(); - - 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.tx().send(Message::new(input.into(), color::RED)).unwrap(); - 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.tx().send(msg).unwrap(); - } - message_buffer.tx().send(Message::new(String::from("other"), color::RED)).unwrap(); - message_buffer.tx().send(Message::new(String::from("test"), color::YELLOW)).unwrap(); - 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); - } -} |