Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(borders): properly handle wide chars in pane titles #698

Merged
merged 5 commits into from
Sep 6, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
* Fix bug when opening new tab the new pane's viewport would sometimes be calculated incorrectly (https://github.com/zellij-org/zellij/pull/683)
* Fix bug when in some cases closing a tab would not clear the previous pane's contents (https://github.com/zellij-org/zellij/pull/684)
* Fix bug where tabs would sometimes be created with the wrong index in their name (https://github.com/zellij-org/zellij/pull/686)
* Fix bug where wide chars would mess up pane titles (https://github.com/zellij-org/zellij/pull/698)

## [0.16.0] - 2021-08-31
* Plugins don't crash zellij anymore on receiving mouse events (https://github.com/zellij-org/zellij/pull/620)
Expand Down
20 changes: 20 additions & 0 deletions test-template.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
template:
direction: Horizontal
parts:
- direction: Vertical
borderless: true
split_size:
Fixed: 1
run:
plugin: tab-bar
- direction: Vertical
borderless: true
- direction: Vertical
borderless: true
- direction: Vertical
borderless: true
split_size:
Fixed: 2
run:
plugin: status-bar
69 changes: 41 additions & 28 deletions zellij-server/src/ui/pane_boundaries_frame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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
Expand All @@ -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)
}
}
Expand All @@ -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!(
Expand All @@ -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!(
Expand Down