summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md1
-rw-r--r--alacritty/src/message_bar.rs68
2 files changed, 57 insertions, 12 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a7f130a2..4da3e707 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -47,6 +47,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- IME window position with fullwidth characters in the search bar
- Selection expanding over 2 characters when scrolled in history with fullwidth characters in use
- Selection scrolling not starting when mouse is over the message bar
+- Incorrect text width calculation in message bar when the message contains multibyte characters
## 0.5.0
diff --git a/alacritty/src/message_bar.rs b/alacritty/src/message_bar.rs
index 851cb6ee..609af55d 100644
--- a/alacritty/src/message_bar.rs
+++ b/alacritty/src/message_bar.rs
@@ -1,6 +1,7 @@
use std::collections::VecDeque;
use alacritty_terminal::term::SizeInfo;
+use unicode_width::UnicodeWidthChar;
pub const CLOSE_BUTTON_TEXT: &str = "[X]";
const CLOSE_BUTTON_PADDING: usize = 1;
@@ -37,34 +38,49 @@ impl Message {
let total_lines =
(size_info.height() - 2. * size_info.padding_y()) / size_info.cell_height();
let max_lines = (total_lines as usize).saturating_sub(MIN_FREE_LINES);
- let button_len = CLOSE_BUTTON_TEXT.len();
+ let button_len = CLOSE_BUTTON_TEXT.chars().count();
// Split line to fit the screen.
let mut lines = Vec::new();
let mut line = String::new();
+ let mut line_len = 0;
for c in self.text.trim().chars() {
if c == '\n'
- || line.len() == num_cols
+ || 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))
+ && line_len == num_cols.saturating_sub(button_len + CLOSE_BUTTON_PADDING))
{
+ let is_whitespace = c.is_whitespace();
+
// Attempt to wrap on word boundaries.
- if let (Some(index), true) = (line.rfind(char::is_whitespace), c != '\n') {
+ let mut new_line = String::new();
+ if let Some(index) = line.rfind(char::is_whitespace).filter(|_| !is_whitespace) {
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();
+ new_line = split;
+ }
+
+ lines.push(Self::pad_text(line, num_cols));
+ line = new_line;
+ line_len = line.chars().count();
+
+ // Do not append whitespace at EOL.
+ if is_whitespace {
+ continue;
}
}
- if c != '\n' {
- line.push(c);
+ line.push(c);
+
+ // Reserve extra column for fullwidth characters.
+ let width = c.width().unwrap_or(0);
+ if width == 2 {
+ line.push(' ');
}
+
+ line_len += width
}
lines.push(Self::pad_text(line, num_cols));
@@ -110,7 +126,7 @@ impl Message {
/// 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());
+ let padding_len = num_cols.saturating_sub(text.chars().count());
text.extend(vec![' '; padding_len]);
text
}
@@ -341,6 +357,34 @@ mod tests {
}
#[test]
+ fn wrap_with_unicode() {
+ let input = "ab\nc 👩d fgh";
+ let mut message_buffer = MessageBuffer::new();
+ message_buffer.push(Message::new(input.into(), MessageType::Error));
+ let size = SizeInfo::new(7., 10., 1., 1., 0., 0., false);
+
+ let lines = message_buffer.message().unwrap().text(&size);
+
+ assert_eq!(lines, vec![
+ String::from("ab [X]"),
+ String::from("c 👩 d "),
+ String::from("fgh ")
+ ]);
+ }
+
+ #[test]
+ fn strip_whitespace_at_linebreak() {
+ let input = "\n0 1 2 3";
+ let mut message_buffer = MessageBuffer::new();
+ message_buffer.push(Message::new(input.into(), MessageType::Error));
+ let size = SizeInfo::new(3., 10., 1., 1., 0., 0., false);
+
+ let lines = message_buffer.message().unwrap().text(&size);
+
+ assert_eq!(lines, vec![String::from("[X]"), String::from("0 1"), String::from("2 3"),]);
+ }
+
+ #[test]
fn remove_duplicates() {
let mut message_buffer = MessageBuffer::new();
for _ in 0..10 {