diff options
author | Aram Drevekenin <aram@poor.dev> | 2021-09-06 20:24:47 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-09-06 20:24:47 +0200 |
commit | 86fdd2400e467c5788e6598ca8acc2359d42e1c2 (patch) | |
tree | ea92ee99b3c02203dcfc13f307f9a04c6f46759d /zellij-server/src/ui | |
parent | 1c9dc35121dbec00c424e4d3e367ec600aa909c0 (diff) |
fix(borders): properly handle wide chars in pane titles (#698)
* work
* fix(frame): properly handle widechars in frame titles
* style(fmt): make rustfmt happy
* fix(truncate): do not reverse second part of string (oops)
* docs(changelog): document change
Diffstat (limited to 'zellij-server/src/ui')
-rw-r--r-- | zellij-server/src/ui/pane_boundaries_frame.rs | 69 |
1 files changed, 41 insertions, 28 deletions
diff --git a/zellij-server/src/ui/pane_boundaries_frame.rs b/zellij-server/src/ui/pane_boundaries_frame.rs index d3cd6d5af..493441496 100644 --- a/zellij-server/src/ui/pane_boundaries_frame.rs +++ b/zellij-server/src/ui/pane_boundaries_frame.rs @@ -4,6 +4,8 @@ use ansi_term::Style; use zellij_utils::pane_size::Viewport; use zellij_utils::zellij_tile::prelude::PaletteColor; +use unicode_width::{UnicodeWidthChar, UnicodeWidthStr}; + fn color_string(character: &str, color: Option<PaletteColor>) -> String { match color { Some(color) => match color { @@ -33,11 +35,11 @@ impl PaneFrame { let full_indication = format!(" {}/{} ", self.scroll_position.0, self.scroll_position.1); let short_indication = format!(" {} ", self.scroll_position.0); - if prefix.chars().count() + full_indication.chars().count() <= max_length { + if prefix.width() + full_indication.width() <= max_length { Some(format!("{}{}", prefix, full_indication)) - } else if full_indication.chars().count() <= max_length { + } else if full_indication.width() <= max_length { Some(full_indication) - } else if short_indication.chars().count() <= max_length { + } else if short_indication.width() <= max_length { Some(short_indication) } else { None @@ -52,28 +54,41 @@ impl PaneFrame { let full_text = format!(" {} ", &self.title); if max_length <= 6 { None - } else if full_text.chars().count() <= max_length { + } else if full_text.width() <= max_length { Some(full_text) } else { - let length_of_each_half = (max_length - middle_truncated_sign.chars().count()) / 2; - let first_part: String = full_text.chars().take(length_of_each_half).collect(); - let second_part: String = full_text - .chars() - .skip(full_text.chars().count() - length_of_each_half) - .collect(); - let title_left_side = if first_part.chars().count() - + middle_truncated_sign.chars().count() - + second_part.chars().count() - < max_length - { - // this means we lost 1 character when dividing the total length into halves - format!( - "{}{}{}", - first_part, middle_truncated_sign_long, second_part - ) - } else { - format!("{}{}{}", first_part, middle_truncated_sign, second_part) - }; + let length_of_each_half = (max_length - middle_truncated_sign.width()) / 2; + + let mut first_part: String = String::with_capacity(length_of_each_half); + for char in full_text.chars() { + if first_part.width() + char.width().unwrap_or(0) > length_of_each_half { + break; + } else { + first_part.push(char); + } + } + + let mut second_part: String = String::with_capacity(length_of_each_half); + for char in full_text.chars().rev() { + if second_part.width() + char.width().unwrap_or(0) > length_of_each_half { + break; + } else { + second_part.insert(0, char); + } + } + + let title_left_side = + if first_part.width() + middle_truncated_sign.width() + second_part.width() + < max_length + { + // this means we lost 1 character when dividing the total length into halves + format!( + "{}{}{}", + first_part, middle_truncated_sign_long, second_part + ) + } else { + format!("{}{}{}", first_part, middle_truncated_sign, second_part) + }; Some(title_left_side) } } @@ -83,15 +98,13 @@ impl PaneFrame { let right_boundary = boundary_type::TOP_RIGHT; let left_side = self.render_title_left_side(total_title_length); let right_side = left_side.as_ref().and_then(|left_side| { - let space_left = total_title_length.saturating_sub(left_side.chars().count() + 1); // 1 for a middle separator + let space_left = total_title_length.saturating_sub(left_side.width() + 1); // 1 for a middle separator self.render_title_right_side(space_left) }); let title_text = match (left_side, right_side) { (Some(left_side), Some(right_side)) => { let mut middle = String::new(); - for _ in - (left_side.chars().count() + right_side.chars().count())..total_title_length - { + for _ in (left_side.width() + right_side.width())..total_title_length { middle.push_str(boundary_type::HORIZONTAL); } format!( @@ -101,7 +114,7 @@ impl PaneFrame { } (Some(left_side), None) => { let mut middle_padding = String::new(); - for _ in left_side.chars().count()..total_title_length { + for _ in left_side.width()..total_title_length { middle_padding.push_str(boundary_type::HORIZONTAL); } format!( |