fix(compatibility): support wide characters (#535)

* fix(compatibility): support wide characters

* style(fmt): rustfmt

* style(fmt): make clippy happy
This commit is contained in:
Aram Drevekenin 2021-05-26 18:05:43 +02:00 committed by GitHub
parent f55805d653
commit 44d67de187
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
34 changed files with 659 additions and 117 deletions

View file

@ -0,0 +1,3 @@
⏎(B ⏎ Welcome to fish, the friendly interactive shell
[?2004h]0;fish /home/aram/code/zellij(B⋊>(B ~/c/zellij(B on wide-char(B 15:35:20(B   b15:35:20(B  b(B15:35:20(B  ash(B15:35:20(B  ash(B15:35:20(B  sh(B15:35:20(B  h(B15:35:20(B  bash(B15:35:20(B  15:35:20(B  
(B[?2004l]0;bash /home/aram/code/zellij(B [?2004h[aram@green zellij]$ 

View file

@ -0,0 +1 @@
124

View file

@ -0,0 +1 @@
i there ii

View file

@ -0,0 +1 @@
i there ii

View file

@ -0,0 +1,2 @@
⏎(B ⏎ Welcome to fish, the friendly interactive shell
[?2004h]0;fish /home/aram/code/zellij(B⋊>(B ~/c/zellij(B on main(B 15:53:10(B   15:53:10(B  (B15:53:10(B  (B15:53:10(B  (B15:53:10(B  (B15:53:10(B  (B15:53:10(B  (B15:53:10(B  (B15:53:10(B  (B15:53:10(B  (B15:53:10(B  (B15:53:10(B  (B15:53:10(B  (B15:53:10(B  (B15:53:10(B  (B15:53:10(B  (B15:53:10(B  (B15:53:10(B  (B15:53:10(B  (B15:53:10(B  (B15:53:10(B  (B15:53:10(B  (B15:53:10(B  (B15:53:10(B  (B15:53:10(B  (B15:53:10(B  (B15:53:10(B  (B15:53:10(B  (B15:53:10(B  (B15:53:10(B  (B15:53:10(B  (B15:53:10(B  (B15:53:10(B  (B15:53:10(B  (B15:53:10(B  (B15:53:10(B  (B15:53:10(B  (B15:53:10(B  (B

View file

@ -0,0 +1 @@
124

2
src/tests/fixtures/wide_characters vendored Executable file
View file

@ -0,0 +1,2 @@
⏎(B ⏎ Welcome to fish, the friendly interactive shell
[?2004h]0;fish /home/aram/code/zellij(B⋊>(B ~/c/zellij(B on main(B 15:19:10(B   15:19:10(B  (B15:19:10(B  (B15:19:10(B  (B15:19:10(B  (B15:19:10(B  (B15:19:10(B  (B15:19:10(B  (B15:19:10(B  

31
src/tests/fixtures/wide_characters_full vendored Normal file
View file

@ -0,0 +1,31 @@

View file

@ -0,0 +1,30 @@
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

View file

@ -0,0 +1,30 @@
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

View file

@ -0,0 +1,3 @@
⏎(B ⏎ Welcome to fish, the friendly interactive shell
[?2004h]0;fish /home/aram/code/zellij(B⋊>(B ~/c/zellij(B on main(B 15:50:11(B   b15:50:11(B  b(B15:50:11(B  ash(B15:50:11(B  ash(B15:50:11(B  sh(B15:50:11(B  h(B15:50:11(B  bash(B15:50:11(B  15:50:11(B  
(B[?2004l]0;bash /home/aram/code/zellij(B [?2004h[aram@green zellij]$ 

View file

@ -1,3 +1,5 @@
use unicode_width::UnicodeWidthChar;
use std::{ use std::{
cmp::Ordering, cmp::Ordering,
collections::{BTreeSet, VecDeque}, collections::{BTreeSet, VecDeque},
@ -251,9 +253,6 @@ impl Grid {
colors, colors,
} }
} }
pub fn contains_widechar(&self) -> bool {
self.viewport.iter().any(|c| c.contains_widechar())
}
pub fn advance_to_next_tabstop(&mut self, styles: CharacterStyles) { pub fn advance_to_next_tabstop(&mut self, styles: CharacterStyles) {
let mut next_tabstop = None; let mut next_tabstop = None;
for tabstop in self.horizontal_tabstops.iter() { for tabstop in self.horizontal_tabstops.iter() {
@ -421,12 +420,12 @@ impl Grid {
canonical_line_parts.push(Row::new().canonical()); canonical_line_parts.push(Row::new().canonical());
} }
while !canonical_line.columns.is_empty() { while !canonical_line.columns.is_empty() {
let next_wrap = if canonical_line.len() > new_columns { let next_wrap = if canonical_line.width() > new_columns {
canonical_line.columns.drain(..new_columns) canonical_line.drain_until(new_columns)
} else { } else {
canonical_line.columns.drain(..) canonical_line.columns.drain(..).collect()
}; };
let row = Row::from_columns(next_wrap.collect()); let row = Row::from_columns(next_wrap);
// if there are no more parts, this row is canonical as long as it originally // if there are no more parts, this row is canonical as long as it originally
// was canonical (it might not have been for example if it's the first row in // was canonical (it might not have been for example if it's the first row in
// the viewport, and the actual canonical row is above it in the scrollback) // the viewport, and the actual canonical row is above it in the scrollback)
@ -522,9 +521,13 @@ impl Grid {
.viewport .viewport
.iter() .iter()
.map(|r| { .map(|r| {
let excess_width = r.excess_width();
let mut line: Vec<TerminalCharacter> = r.columns.iter().copied().collect(); let mut line: Vec<TerminalCharacter> = r.columns.iter().copied().collect();
// pad line // pad line
line.resize(self.width, EMPTY_TERMINAL_CHARACTER); line.resize(
self.width.saturating_sub(excess_width),
EMPTY_TERMINAL_CHARACTER,
);
line line
}) })
.collect(); .collect();
@ -657,7 +660,11 @@ impl Grid {
} }
} }
} }
pub fn add_character_at_cursor_position(&mut self, terminal_character: TerminalCharacter) { pub fn add_character_at_cursor_position(
&mut self,
terminal_character: TerminalCharacter,
max_width: usize,
) {
match self.viewport.get_mut(self.cursor.y) { match self.viewport.get_mut(self.cursor.y) {
Some(row) => { Some(row) => {
if self.insert_mode { if self.insert_mode {
@ -665,6 +672,7 @@ impl Grid {
} else { } else {
row.add_character_at(terminal_character, self.cursor.x); row.add_character_at(terminal_character, self.cursor.x);
} }
row.truncate(max_width);
} }
None => { None => {
// pad lines until cursor if they do not exist // pad lines until cursor if they do not exist
@ -678,6 +686,7 @@ impl Grid {
} }
pub fn add_character(&mut self, terminal_character: TerminalCharacter) { pub fn add_character(&mut self, terminal_character: TerminalCharacter) {
// TODO: try to separate adding characters from moving the cursors in this function // TODO: try to separate adding characters from moving the cursors in this function
let character_width = terminal_character.width;
if self.cursor.x >= self.width { if self.cursor.x >= self.width {
if self.disable_linewrap { if self.disable_linewrap {
return; return;
@ -703,8 +712,8 @@ impl Grid {
} }
} }
} }
self.add_character_at_cursor_position(terminal_character); self.add_character_at_cursor_position(terminal_character, self.width);
self.move_cursor_forward_until_edge(1); self.move_cursor_forward_until_edge(character_width);
} }
pub fn move_cursor_forward_until_edge(&mut self, count: usize) { pub fn move_cursor_forward_until_edge(&mut self, count: usize) {
let count_to_move = std::cmp::min(count, self.width - (self.cursor.x)); let count_to_move = std::cmp::min(count, self.width - (self.cursor.x));
@ -714,19 +723,11 @@ impl Grid {
self.viewport self.viewport
.get_mut(self.cursor.y) .get_mut(self.cursor.y)
.unwrap() .unwrap()
.truncate(self.cursor.x); .replace_and_pad_end(self.cursor.x, self.width, replace_with);
if self.cursor.x < self.width - 1 {
let mut characters_to_append = vec![replace_with; self.width - self.cursor.x];
self.viewport
.get_mut(self.cursor.y)
.unwrap()
.append(&mut characters_to_append);
}
} }
pub fn replace_characters_in_line_before_cursor(&mut self, replace_with: TerminalCharacter) { pub fn replace_characters_in_line_before_cursor(&mut self, replace_with: TerminalCharacter) {
let line_part = vec![replace_with; self.cursor.x + 1];
let row = self.viewport.get_mut(self.cursor.y).unwrap(); let row = self.viewport.get_mut(self.cursor.y).unwrap();
row.replace_beginning_with(line_part); row.replace_and_pad_beginning(self.cursor.x, replace_with);
} }
pub fn clear_all_after_cursor(&mut self, replace_with: TerminalCharacter) { pub fn clear_all_after_cursor(&mut self, replace_with: TerminalCharacter) {
if let Some(cursor_row) = self.viewport.get_mut(self.cursor.y) { if let Some(cursor_row) = self.viewport.get_mut(self.cursor.y) {
@ -946,13 +947,15 @@ impl Grid {
empty_character.styles = empty_char_style; empty_character.styles = empty_char_style;
let current_row = self.viewport.get_mut(self.cursor.y).unwrap(); let current_row = self.viewport.get_mut(self.cursor.y).unwrap();
for _ in 0..count { for _ in 0..count {
current_row.delete_character(self.cursor.x); let deleted_character = current_row.delete_and_return_character(self.cursor.x);
let excess_width = deleted_character
.map(|terminal_character| terminal_character.width)
.unwrap_or(0)
.saturating_sub(1);
for _ in 0..excess_width {
current_row.insert_character_at(empty_character, self.cursor.x);
}
} }
let mut empty_space_to_append = vec![empty_character; count];
self.viewport
.get_mut(self.cursor.y)
.unwrap()
.append(&mut empty_space_to_append);
} }
fn add_newline(&mut self) { fn add_newline(&mut self) {
self.add_canonical_line(); self.add_canonical_line();
@ -988,6 +991,7 @@ impl Perform for Grid {
// is a little faster // is a little faster
let terminal_character = TerminalCharacter { let terminal_character = TerminalCharacter {
character: c, character: c,
width: c.width().unwrap_or(0),
styles: self.cursor.pending_styles, styles: self.cursor.pending_styles,
}; };
self.set_preceding_character(terminal_character); self.set_preceding_character(terminal_character);
@ -1628,20 +1632,47 @@ impl Row {
self.is_canonical = true; self.is_canonical = true;
self self
} }
pub fn contains_widechar(&self) -> bool { pub fn width(&self) -> usize {
self.columns.iter().any(|c| c.is_widechar()) let mut width = 0;
for terminal_character in self.columns.iter() {
width += terminal_character.width;
}
width
}
pub fn excess_width(&self) -> usize {
let mut acc = 0;
for terminal_character in self.columns.iter() {
if terminal_character.width > 1 {
acc += terminal_character.width - 1;
}
}
acc
}
pub fn excess_width_until(&self, x: usize) -> usize {
let mut acc = 0;
for terminal_character in self.columns.iter().take(x) {
if terminal_character.width > 1 {
acc += terminal_character.width - 1;
}
}
acc
} }
pub fn add_character_at(&mut self, terminal_character: TerminalCharacter, x: usize) { pub fn add_character_at(&mut self, terminal_character: TerminalCharacter, x: usize) {
match self.columns.len().cmp(&x) { match self.width().cmp(&x) {
Ordering::Equal => self.columns.push(terminal_character), Ordering::Equal => {
self.columns.push(terminal_character);
}
Ordering::Less => { Ordering::Less => {
self.columns.resize(x, EMPTY_TERMINAL_CHARACTER); let width_offset = self.excess_width_until(x);
self.columns
.resize(x.saturating_sub(width_offset), EMPTY_TERMINAL_CHARACTER);
self.columns.push(terminal_character); self.columns.push(terminal_character);
} }
Ordering::Greater => { Ordering::Greater => {
let width_offset = self.excess_width_until(x);
// this is much more performant than remove/insert // this is much more performant than remove/insert
self.columns.push(terminal_character); self.columns.push(terminal_character);
self.columns.swap_remove(x); self.columns.swap_remove(x.saturating_sub(width_offset));
} }
} }
} }
@ -1661,7 +1692,11 @@ impl Row {
// this is much more performant than remove/insert // this is much more performant than remove/insert
if x < self.columns.len() { if x < self.columns.len() {
self.columns.push(terminal_character); self.columns.push(terminal_character);
self.columns.swap_remove(x); let character = self.columns.swap_remove(x);
let excess_width = character.width.saturating_sub(1);
for _ in 0..excess_width {
self.columns.insert(x, terminal_character);
}
} }
} }
pub fn replace_columns(&mut self, columns: Vec<TerminalCharacter>) { pub fn replace_columns(&mut self, columns: Vec<TerminalCharacter>) {
@ -1671,12 +1706,77 @@ impl Row {
self.columns.push(terminal_character); self.columns.push(terminal_character);
} }
pub fn truncate(&mut self, x: usize) { pub fn truncate(&mut self, x: usize) {
self.columns.truncate(x); let width_offset = self.excess_width_until(x);
let truncate_position = x.saturating_sub(width_offset);
if truncate_position < self.columns.len() {
self.columns.truncate(truncate_position);
}
}
pub fn position_accounting_for_widechars(&self, x: usize) -> usize {
let mut position = x;
for (index, terminal_character) in self.columns.iter().enumerate() {
if index == position {
break;
}
if terminal_character.width > 1 {
position = position.saturating_sub(terminal_character.width.saturating_sub(1));
}
}
position
}
pub fn replace_and_pad_end(
&mut self,
from: usize,
to: usize,
terminal_character: TerminalCharacter,
) {
let from_position_accounting_for_widechars = self.position_accounting_for_widechars(from);
let to_position_accounting_for_widechars = self.position_accounting_for_widechars(to);
let replacement_length = to_position_accounting_for_widechars
.saturating_sub(from_position_accounting_for_widechars);
let mut replace_with = vec![terminal_character; replacement_length];
self.columns
.truncate(from_position_accounting_for_widechars);
self.columns.append(&mut replace_with);
} }
pub fn append(&mut self, to_append: &mut Vec<TerminalCharacter>) { pub fn append(&mut self, to_append: &mut Vec<TerminalCharacter>) {
self.columns.append(to_append); self.columns.append(to_append);
} }
pub fn drain_until(&mut self, x: usize) -> Vec<TerminalCharacter> {
let mut drained_part: Vec<TerminalCharacter> = vec![];
let mut drained_part_len = 0;
loop {
if self.columns.is_empty() {
break;
}
let next_character_len = self.columns.get(0).unwrap().width;
if drained_part_len + next_character_len <= x {
drained_part.push(self.columns.remove(0));
drained_part_len += next_character_len;
} else {
break;
}
}
drained_part
}
pub fn replace_and_pad_beginning(&mut self, to: usize, terminal_character: TerminalCharacter) {
let to_position_accounting_for_widechars = self.position_accounting_for_widechars(to);
let width_of_current_character = self
.columns
.get(to_position_accounting_for_widechars)
.map(|character| character.width)
.unwrap_or(1);
let mut replace_with = vec![terminal_character; to + width_of_current_character];
if to_position_accounting_for_widechars > self.columns.len() {
self.columns.clear();
} else {
drop(self.columns.drain(0..=to_position_accounting_for_widechars));
}
replace_with.append(&mut self.columns);
self.columns = replace_with;
}
pub fn replace_beginning_with(&mut self, mut line_part: Vec<TerminalCharacter>) { pub fn replace_beginning_with(&mut self, mut line_part: Vec<TerminalCharacter>) {
// this assumes line_part has no wide characters
if line_part.len() > self.columns.len() { if line_part.len() > self.columns.len() {
self.columns.clear(); self.columns.clear();
} else { } else {
@ -1691,20 +1791,25 @@ impl Row {
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
self.columns.is_empty() self.columns.is_empty()
} }
pub fn delete_character(&mut self, x: usize) { pub fn delete_and_return_character(&mut self, x: usize) -> Option<TerminalCharacter> {
if x < self.columns.len() { if x < self.columns.len() {
self.columns.remove(x); Some(self.columns.remove(x))
} else {
None
} }
} }
pub fn split_to_rows_of_length(&mut self, max_row_length: usize) -> Vec<Row> { pub fn split_to_rows_of_length(&mut self, max_row_length: usize) -> Vec<Row> {
let mut parts: Vec<Row> = vec![]; let mut parts: Vec<Row> = vec![];
let mut current_part: Vec<TerminalCharacter> = vec![]; let mut current_part: Vec<TerminalCharacter> = vec![];
let mut current_part_len = 0;
for character in self.columns.drain(..) { for character in self.columns.drain(..) {
if current_part.len() == max_row_length { if current_part_len + character.width > max_row_length {
parts.push(Row::from_columns(current_part)); parts.push(Row::from_columns(current_part));
current_part = vec![]; current_part = vec![];
current_part_len = 0;
} }
current_part.push(character); current_part.push(character);
current_part_len += character.width;
} }
if !current_part.is_empty() { if !current_part.is_empty() {
parts.push(Row::from_columns(current_part)) parts.push(Row::from_columns(current_part))

View file

@ -99,9 +99,6 @@ impl Pane for PluginPane {
fn position_and_size_override(&self) -> Option<PositionAndSize> { fn position_and_size_override(&self) -> Option<PositionAndSize> {
self.position_and_size_override self.position_and_size_override
} }
fn contains_widechar(&self) -> bool {
false
}
fn should_render(&self) -> bool { fn should_render(&self) -> bool {
self.should_render self.should_render
} }

View file

@ -1,5 +1,3 @@
use unicode_width::UnicodeWidthChar;
use std::convert::TryFrom; use std::convert::TryFrom;
use std::fmt::{self, Debug, Display, Formatter}; use std::fmt::{self, Debug, Display, Formatter};
use std::ops::{Index, IndexMut}; use std::ops::{Index, IndexMut};
@ -8,6 +6,7 @@ use zellij_utils::vte::ParamsIter;
pub const EMPTY_TERMINAL_CHARACTER: TerminalCharacter = TerminalCharacter { pub const EMPTY_TERMINAL_CHARACTER: TerminalCharacter = TerminalCharacter {
character: ' ', character: ' ',
width: 1,
styles: CharacterStyles { styles: CharacterStyles {
foreground: Some(AnsiCode::Reset), foreground: Some(AnsiCode::Reset),
background: Some(AnsiCode::Reset), background: Some(AnsiCode::Reset),
@ -750,6 +749,7 @@ impl Cursor {
pub struct TerminalCharacter { pub struct TerminalCharacter {
pub character: char, pub character: char,
pub styles: CharacterStyles, pub styles: CharacterStyles,
pub width: usize,
} }
impl ::std::fmt::Debug for TerminalCharacter { impl ::std::fmt::Debug for TerminalCharacter {
@ -758,16 +758,6 @@ impl ::std::fmt::Debug for TerminalCharacter {
} }
} }
impl TerminalCharacter {
pub fn width(&self) -> usize {
self.character.width().unwrap_or(0)
}
pub fn is_widechar(&self) -> bool {
self.width() > 1
}
}
fn parse_sgr_color(params: &mut dyn Iterator<Item = u16>) -> Option<AnsiCode> { fn parse_sgr_color(params: &mut dyn Iterator<Item = u16>) -> Option<AnsiCode> {
match params.next() { match params.next() {
Some(2) => Some(AnsiCode::RgbCode(( Some(2) => Some(AnsiCode::RgbCode((

View file

@ -123,9 +123,6 @@ impl Pane for TerminalPane {
fn position_and_size_override(&self) -> Option<PositionAndSize> { fn position_and_size_override(&self) -> Option<PositionAndSize> {
self.position_and_size_override self.position_and_size_override
} }
fn contains_widechar(&self) -> bool {
self.grid.contains_widechar()
}
fn should_render(&self) -> bool { fn should_render(&self) -> bool {
self.grid.should_render self.grid.should_render
} }

View file

@ -396,3 +396,162 @@ fn terminal_reports() {
} }
assert_snapshot!(format!("{:?}", grid.pending_messages_to_pty)); assert_snapshot!(format!("{:?}", grid.pending_messages_to_pty));
} }
#[test]
fn wide_characters() {
let mut vte_parser = vte::Parser::new();
let mut grid = Grid::new(21, 104, Palette::default());
let fixture_name = "wide_characters";
let content = read_fixture(fixture_name);
for byte in content {
vte_parser.advance(&mut grid, byte);
}
assert_snapshot!(format!("{:?}", grid));
}
#[test]
fn wide_characters_line_wrap() {
let mut vte_parser = vte::Parser::new();
let mut grid = Grid::new(21, 104, Palette::default());
let fixture_name = "wide_characters_line_wrap";
let content = read_fixture(fixture_name);
for byte in content {
vte_parser.advance(&mut grid, byte);
}
assert_snapshot!(format!("{:?}", grid));
}
#[test]
fn fish_wide_characters_override_clock() {
let mut vte_parser = vte::Parser::new();
let mut grid = Grid::new(21, 104, Palette::default());
let fixture_name = "fish_wide_characters_override_clock";
let content = read_fixture(fixture_name);
for byte in content {
vte_parser.advance(&mut grid, byte);
}
assert_snapshot!(format!("{:?}", grid));
}
#[test]
fn bash_delete_wide_characters() {
let mut vte_parser = vte::Parser::new();
let mut grid = Grid::new(21, 104, Palette::default());
let fixture_name = "bash_delete_wide_characters";
let content = read_fixture(fixture_name);
for byte in content {
vte_parser.advance(&mut grid, byte);
}
assert_snapshot!(format!("{:?}", grid));
}
#[test]
fn delete_wide_characters_before_cursor() {
let mut vte_parser = vte::Parser::new();
let mut grid = Grid::new(21, 104, Palette::default());
let fixture_name = "delete_wide_characters_before_cursor";
let content = read_fixture(fixture_name);
for byte in content {
vte_parser.advance(&mut grid, byte);
}
assert_snapshot!(format!("{:?}", grid));
}
#[test]
fn delete_wide_characters_before_cursor_when_cursor_is_on_wide_character() {
let mut vte_parser = vte::Parser::new();
let mut grid = Grid::new(21, 104, Palette::default());
let fixture_name = "delete_wide_characters_before_cursor_when_cursor_is_on_wide_character";
let content = read_fixture(fixture_name);
for byte in content {
vte_parser.advance(&mut grid, byte);
}
assert_snapshot!(format!("{:?}", grid));
}
#[test]
fn delete_wide_character_under_cursor() {
let mut vte_parser = vte::Parser::new();
let mut grid = Grid::new(21, 104, Palette::default());
let fixture_name = "delete_wide_character_under_cursor";
let content = read_fixture(fixture_name);
for byte in content {
vte_parser.advance(&mut grid, byte);
}
assert_snapshot!(format!("{:?}", grid));
}
#[test]
fn replace_wide_character_under_cursor() {
let mut vte_parser = vte::Parser::new();
let mut grid = Grid::new(21, 104, Palette::default());
let fixture_name = "replace_wide_character_under_cursor";
let content = read_fixture(fixture_name);
for byte in content {
vte_parser.advance(&mut grid, byte);
}
assert_snapshot!(format!("{:?}", grid));
}
#[test]
fn wrap_wide_characters() {
let mut vte_parser = vte::Parser::new();
let mut grid = Grid::new(21, 90, Palette::default());
let fixture_name = "wide_characters_full";
let content = read_fixture(fixture_name);
for byte in content {
vte_parser.advance(&mut grid, byte);
}
assert_snapshot!(format!("{:?}", grid));
}
#[test]
fn wrap_wide_characters_on_size_change() {
let mut vte_parser = vte::Parser::new();
let mut grid = Grid::new(21, 93, Palette::default());
let fixture_name = "wide_characters_full";
let content = read_fixture(fixture_name);
for byte in content {
vte_parser.advance(&mut grid, byte);
}
grid.change_size(21, 90);
assert_snapshot!(format!("{:?}", grid));
}
#[test]
fn unwrap_wide_characters_on_size_change() {
let mut vte_parser = vte::Parser::new();
let mut grid = Grid::new(21, 93, Palette::default());
let fixture_name = "wide_characters_full";
let content = read_fixture(fixture_name);
for byte in content {
vte_parser.advance(&mut grid, byte);
}
grid.change_size(21, 90);
grid.change_size(21, 93);
assert_snapshot!(format!("{:?}", grid));
}
#[test]
fn wrap_wide_characters_in_the_middle_of_the_line() {
let mut vte_parser = vte::Parser::new();
let mut grid = Grid::new(21, 91, Palette::default());
let fixture_name = "wide_characters_line_middle";
let content = read_fixture(fixture_name);
for byte in content {
vte_parser.advance(&mut grid, byte);
}
assert_snapshot!(format!("{:?}", grid));
}
#[test]
fn wrap_wide_characters_at_the_end_of_the_line() {
let mut vte_parser = vte::Parser::new();
let mut grid = Grid::new(21, 90, Palette::default());
let fixture_name = "wide_characters_line_end";
let content = read_fixture(fixture_name);
for byte in content {
vte_parser.advance(&mut grid, byte);
}
assert_snapshot!(format!("{:?}", grid));
}

View file

@ -0,0 +1,9 @@
---
source: zellij-server/src/panes/./unit/grid_tests.rs
expression: "format!(\"{:?}\", grid)"
---
00 (C): Welcome to fish, the friendly interactive shell
01 (C): ⋊> ~/c/zellij on wide-char bash 15:35:20
02 (C): [aram@green zellij]$

View file

@ -0,0 +1,8 @@
---
source: zellij-server/src/panes/./unit/grid_tests.rs
expression: "format!(\"{:?}\", grid)"
---
00 (C): 12 4
01 (C):

View file

@ -0,0 +1,7 @@
---
source: zellij-server/src/panes/./unit/grid_tests.rs
expression: "format!(\"{:?}\", grid)"
---
00 (C): i

View file

@ -0,0 +1,7 @@
---
source: zellij-server/src/panes/./unit/grid_tests.rs
expression: "format!(\"{:?}\", grid)"
---
00 (C): i

View file

@ -0,0 +1,8 @@
---
source: zellij-server/src/panes/./unit/grid_tests.rs
expression: "format!(\"{:?}\", grid)"
---
00 (C): Welcome to fish, the friendly interactive shell
01 (C): ⋊> ~/c/zellij on main

View file

@ -0,0 +1,8 @@
---
source: zellij-server/src/panes/./unit/grid_tests.rs
expression: "format!(\"{:?}\", grid)"
---
00 (C): 12 4
01 (C):

View file

@ -0,0 +1,27 @@
---
source: zellij-server/src/panes/./unit/grid_tests.rs
expression: "format!(\"{:?}\", grid)"
---
00 (C):
01 (C):
02 (C):
03 (C):
04 (C):
05 (C):
06 (C):
07 (C):
08 (C):
09 (C):
10 (C):
11 (C):
12 (C):
13 (C):
14 (C):
15 (C):
16 (C):
17 (C):
18 (C):
19 (C):
20 (C):

View file

@ -3,7 +3,7 @@ source: zellij-server/src/panes/./unit/grid_tests.rs
expression: "format!(\"{:?}\", grid)" expression: "format!(\"{:?}\", grid)"
--- ---
00 (C): A******************************************************************************BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 00 (C): A******************************************************************************BAAAAAAAAAAAAAAAAA
01 (C): 01 (C):
02 (C): 02 (C):
03 (C): Test of 'Insert Mode'. The top line should be 'A*** ... ***B'. Push <RETURN> 03 (C): Test of 'Insert Mode'. The top line should be 'A*** ... ***B'. Push <RETURN>

View file

@ -3,7 +3,7 @@ source: zellij-server/src/panes/./unit/grid_tests.rs
expression: "format!(\"{:?}\", grid)" expression: "format!(\"{:?}\", grid)"
--- ---
00 (C): ABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 00 (C): ABAAAAAAAAAAAAAAAAA
01 (C): 01 (C):
02 (C): 02 (C):
03 (C): Test of 'Delete Character'. The top line should be 'AB'. Push <RETURN> 03 (C): Test of 'Delete Character'. The top line should be 'AB'. Push <RETURN>

View file

@ -3,30 +3,30 @@ source: zellij-server/src/panes/./unit/grid_tests.rs
expression: "format!(\"{:?}\", grid)" expression: "format!(\"{:?}\", grid)"
--- ---
00 (C): AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 00 (C): AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
01 (C): BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB 01 (C): BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
02 (C): CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC 02 (C): CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
03 (C): The right column should be staggered DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD 03 (C): The right column should be staggered DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
04 (C): by one. Push <RETURN>EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE 04 (C): by one. Push <RETURN>EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
05 (C): FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF 05 (C): FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
06 (C): GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG 06 (C): GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG
07 (C): HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH 07 (C): HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
08 (C): IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII 08 (C): IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII
09 (C): JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ 09 (C): JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ
10 (C): KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK 10 (C): KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK
11 (C): LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL 11 (C): LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
12 (C): MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM 12 (C): MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
13 (C): NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN 13 (C): NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN
14 (C): OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO 14 (C): OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
15 (C): PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP 15 (C): PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
16 (C): QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ 16 (C): QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ
17 (C): RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR 17 (C): RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR
18 (C): SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS 18 (C): SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS
19 (C): TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT 19 (C): TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT
20 (C): UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU 20 (C): UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU
21 (C): VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV 21 (C): VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
22 (C): WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW 22 (C): WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
23 (C): XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 23 (C): XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
24 (C): 24 (C):
25 (C): 25 (C):
26 (C): 26 (C):

View file

@ -3,30 +3,30 @@ source: zellij-server/src/panes/./unit/grid_tests.rs
expression: "format!(\"{:?}\", grid)" expression: "format!(\"{:?}\", grid)"
--- ---
00 (C): AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 00 (C): AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
01 (C): BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB 01 (C): BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
02 (C): CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC 02 (C): CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
03 (C): The right column should be staggered 03 (C): The right column should be staggered
04 (C): by one. Push <RETURN>EEEEEEEEEEEEE 04 (C): by one. Push <RETURN>EEEEEEEEEEEEE
05 (C): FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF 05 (C): FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
06 (C): GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG 06 (C): GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG
07 (C): HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH 07 (C): HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
08 (C): IIIIIIIIIIIIIIIIIIIIIIIIIIIIIII 08 (C): IIIIIIIIIIIIIIIIIIIIIIIIIIIIIII
09 (C): JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ 09 (C): JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ
10 (C): KKKKKKKKKKKKKKKKKKKKKKKKKKKKK 10 (C): KKKKKKKKKKKKKKKKKKKKKKKKKKKKK
11 (C): LLLLLLLLLLLLLLLLLLLLLLLLLLLL 11 (C): LLLLLLLLLLLLLLLLLLLLLLLLLLLL
12 (C): MMMMMMMMMMMMMMMMMMMMMMMMMMM 12 (C): MMMMMMMMMMMMMMMMMMMMMMMMMMM
13 (C): NNNNNNNNNNNNNNNNNNNNNNNNNN 13 (C): NNNNNNNNNNNNNNNNNNNNNNNNNN
14 (C): OOOOOOOOOOOOOOOOOOOOOOOOO 14 (C): OOOOOOOOOOOOOOOOOOOOOOOOO
15 (C): PPPPPPPPPPPPPPPPPPPPPPPP 15 (C): PPPPPPPPPPPPPPPPPPPPPPPP
16 (C): QQQQQQQQQQQQQQQQQQQQQQQ 16 (C): QQQQQQQQQQQQQQQQQQQQQQQ
17 (C): RRRRRRRRRRRRRRRRRRRRRR 17 (C): RRRRRRRRRRRRRRRRRRRRRR
18 (C): SSSSSSSSSSSSSSSSSSSSS 18 (C): SSSSSSSSSSSSSSSSSSSSS
19 (C): TTTTTTTTTTTTTTTTTTTT 19 (C): TTTTTTTTTTTTTTTTTTTT
20 (C): UUUUUUUUUUUUUUUUUUU 20 (C): UUUUUUUUUUUUUUUUUUU
21 (C): VVVVVVVVVVVVVVVVVV 21 (C): VVVVVVVVVVVVVVVVVV
22 (C): WWWWWWWWWWWWWWWWW 22 (C): WWWWWWWWWWWWWWWWW
23 (C): XXXXXXXXXXXXXXXX 23 (C): XXXXXXXXXXXXXXXX
24 (C): 24 (C):
25 (C): 25 (C):
26 (C): 26 (C):

View file

@ -0,0 +1,8 @@
---
source: zellij-server/src/panes/./unit/grid_tests.rs
expression: "format!(\"{:?}\", grid)"
---
00 (C): Welcome to fish, the friendly interactive shell
01 (C): ⋊> ~/c/zellij on main 15:19:10

View file

@ -0,0 +1,10 @@
---
source: zellij-server/src/panes/./unit/grid_tests.rs
expression: "format!(\"{:?}\", grid)"
---
00 (C): Welcome to fish, the friendly interactive shell
01 (C): ⋊> ~/c/zellij on main bash 15:50:11
02 (C): [aram@green zellij]$
03 (W):

View file

@ -0,0 +1,27 @@
---
source: zellij-server/src/panes/./unit/grid_tests.rs
expression: "format!(\"{:?}\", grid)"
---
00 (W):
01 (C):
02 (W):
03 (C):
04 (W):
05 (C):
06 (W):
07 (C):
08 (W):
09 (C):
10 (W):
11 (C):
12 (W):
13 (C):
14 (W):
15 (C):
16 (W):
17 (C):
18 (W):
19 (C):
20 (C):

View file

@ -0,0 +1,27 @@
---
source: zellij-server/src/panes/./unit/grid_tests.rs
expression: "format!(\"{:?}\", grid)"
---
00 (C): aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
01 (W):
02 (C): aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
03 (W):
04 (C): aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
05 (W):
06 (C): aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
07 (W):
08 (C): aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
09 (W):
10 (C): aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
11 (W):
12 (C): aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
13 (W):
14 (C): aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
15 (W):
16 (C): aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
17 (W):
18 (C): aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
19 (W):
20 (C):

View file

@ -0,0 +1,27 @@
---
source: zellij-server/src/panes/./unit/grid_tests.rs
expression: "format!(\"{:?}\", grid)"
---
00 (C): aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
01 (W): a
02 (C): aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
03 (W): a
04 (C): aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
05 (W): a
06 (C): aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
07 (W): a
08 (C): aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
09 (W): a
10 (C): aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
11 (W): a
12 (C): aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
13 (W): a
14 (C): aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
15 (W): a
16 (C): aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
17 (W): a
18 (C): aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
19 (W): a
20 (C):

View file

@ -0,0 +1,27 @@
---
source: zellij-server/src/panes/./unit/grid_tests.rs
expression: "format!(\"{:?}\", grid)"
---
00 (W):
01 (C):
02 (W):
03 (C):
04 (W):
05 (C):
06 (W):
07 (C):
08 (W):
09 (C):
10 (W):
11 (C):
12 (W):
13 (C):
14 (W):
15 (C):
16 (W):
17 (C):
18 (W):
19 (C):
20 (C):

View file

@ -108,9 +108,6 @@ pub trait Pane {
fn position_and_size_override(&self) -> Option<PositionAndSize>; fn position_and_size_override(&self) -> Option<PositionAndSize>;
fn should_render(&self) -> bool; fn should_render(&self) -> bool;
fn set_should_render(&mut self, should_render: bool); fn set_should_render(&mut self, should_render: bool);
// FIXME: this method is used to trigger a force render to hide widechar problem
// it should be removed when we can handle widechars
fn contains_widechar(&self) -> bool;
fn selectable(&self) -> bool; fn selectable(&self) -> bool;
fn set_selectable(&mut self, selectable: bool); fn set_selectable(&mut self, selectable: bool);
fn set_invisible_borders(&mut self, invisible_borders: bool); fn set_invisible_borders(&mut self, invisible_borders: bool);
@ -721,9 +718,6 @@ impl Tab {
pub fn toggle_sync_panes_is_active(&mut self) { pub fn toggle_sync_panes_is_active(&mut self) {
self.synchronize_is_active = !self.synchronize_is_active; self.synchronize_is_active = !self.synchronize_is_active;
} }
pub fn panes_contain_widechar(&self) -> bool {
self.panes.iter().any(|(_, p)| p.contains_widechar())
}
pub fn render(&mut self) { pub fn render(&mut self) {
if self.active_terminal.is_none() if self.active_terminal.is_none()
|| *self.session_state.read().unwrap() != SessionState::Attached || *self.session_state.read().unwrap() != SessionState::Attached
@ -733,11 +727,6 @@ impl Tab {
// or if this session is not attached to a client, we do not have to render // or if this session is not attached to a client, we do not have to render
return; return;
} }
// if any pane contain widechar, all pane in the same row will messup. We should render them every time
// FIXME: remove this when we can handle widechars correctly
if self.panes_contain_widechar() {
self.set_force_render()
}
let mut output = String::new(); let mut output = String::new();
let mut boundaries = Boundaries::new( let mut boundaries = Boundaries::new(
self.full_screen_ws.columns as u16, self.full_screen_ws.columns as u16,