aboutsummaryrefslogtreecommitdiff
path: root/src/message_bar.rs
diff options
context:
space:
mode:
authorTheodore Dubois <tblodt@icloud.com>2019-04-28 06:24:58 -0700
committerChristian Duerr <chrisduerr@users.noreply.github.com>2019-04-28 13:24:58 +0000
commitdbd8538762ef8968a493e1bf996e8693479ca783 (patch)
tree32ac2a6a5e01238a272d4ba534551d2e42903c7a /src/message_bar.rs
parent9c6d12ea2c863ba76015bdedc00db13b7307725a (diff)
downloadalacritty-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.rs473
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);
- }
-}