aboutsummaryrefslogtreecommitdiffstats
path: root/zellij-server
diff options
context:
space:
mode:
authorAram Drevekenin <aram@poor.dev>2022-07-08 17:19:42 +0200
committerGitHub <noreply@github.com>2022-07-08 17:19:42 +0200
commitc89b416d764d80a72130821506f36157a08321e9 (patch)
tree6d1cc2d7fd5fddbb33fcbff192153700a9788bec /zellij-server
parentfix: typo (#1567) (diff)
downloadsl0ppij-c89b416d764d80a72130821506f36157a08321e9.tar.gz
sl0ppij-c89b416d764d80a72130821506f36157a08321e9.tar.xz
sl0ppij-c89b416d764d80a72130821506f36157a08321e9.zip
feat(terminal): sixel support (#1557)
* work * work * work * work * work * more work * work * work * work * hack around stdin repeater * refactor(sixel): rename sixel structs * feat(sixel): render text above images * fix(sixel): reap images once they're past the end of the scrollbuffer * fix(sixel): display images in the middle of the line * fix(sixel): render crash * fix(sixel): react to SIGWINCH * fix(sixel): behave properly in alternate screen mode * fix(sixel): reap images on terminal reset * feat(sixel): handle DECSDM * fix(terminal): properly respond to XTSMGRAPHICS and device attributes with Sixel * Add comment * fix(sixel): hack for unknown event overflow until we fix the api * feat(input): query terminal for all OSC 4 colors and respond to them in a buggy way * fix(sixel): do not render corrupted image * feat(input): improve STDIN queries * fix(client): mistake in clear terminal attributes string * fix(ansi): report correct number of supported color registers * fix(sixel): reap images that are completely covered * style(comment): fix name * test(sixel): infra * test(sixel): cases and fixes * fix(sixel): forward dcs bytes to sixel parser * refactor(client): ansi stdin parser * refactor(output): cleanup * some refactorings * fix test * refactor(grid): sixel-grid / sixel-image-store * refactor(grid): grid debug method * refactor(grid): move various logic to sixel.rs * refactor(grid): remove unused methods * fix(sixel): work with multiple users * refactor(pane): remove unused z_index * style(fmt): prepend unused variable * style(fmt): rustfmt * fix(tests): various apis * chore(dependencies): use published version of sixel crates * style(fmt): rustfmt * style(fmt): rustfmt * style(lint): make clippy happy * style(lint): make clippy happy... again * style(lint): make clippy happy... again (chapter 2) * style(comment): remove unused * fix(colors): export COLORTERM and respond to XTVERSION * fix(test): color register count * fix(stdin): adjust STDIN sleep times
Diffstat (limited to 'zellij-server')
-rw-r--r--zellij-server/Cargo.toml3
-rw-r--r--zellij-server/src/output/mod.rs328
-rw-r--r--zellij-server/src/panes/grid.rs368
-rw-r--r--zellij-server/src/panes/mod.rs2
-rw-r--r--zellij-server/src/panes/plugin_pane.rs6
-rw-r--r--zellij-server/src/panes/sixel.rs466
-rw-r--r--zellij-server/src/panes/terminal_pane.rs16
-rw-r--r--zellij-server/src/panes/unit/grid_tests.rs704
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__ansi_csi_at_sign.snap52
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__bash_cursor_linewrap.snap26
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__bash_delete_wide_characters.snap22
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__clear_scroll_region.snap27
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__csi_b.snap51
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__csi_capital_i.snap51
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__csi_capital_z.snap51
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__delete_char_in_middle_of_line_with_multiple_widechars.snap22
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__delete_char_in_middle_of_line_with_widechar.snap22
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__delete_wide_character_under_cursor.snap21
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__delete_wide_characters_before_cursor.snap22
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__delete_wide_characters_before_cursor_when_cursor_is_on_wide_character.snap22
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__display_tab_characters_properly.snap15
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__emacs_longbuf.snap58
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__fish_paste_multiline.snap9
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__fish_select_tab_completion_options.snap25
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__fish_tab_completion_options.snap25
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__fish_wide_characters_override_clock.snap23
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__insert_character_in_line_with_wide_character.snap22
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__replace_multiple_wide_characters_under_cursor.snap51
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__replace_non_wide_characters_with_wide_characters.snap51
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__replace_wide_character_under_cursor.snap21
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__sixel_image_in_alternate_buffer-2.snap36
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__sixel_image_in_alternate_buffer.snap36
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__sixel_with_image_scrolling_decsdm-2.snap36
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__sixel_with_image_scrolling_decsdm.snap36
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__terminal_reports.snap6
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__wide_characters.snap21
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__wide_characters_line_wrap.snap19
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__terminal_pane__grid_tests__changing_character_cell_size_with_sixel_images.snap26
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__terminal_pane__grid_tests__keep_working_after_corrupted_sixel_image.snap26
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__terminal_pane__grid_tests__multiple_sixel_images_in_pane.snap26
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__terminal_pane__grid_tests__overflowing_sixel_image_inside_terminal_pane.snap26
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__terminal_pane__grid_tests__partial_sixel_image_inside_terminal_pane.snap26
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__terminal_pane__grid_tests__resizing_pane_with_sixel_images.snap26
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__terminal_pane__grid_tests__scrolling_through_a_sixel_image-2.snap26
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__terminal_pane__grid_tests__scrolling_through_a_sixel_image-3.snap26
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__terminal_pane__grid_tests__scrolling_through_a_sixel_image.snap26
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__terminal_pane__grid_tests__sixel_image_inside_terminal_pane.snap26
-rw-r--r--zellij-server/src/panes/unit/terminal_pane_tests.rs353
-rw-r--r--zellij-server/src/route.rs36
-rw-r--r--zellij-server/src/screen.rs31
-rw-r--r--zellij-server/src/tab/mod.rs36
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__floating_pane_above_sixel_image.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_floating_pane_with_sixel_image.snap26
-rw-r--r--zellij-server/src/tab/unit/tab_integration_tests.rs181
-rw-r--r--zellij-server/src/tab/unit/tab_tests.rs11
-rw-r--r--zellij-server/src/ui/pane_contents_and_ui.rs17
56 files changed, 3637 insertions, 112 deletions
diff --git a/zellij-server/Cargo.toml b/zellij-server/Cargo.toml
index 4154571e..41fe4ffb 100644
--- a/zellij-server/Cargo.toml
+++ b/zellij-server/Cargo.toml
@@ -27,6 +27,9 @@ typetag = "0.1.7"
chrono = "0.4.19"
close_fds = "0.3.2"
sysinfo = "0.22.5"
+sixel-tokenizer = "0.1.0"
+sixel-image = "0.1.0"
+arrayvec = "0.7.2"
uuid = { version = "0.8.2", features = ["serde", "v4"] }
[dev-dependencies]
diff --git a/zellij-server/src/output/mod.rs b/zellij-server/src/output/mod.rs
index 6d801001..c13848ad 100644
--- a/zellij-server/src/output/mod.rs
+++ b/zellij-server/src/output/mod.rs
@@ -4,6 +4,7 @@ use crate::panes::selection::Selection;
use crate::panes::Row;
use crate::{
+ panes::sixel::SixelImageStore,
panes::terminal_character::{AnsiCode, CharacterStyles},
panes::{LinkHandler, TerminalCharacter, EMPTY_TERMINAL_CHARACTER},
ClientId,
@@ -16,6 +17,7 @@ use std::{
str,
};
use zellij_utils::pane_size::PaneGeom;
+use zellij_utils::pane_size::SizeInPixels;
fn vte_goto_instruction(x_coords: usize, y_coords: usize, vte_output: &mut String) {
write!(
@@ -54,7 +56,6 @@ fn write_changed_styles(
if let Some(new_styles) =
character_styles.update_and_return_diff(&current_character_styles, chunk_changed_colors)
{
- // if let Some(osc8_link) = link_handler.as_ref().and_then(|l_h| l_h.borrow().output_osc8(new_styles.link_anchor)) {
if let Some(osc8_link) =
link_handler.and_then(|l_h| l_h.output_osc8(new_styles.link_anchor))
{
@@ -65,11 +66,14 @@ fn write_changed_styles(
}
}
-fn serialize_character_chunks(
+fn serialize_chunks(
character_chunks: Vec<CharacterChunk>,
+ sixel_chunks: Option<&Vec<SixelImageChunk>>,
link_handler: Option<&mut Rc<RefCell<LinkHandler>>>,
+ sixel_image_store: &mut SixelImageStore,
) -> String {
- let mut vte_output = String::new(); // TODO: preallocate character_chunks.len()?
+ let mut vte_output = String::new();
+ let mut sixel_vte: Option<String> = None;
let link_handler = link_handler.map(|l_h| l_h.borrow());
for character_chunk in character_chunks {
let chunk_selection_and_background_color = character_chunk.selection_and_background_color();
@@ -96,6 +100,32 @@ fn serialize_character_chunks(
}
character_styles.clear();
}
+ if let Some(sixel_chunks) = sixel_chunks {
+ for sixel_chunk in sixel_chunks {
+ let serialized_sixel_image = sixel_image_store.serialize_image(
+ sixel_chunk.sixel_image_id,
+ sixel_chunk.sixel_image_pixel_x,
+ sixel_chunk.sixel_image_pixel_y,
+ sixel_chunk.sixel_image_pixel_width,
+ sixel_chunk.sixel_image_pixel_height,
+ );
+ if let Some(serialized_sixel_image) = serialized_sixel_image {
+ let sixel_vte = sixel_vte.get_or_insert_with(String::new);
+ vte_goto_instruction(sixel_chunk.cell_x, sixel_chunk.cell_y, sixel_vte);
+ sixel_vte.push_str(&serialized_sixel_image);
+ }
+ }
+ }
+ if let Some(ref sixel_vte) = sixel_vte {
+ // we do this at the end because of the implied z-index,
+ // images should be above text unless the text was explicitly inserted after them (the
+ // latter being a case we handle in our own internal state and not in the output)
+ let save_cursor_position = "\u{1b}[s";
+ let restore_cursor_position = "\u{1b}[u";
+ vte_output.push_str(save_cursor_position);
+ vte_output.push_str(sixel_vte);
+ vte_output.push_str(restore_cursor_position);
+ }
vte_output
}
@@ -148,11 +178,24 @@ pub struct Output {
pre_vte_instructions: HashMap<ClientId, Vec<String>>,
post_vte_instructions: HashMap<ClientId, Vec<String>>,
client_character_chunks: HashMap<ClientId, Vec<CharacterChunk>>,
+ sixel_chunks: HashMap<ClientId, Vec<SixelImageChunk>>,
link_handler: Option<Rc<RefCell<LinkHandler>>>,
+ sixel_image_store: Rc<RefCell<SixelImageStore>>,
+ character_cell_size: Rc<RefCell<Option<SizeInPixels>>>,
floating_panes_stack: Option<FloatingPanesStack>,
}
impl Output {
+ pub fn new(
+ sixel_image_store: Rc<RefCell<SixelImageStore>>,
+ character_cell_size: Rc<RefCell<Option<SizeInPixels>>>,
+ ) -> Self {
+ Output {
+ sixel_image_store,
+ character_cell_size,
+ ..Default::default()
+ }
+ }
pub fn add_clients(
&mut self,
client_ids: &HashSet<ClientId>,
@@ -240,6 +283,48 @@ impl Output {
.or_insert_with(Vec::new);
entry.push(String::from(vte_instruction));
}
+ pub fn add_sixel_image_chunks_to_client(
+ &mut self,
+ client_id: ClientId,
+ sixel_image_chunks: Vec<SixelImageChunk>,
+ z_index: Option<usize>,
+ ) {
+ if let Some(character_cell_size) = *self.character_cell_size.borrow() {
+ let mut sixel_chunks = if let Some(floating_panes_stack) = &self.floating_panes_stack {
+ floating_panes_stack.visible_sixel_image_chunks(
+ sixel_image_chunks,
+ z_index,
+ &character_cell_size,
+ )
+ } else {
+ sixel_image_chunks
+ };
+ let entry = self.sixel_chunks.entry(client_id).or_insert_with(Vec::new);
+ entry.append(&mut sixel_chunks);
+ }
+ }
+ pub fn add_sixel_image_chunks_to_multiple_clients(
+ &mut self,
+ sixel_image_chunks: Vec<SixelImageChunk>,
+ client_ids: impl Iterator<Item = ClientId>,
+ z_index: Option<usize>,
+ ) {
+ if let Some(character_cell_size) = *self.character_cell_size.borrow() {
+ let sixel_chunks = if let Some(floating_panes_stack) = &self.floating_panes_stack {
+ floating_panes_stack.visible_sixel_image_chunks(
+ sixel_image_chunks,
+ z_index,
+ &character_cell_size,
+ )
+ } else {
+ sixel_image_chunks
+ };
+ for client_id in client_ids {
+ let entry = self.sixel_chunks.entry(client_id).or_insert_with(Vec::new);
+ entry.append(&mut sixel_chunks.clone());
+ }
+ }
+ }
pub fn serialize(&mut self) -> HashMap<ClientId, String> {
let mut serialized_render_instructions = HashMap::new();
@@ -256,9 +341,11 @@ impl Output {
}
// append the actual vte
- client_serialized_render_instructions.push_str(&serialize_character_chunks(
+ client_serialized_render_instructions.push_str(&serialize_chunks(
client_character_chunks,
+ self.sixel_chunks.get(&client_id),
self.link_handler.as_mut(),
+ &mut self.sixel_image_store.borrow_mut(),
)); // TODO: less allocations?
// append post-vte instructions for this client
@@ -319,6 +406,26 @@ impl FloatingPanesStack {
}
visible_chunks
}
+ pub fn visible_sixel_image_chunks(
+ &self,
+ mut sixel_image_chunks: Vec<SixelImageChunk>,
+ z_index: Option<usize>,
+ character_cell_size: &SizeInPixels,
+ ) -> Vec<SixelImageChunk> {
+ let z_index = z_index.unwrap_or(0);
+ let mut chunks_to_check: Vec<SixelImageChunk> = sixel_image_chunks.drain(..).collect();
+ let panes_to_check = self.layers.iter().skip(z_index);
+ for pane_geom in panes_to_check {
+ let chunks_to_check_against_this_pane: Vec<SixelImageChunk> =
+ chunks_to_check.drain(..).collect();
+ for s_chunk in chunks_to_check_against_this_pane {
+ let mut uncovered_chunks =
+ self.remove_covered_sixel_parts(pane_geom, &s_chunk, character_cell_size);
+ chunks_to_check.append(&mut uncovered_chunks);
+ }
+ }
+ chunks_to_check
+ }
fn remove_covered_parts(
&self,
pane_geom: &PaneGeom,
@@ -368,6 +475,165 @@ impl FloatingPanesStack {
};
None
}
+ fn remove_covered_sixel_parts(
+ &self,
+ pane_geom: &PaneGeom,
+ s_chunk: &SixelImageChunk,
+ character_cell_size: &SizeInPixels,
+ ) -> Vec<SixelImageChunk> {
+ // round these up to the nearest cell edge
+ let rounded_sixel_image_pixel_height =
+ if s_chunk.sixel_image_pixel_height % character_cell_size.height > 0 {
+ let modulus = s_chunk.sixel_image_pixel_height % character_cell_size.height;
+ s_chunk.sixel_image_pixel_height + (character_cell_size.height - modulus)
+ } else {
+ s_chunk.sixel_image_pixel_height
+ };
+ let rounded_sixel_image_pixel_width =
+ if s_chunk.sixel_image_pixel_width % character_cell_size.width > 0 {
+ let modulus = s_chunk.sixel_image_pixel_width % character_cell_size.width;
+ s_chunk.sixel_image_pixel_width + (character_cell_size.width - modulus)
+ } else {
+ s_chunk.sixel_image_pixel_width
+ };
+
+ let pane_top_edge = pane_geom.y * character_cell_size.height;
+ let pane_left_edge = pane_geom.x * character_cell_size.width;
+ let pane_bottom_edge = (pane_geom.y + pane_geom.rows.as_usize().saturating_sub(1))
+ * character_cell_size.height;
+ let pane_right_edge =
+ (pane_geom.x + pane_geom.cols.as_usize().saturating_sub(1)) * character_cell_size.width;
+ let s_chunk_top_edge = s_chunk.cell_y * character_cell_size.height;
+ let s_chunk_bottom_edge = s_chunk_top_edge + rounded_sixel_image_pixel_height;
+ let s_chunk_left_edge = s_chunk.cell_x * character_cell_size.width;
+ let s_chunk_right_edge = s_chunk_left_edge + rounded_sixel_image_pixel_width;
+
+ let mut uncovered_chunks = vec![];
+ let pane_covers_chunk_completely = pane_top_edge <= s_chunk_top_edge
+ && pane_bottom_edge >= s_chunk_bottom_edge
+ && pane_left_edge <= s_chunk_left_edge
+ && pane_right_edge >= s_chunk_right_edge;
+ let pane_intersects_with_chunk_vertically = (pane_left_edge >= s_chunk_left_edge
+ && pane_left_edge <= s_chunk_right_edge)
+ || (pane_right_edge >= s_chunk_left_edge && pane_right_edge <= s_chunk_right_edge)
+ || (pane_left_edge <= s_chunk_left_edge && pane_right_edge >= s_chunk_right_edge);
+ let pane_intersects_with_chunk_horizontally = (pane_top_edge >= s_chunk_top_edge
+ && pane_top_edge <= s_chunk_bottom_edge)
+ || (pane_bottom_edge >= s_chunk_top_edge && pane_bottom_edge <= s_chunk_bottom_edge)
+ || (pane_top_edge <= s_chunk_top_edge && pane_bottom_edge >= s_chunk_bottom_edge);
+ if pane_covers_chunk_completely {
+ return uncovered_chunks;
+ }
+ if pane_top_edge >= s_chunk_top_edge
+ && pane_top_edge <= s_chunk_bottom_edge
+ && pane_intersects_with_chunk_vertically
+ {
+ // pane covers image bottom
+ let top_image_chunk = SixelImageChunk {
+ cell_x: s_chunk.cell_x,
+ cell_y: s_chunk.cell_y,
+ sixel_image_pixel_x: s_chunk.sixel_image_pixel_x,
+ sixel_image_pixel_y: s_chunk.sixel_image_pixel_y,
+ sixel_image_pixel_width: rounded_sixel_image_pixel_width,
+ sixel_image_pixel_height: pane_top_edge - s_chunk_top_edge,
+ sixel_image_id: s_chunk.sixel_image_id,
+ };
+ uncovered_chunks.push(top_image_chunk);
+ }
+ if pane_bottom_edge <= s_chunk_bottom_edge
+ && pane_bottom_edge >= s_chunk_top_edge
+ && pane_intersects_with_chunk_vertically
+ {
+ // pane covers image top
+ let bottom_image_chunk = SixelImageChunk {
+ cell_x: s_chunk.cell_x,
+ cell_y: (pane_bottom_edge / character_cell_size.height) + 1,
+ sixel_image_pixel_x: s_chunk.sixel_image_pixel_x,
+ sixel_image_pixel_y: s_chunk.sixel_image_pixel_y
+ + (pane_bottom_edge - s_chunk_top_edge)
+ + character_cell_size.height,
+ sixel_image_pixel_width: rounded_sixel_image_pixel_width,
+ sixel_image_pixel_height: (rounded_sixel_image_pixel_height
+ - (pane_bottom_edge - s_chunk_top_edge))
+ .saturating_sub(character_cell_size.height),
+ sixel_image_id: s_chunk.sixel_image_id,
+ };
+ uncovered_chunks.push(bottom_image_chunk);
+ }
+ if pane_left_edge >= s_chunk_left_edge
+ && pane_left_edge <= s_chunk_right_edge
+ && pane_intersects_with_chunk_horizontally
+ {
+ // pane covers image right
+ let sixel_image_pixel_y = if s_chunk_top_edge < pane_top_edge {
+ s_chunk.sixel_image_pixel_y + (pane_top_edge - s_chunk_top_edge)
+ } else {
+ s_chunk.sixel_image_pixel_y
+ };
+ let max_image_height = if s_chunk_top_edge < pane_top_edge {
+ rounded_sixel_image_pixel_height.saturating_sub(pane_top_edge - s_chunk_top_edge)
+ } else {
+ rounded_sixel_image_pixel_height
+ };
+ let left_image_chunk = SixelImageChunk {
+ cell_x: s_chunk.cell_x,
+ // if the pane_top_edge is lower than the image, we want to start there, because we
+ // already cut that part above when checking if the pane covered the chunk bottom
+ cell_y: std::cmp::max(s_chunk.cell_y, pane_top_edge / character_cell_size.height),
+ sixel_image_pixel_x: s_chunk.sixel_image_pixel_x,
+ sixel_image_pixel_y,
+ sixel_image_pixel_width: rounded_sixel_image_pixel_width
+ .saturating_sub(s_chunk_right_edge.saturating_sub(pane_left_edge)),
+ sixel_image_pixel_height: std::cmp::min(
+ pane_bottom_edge - pane_top_edge + character_cell_size.height,
+ max_image_height,
+ ),
+ sixel_image_id: s_chunk.sixel_image_id,
+ };
+ uncovered_chunks.push(left_image_chunk);
+ }
+ if pane_right_edge <= s_chunk_right_edge
+ && pane_right_edge >= s_chunk_left_edge
+ && pane_intersects_with_chunk_horizontally
+ {
+ // pane covers image left
+ let sixel_image_pixel_y = if s_chunk_top_edge < pane_top_edge {
+ s_chunk.sixel_image_pixel_y + (pane_top_edge - s_chunk_top_edge)
+ } else {
+ s_chunk.sixel_image_pixel_y
+ };
+ let max_image_height = if s_chunk_top_edge < pane_top_edge {
+ rounded_sixel_image_pixel_height.saturating_sub(pane_top_edge - s_chunk_top_edge)
+ } else {
+ rounded_sixel_image_pixel_height
+ };
+ let sixel_image_pixel_x = s_chunk.sixel_image_pixel_x
+ + (pane_right_edge - s_chunk_left_edge)
+ + character_cell_size.width;
+ let right_image_chunk = SixelImageChunk {
+ cell_x: (pane_right_edge / character_cell_size.width) + 1,
+ // if the pane_top_edge is lower than the image, we want to start there, because we
+ // already cut that part above when checking if the pane covered the chunk bottom
+ cell_y: std::cmp::max(s_chunk.cell_y, pane_top_edge / character_cell_size.height),
+ sixel_image_pixel_x,
+ sixel_image_pixel_y,
+ sixel_image_pixel_width: (rounded_sixel_image_pixel_width
+ .saturating_sub(pane_right_edge - s_chunk_left_edge))
+ .saturating_sub(character_cell_size.width),
+ sixel_image_pixel_height: std::cmp::min(
+ pane_bottom_edge - pane_top_edge + character_cell_size.height,
+ max_image_height,
+ ),
+ sixel_image_id: s_chunk.sixel_image_id,
+ };
+ uncovered_chunks.push(right_image_chunk);
+ }
+ if uncovered_chunks.is_empty() {
+ // the pane doesn't cover the chunk at all, so we return it as is
+ uncovered_chunks.push(*s_chunk);
+ }
+ uncovered_chunks
+ }
}
#[derive(Debug, Clone, Default)]
@@ -379,6 +645,17 @@ pub struct CharacterChunk {
selection_and_background_color: Option<(Selection, AnsiCode)>,
}
+#[derive(Debug, Clone, Copy, Default)]
+pub struct SixelImageChunk {
+ pub cell_x: usize,
+ pub cell_y: usize,
+ pub sixel_image_pixel_x: usize,
+ pub sixel_image_pixel_y: usize,
+ pub sixel_image_pixel_width: usize,
+ pub sixel_image_pixel_height: usize,
+ pub sixel_image_id: usize,
+}
+
impl CharacterChunk {
pub fn new(terminal_characters: Vec<TerminalCharacter>, x: usize, y: usize) -> Self {
CharacterChunk {
@@ -480,8 +757,8 @@ impl CharacterChunk {
#[derive(Clone, Debug)]
pub struct OutputBuffer {
- changed_lines: Vec<usize>, // line index
- should_update_all_lines: bool,
+ pub changed_lines: Vec<usize>, // line index
+ pub should_update_all_lines: bool,
}
impl Default for OutputBuffer {
@@ -520,6 +797,7 @@ impl OutputBuffer {
for line_index in 0..viewport_height {
let terminal_characters =
self.extract_line_from_viewport(line_index, viewport, viewport_width);
+
let x = x_offset; // right now we only buffer full lines as this doesn't seem to have a huge impact on performance, but the infra is here if we want to change this
let y = line_index + y_offset;
changed_chunks.push(CharacterChunk::new(terminal_characters, x, y));
@@ -568,4 +846,42 @@ impl OutputBuffer {
},
}
}
+ pub fn changed_rects_in_viewport(&self, viewport_height: usize) -> HashMap<usize, usize> {
+ // group the changed lines into "changed_rects", which indicate where the line starts (the
+ // hashmap key) and how many lines are in there (its value)
+ let mut changed_rects: HashMap<usize, usize> = HashMap::new(); // <start_line_index, line_count>
+ let mut last_changed_line_index: Option<usize> = None;
+ let mut changed_line_count = 0;
+ let mut add_changed_line = |line_index| match last_changed_line_index.as_mut() {
+ Some(changed_line_index) => {
+ if *changed_line_index + changed_line_count == line_index {
+ changed_line_count += 1
+ } else {
+ changed_rects.insert(*changed_line_index, changed_line_count);
+ last_changed_line_index = Some(line_index);
+ changed_line_count = 1;
+ }
+ },
+ None => {
+ last_changed_line_index = Some(line_index);
+ changed_line_count = 1;
+ },
+ };
+
+ // TODO: move this whole thing to output_buffer
+ if self.should_update_all_lines {
+ // for line_index in 0..self.viewport.len() {
+ for line_index in 0..viewport_height {
+ add_changed_line(line_index);
+ }
+ } else {
+ for line_index in self.changed_lines.iter().copied() {
+ add_changed_line(line_index);
+ }
+ }
+ if let Some(changed_line_index) = last_changed_line_index {
+ changed_rects.insert(changed_line_index, changed_line_count);
+ }
+ changed_rects
+ }
}
diff --git a/zellij-server/src/panes/grid.rs b/zellij-server/src/panes/grid.rs
index 23df7948..8c6e3e09 100644
--- a/zellij-server/src/panes/grid.rs
+++ b/zellij-server/src/panes/grid.rs
@@ -1,4 +1,6 @@
+use super::sixel::{PixelRect, SixelGrid, SixelImageStore};
use std::cell::RefCell;
+use std::collections::HashMap;
use std::rc::Rc;
use unicode_width::UnicodeWidthChar;
use zellij_utils::regex::Regex;
@@ -24,7 +26,7 @@ pub const MAX_TITLE_STACK_SIZE: usize = 1000;
use vte::{Params, Perform};
use zellij_utils::{consts::VERSION, shared::version_number};
-use crate::output::{CharacterChunk, OutputBuffer};
+use crate::output::{CharacterChunk, OutputBuffer, SixelImageChunk};
use crate::panes::alacritty_functions::{parse_number, xparse_color};
use crate::panes::link_handler::LinkHandler;
use crate::panes::selection::Selection;
@@ -112,6 +114,7 @@ fn get_top_canonical_row_and_wraps(rows: &mut Vec<Row>) -> Vec<Row> {
fn transfer_rows_from_lines_above_to_viewport(
lines_above: &mut VecDeque<Row>,
viewport: &mut Vec<Row>,
+ sixel_grid: &mut SixelGrid,
count: usize,
max_viewport_width: usize,
) -> usize {
@@ -143,7 +146,7 @@ fn transfer_rows_from_lines_above_to_viewport(
}
if !next_lines.is_empty() {
let excess_row = Row::from_rows(next_lines, 0);
- bounded_push(lines_above, excess_row);
+ bounded_push(lines_above, sixel_grid, excess_row);
}
match usize::try_from(lines_added_to_viewport) {
Ok(n) => n,
@@ -154,6 +157,7 @@ fn transfer_rows_from_lines_above_to_viewport(
fn transfer_rows_from_viewport_to_lines_above(
viewport: &mut Vec<Row>,
lines_above: &mut VecDeque<Row>,
+ sixel_grid: &mut SixelGrid,
count: usize,
max_viewport_width: usize,
) -> isize {
@@ -176,7 +180,7 @@ fn transfer_rows_from_viewport_to_lines_above(
break; // no more rows
}
}
- let dropped_line_width = bounded_push(lines_above, next_lines.remove(0));
+ let dropped_line_width = bounded_push(lines_above, sixel_grid, next_lines.remove(0));
if let Some(width) = dropped_line_width {
transferred_rows_count -=
calculate_row_display_height(width, max_viewport_width) as isize;
@@ -232,11 +236,12 @@ fn transfer_rows_from_lines_below_to_viewport(
}
}
-fn bounded_push(vec: &mut VecDeque<Row>, value: Row) -> Option<usize> {
+fn bounded_push(vec: &mut VecDeque<Row>, sixel_grid: &mut SixelGrid, value: Row) -> Option<usize> {
let mut dropped_line_width = None;
if vec.len() >= *SCROLL_BUFFER_SIZE.get().unwrap() {
let line = vec.pop_front();
if let Some(line) = line {
+ sixel_grid.offset_grid_top();
dropped_line_width = Some(line.width());
}
}
@@ -298,7 +303,7 @@ pub struct Grid {
viewport: Vec<Row>,
lines_below: Vec<Row>,
horizontal_tabstops: BTreeSet<usize>,
- alternate_lines_above_viewport_and_cursor: Option<(VecDeque<Row>, Vec<Row>, Cursor)>,
+ alternate_screen_state: Option<AlternateScreenState>,
cursor: Cursor,
saved_cursor_position: Option<Cursor>,
// FIXME: change scroll_region to be (usize, usize) - where the top line is always the first
@@ -309,14 +314,17 @@ pub struct Grid {
active_charset: CharsetIndex,
preceding_char: Option<TerminalCharacter>,
terminal_emulator_colors: Rc<RefCell<Palette>>,
+ terminal_emulator_color_codes: Rc<RefCell<HashMap<usize, String>>>,
output_buffer: OutputBuffer,
title_stack: Vec<String>,
character_cell_size: Rc<RefCell<Option<SizeInPixels>>>,
+ sixel_grid: SixelGrid,
pub changed_colors: Option<[Option<AnsiCode>; 256]>,
pub should_render: bool,
pub cursor_key_mode: bool, // DECCKM - when set, cursor keys should send ANSI direction codes (eg. "OD") instead of the arrow keys (eg. "")
pub bracketed_paste_mode: bool, // when set, paste instructions to the terminal should be escaped with a special sequence
pub erasure_mode: bool, // ERM
+ pub sixel_scrolling: bool, // DECSDM
pub insert_mode: bool,
pub disable_linewrap: bool,
pub clear_viewport_before_rendering: bool,
@@ -334,7 +342,41 @@ pub struct Grid {
impl Debug for Grid {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
- for (i, row) in self.viewport.iter().enumerate() {
+ let mut buffer: Vec<Row> = self.viewport.clone();
+ // pad buffer
+ for _ in buffer.len()..self.height {
+ buffer.push(Row::new(self.width).canonical());
+ }
+
+ // display sixel placeholder
+ let sixel_indication_character = |x| {
+ let sixel_indication_word = "Sixel";
+ sixel_indication_word
+ .chars()
+ .nth(x % sixel_indication_word.len())
+ .unwrap()
+ };
+ for image_coordinates in self
+ .sixel_grid
+ .image_cell_coordinates_in_viewport(self.height, self.lines_above.len())
+ {
+ let (image_top_edge, image_bottom_edge, image_left_edge, image_right_edge) =
+ image_coordinates;
+ for y in image_top_edge..image_bottom_edge {
+ let row = buffer.get_mut(y).unwrap();
+ for x in image_left_edge..image_right_edge {
+ let fake_sixel_terminal_character = TerminalCharacter {
+ character: sixel_indication_character(x),
+ width: 1,
+ styles: Default::default(),
+ };
+ row.add_character_at(fake_sixel_terminal_character, x);
+ }
+ }
+ }
+
+ // display terminal characters with stripped styles
+ for (i, row) in buffer.iter().enumerate() {
if row.is_canonical {
writeln!(f, "{:02?} (C): {:?}", i, row)?;
} else {
@@ -350,9 +392,12 @@ impl Grid {
rows: usize,
columns: usize,
terminal_emulator_colors: Rc<RefCell<Palette>>,
+ terminal_emulator_color_codes: Rc<RefCell<HashMap<usize, String>>>,
link_handler: Rc<RefCell<LinkHandler>>,
character_cell_size: Rc<RefCell<Option<SizeInPixels>>>,
+ sixel_image_store: Rc<RefCell<SixelImageStore>>,
) -> Self {
+ let sixel_grid = SixelGrid::new(character_cell_size.clone(), sixel_image_store);
Grid {
lines_above: VecDeque::with_capacity(
// .get_or_init() is used instead of .get().unwrap() to prevent
@@ -372,13 +417,15 @@ impl Grid {
cursor_key_mode: false,
bracketed_paste_mode: false,
erasure_mode: false,
+ sixel_scrolling: false,
insert_mode: false,
disable_linewrap: false,
- alternate_lines_above_viewport_and_cursor: None,
+ alternate_screen_state: None,
clear_viewport_before_rendering: false,
active_charset: Default::default(),
pending_messages_to_pty: vec![],
terminal_emulator_colors,
+ terminal_emulator_color_codes,
output_buffer: Default::default(),
selection: Default::default(),
title_stack: vec![],
@@ -390,6 +437,7 @@ impl Grid {
scrollback_buffer_lines: 0,
mouse_mode: false,
character_cell_size,
+ sixel_grid,
}
}
pub fn render_full_viewport(&mut self) {
@@ -534,6 +582,7 @@ impl Grid {
let transferred_rows_height = transfer_rows_from_lines_above_to_viewport(
&mut self.lines_above,
&mut self.viewport,
+ &mut self.sixel_grid,
1,
self.width,
);
@@ -560,7 +609,8 @@ impl Grid {
last_line_above
};
- let dropped_line_width = bounded_push(&mut self.lines_above, line_to_push_up);
+ let dropped_line_width =
+ bounded_push(&mut self.lines_above, &mut self.sixel_grid, line_to_push_up);
if let Some(width) = dropped_line_width {
let dropped_line_height = calculate_row_display_height(width, self.width);
@@ -607,7 +657,8 @@ impl Grid {
return;
}
self.selection.reset();
- if new_columns != self.width && self.alternate_lines_above_viewport_and_cursor.is_none() {
+ self.sixel_grid.character_cell_size_possibly_changed();
+ if new_columns != self.width && self.alternate_screen_state.is_none() {
self.horizontal_tabstops = create_horizontal_tabstops(new_columns);
let mut cursor_canonical_line_index = self.cursor_canonical_line_index();
let cursor_index_in_canonical_line = self.cursor_index_in_canonical_line();
@@ -697,6 +748,7 @@ impl Grid {
transfer_rows_from_lines_above_to_viewport(
&mut self.lines_above,
&mut self.viewport,
+ &mut self.sixel_grid,
row_count_to_transfer,
new_columns,
);
@@ -713,6 +765,7 @@ impl Grid {
transfer_rows_from_viewport_to_lines_above(
&mut self.viewport,
&mut self.lines_above,
+ &mut self.sixel_grid,
row_count_to_transfer,
new_columns,
);
@@ -725,9 +778,7 @@ impl Grid {
saved_cursor_position.y = new_cursor_y;
saved_cursor_position.x = new_cursor_x;
};
- } else if new_columns != self.width
- && self.alternate_lines_above_viewport_and_cursor.is_some()
- {
+ } else if new_columns != self.width && self.alternate_screen_state.is_some() {
// in alternate screen just truncate exceeding width
for row in &mut self.viewport {
if row.width() >= new_columns {
@@ -744,6 +795,7 @@ impl Grid {
transfer_rows_from_lines_above_to_viewport(
&mut self.lines_above,
&mut self.viewport,
+ &mut self.sixel_grid,
row_count_to_transfer,
new_columns,
);
@@ -763,13 +815,16 @@ impl Grid {
} else {
self.cursor.y -= row_count_to_transfer;
if let Some(saved_cursor_position) = self.saved_cursor_position.as_mut() {
- saved_cursor_position.y -= row_count_to_transfer
+ saved_cursor_position.y = saved_cursor_position
+ .y
+ .saturating_sub(row_count_to_transfer);
};
}
- if self.alternate_lines_above_viewport_and_cursor.is_none() {
+ if self.alternate_screen_state.is_none() {
transfer_rows_from_viewport_to_lines_above(
&mut self.viewport,
&mut self.lines_above,
+ &mut self.sixel_grid,
row_count_to_transfer,
new_columns,
);
@@ -813,16 +868,34 @@ impl Grid {
}
lines
}
- pub fn read_changes(&mut self, x_offset: usize, y_offset: usize) -> Vec<CharacterChunk> {
- let changes = self.output_buffer.changed_chunks_in_viewport(
+ pub fn read_changes(
+ &mut self,
+ x_offset: usize,
+ y_offset: usize,
+ ) -> (Vec<CharacterChunk>, Vec<SixelImageChunk>) {
+ let changed_character_chunks = self.output_buffer.changed_chunks_in_viewport(
&self.viewport,
self.width,
self.height,
x_offset,
y_offset,
);
+ let changed_rects = self
+ .output_buffer
+ .changed_rects_in_viewport(self.viewport.len());
+ let changed_sixel_image_chunks = self.sixel_grid.changed_sixel_chunks_in_viewport(
+ changed_rects,
+ self.lines_above.len(),
+ self.width,
+ x_offset,
+ y_offset,
+ );
+ if let Some(image_ids_to_reap) = self.sixel_grid.drain_image_ids_to_reap() {
+ self.sixel_grid.reap_images(image_ids_to_reap);
+ }
self.output_buffer.clear();
- changes
+
+ (changed_character_chunks, changed_sixel_image_chunks)
}
pub fn cursor_coordinates(&self) -> Option<(usize, usize)> {
if self.cursor.is_hidden {
@@ -901,7 +974,7 @@ impl Grid {
}
}
pub fn fill_viewport(&mut self, character: TerminalCharacter) {
- if self.alternate_lines_above_viewport_and_cursor.is_some() {
+ if self.alternate_screen_state.is_some() {
self.viewport.clear();
} else {
self.transfer_rows_to_lines_above(self.viewport.len())
@@ -927,7 +1000,7 @@ impl Grid {
return;
}
if scroll_region_bottom == self.height - 1 && scroll_region_top == 0 {
- if self.alternate_lines_above_viewport_and_cursor.is_none() {
+ if self.alternate_screen_state.is_none() {
self.transfer_rows_to_lines_above(1);
} else {
self.viewport.remove(0);
@@ -963,9 +1036,10 @@ impl Grid {
}
if self.cursor.y == self.height - 1 {
if self.scroll_region.is_none() {
- if self.alternate_lines_above_viewport_and_cursor.is_none() {
+ if self.alternate_screen_state.is_none() {
self.transfer_rows_to_lines_above(1);
} else {
+ self.sixel_grid.offset_grid_top();
self.viewport.remove(0);
}
@@ -997,6 +1071,27 @@ impl Grid {
} else {
row.add_character_at(terminal_character, self.cursor.x);
}
+ if let Some(character_cell_size) = *self.character_cell_size.borrow() {
+ let scrollback_size_in_pixels =
+ self.lines_above.len() * character_cell_size.height;
+ let absolute_x_in_pixels = self.cursor.x * character_cell_size.width;
+ let absolute_y_in_pixels =
+ scrollback_size_in_pixels + (self.cursor.y * character_cell_size.height);
+ let rect_to_cut_out = PixelRect {
+ x: absolute_x_in_pixels,
+ y: absolute_y_in_pixels as isize,
+ width: character_cell_size.width,
+ height: character_cell_size.height,
+ };
+ if let Some(images_to_cut_out) =
+ self.sixel_grid.cut_off_rect_from_images(rect_to_cut_out)
+ {
+ for (image_id, rect_in_image_to_cut_out) in images_to_cut_out {
+ self.sixel_grid
+ .remove_pixels_from_image(image_id, rect_in_image_to_cut_out);
+ }
+ }
+ }
self.output_buffer.update_line(self.cursor.y);
},
None => {
@@ -1088,7 +1183,7 @@ impl Grid {
fn line_wrap(&mut self) {
self.cursor.x = 0;
if self.cursor.y == self.height - 1 {
- if self.alternate_lines_above_viewport_and_cursor.is_none() {
+ if self.alternate_screen_state.is_none() {
self.transfer_rows_to_lines_above(1);
} else {
self.viewport.remove(0);
@@ -1333,7 +1428,7 @@ impl Grid {
self.lines_above = VecDeque::with_capacity(*SCROLL_BUFFER_SIZE.get().unwrap());
self.lines_below = vec![];
self.viewport = vec![Row::new(self.width).canonical()];
- self.alternate_lines_above_viewport_and_cursor = None;
+ self.alternate_screen_state = None;
self.cursor_key_mode = false;
self.scroll_region = None;
self.clear_viewport_before_rendering = true;
@@ -1346,6 +1441,10 @@ impl Grid {
self.output_buffer.update_all_lines();
self.changed_colors = None;
self.scrollback_buffer_lines = 0;
+ self.sixel_scrolling = false;
+ if let Some(images_to_reap) = self.sixel_grid.clear() {
+ self.sixel_grid.reap_images(images_to_reap);
+ }
}
fn set_preceding_character(&mut self, terminal_character: TerminalCharacter) {
self.preceding_char = Some(terminal_character);
@@ -1486,6 +1585,7 @@ impl Grid {
let transferred_rows_count = transfer_rows_from_viewport_to_lines_above(
&mut self.viewport,
&mut self.lines_above,
+ &mut self.sixel_grid,
count,
self.width,
);
@@ -1493,6 +1593,57 @@ impl Grid {
self.scrollback_buffer_lines =
subtract_isize_from_usize(self.scrollback_buffer_lines, transferred_rows_count);
}
+ fn move_cursor_down_by_pixels(&mut self, pixel_count: usize) {
+ if let Some(character_cell_size) = {
+ let c = *self.character_cell_size.borrow();
+ c
+ } {
+ // thanks borrow checker
+ let pixel_height = character_cell_size.height;
+ let to_move = (pixel_count as f64 / pixel_height as f64).ceil() as usize;
+ for _ in 0..to_move {
+ self.add_canonical_line();
+ }
+ }
+ }
+ fn current_cursor_pixel_coordinates(&self) -> Option<(usize, usize)> {
+ // (x, y)
+ if let Some(character_cell_size) = *self.character_cell_size.borrow() {
+ let line_count_in_scrollback = self.lines_above.len();
+ let y_coordinates =
+ (line_count_in_scrollback + self.cursor.y) * character_cell_size.height;
+ let x_coordinates = self.cursor.x * character_cell_size.width;
+ Some((x_coordinates, y_coordinates))
+ } else {
+ None
+ }
+ }
+ fn create_sixel_image(&mut self) {
+ if let Some((x_pixel_coordinates, y_pixel_coordinates)) =
+ self.current_cursor_pixel_coordinates()
+ {
+ let (x_pixel_coordinates, y_pixel_coordinates) = if self.sixel_scrolling {
+ let scrollback_pixel_height =
+ self.lines_above.len() * self.character_cell_size.borrow().unwrap().height;
+ (0, scrollback_pixel_height)
+ } else {
+ (x_pixel_coordinates, y_pixel_coordinates)
+ };
+ let new_image_id = self.sixel_grid.next_image_id();
+ let new_sixel_image =
+ self.sixel_grid
+ .end_image(new_image_id, x_pixel_coordinates, y_pixel_coordinates);
+ if let Some(new_sixel_image) = new_sixel_image {
+ let (image_pixel_height, _image_pixel_width) = new_sixel_image.pixel_size();
+ self.sixel_grid
+ .new_sixel_image(new_image_id, new_sixel_image);
+ if !self.sixel_scrolling {
+ self.move_cursor_down_by_pixels(image_pixel_height);
+ }
+ self.render_full_viewport(); // TODO: this could be optimized if it's a performance bottleneck
+ }
+ }
+ }
}
impl Perform for Grid {
@@ -1543,16 +1694,40 @@ impl Perform for Grid {
}
}
- fn hook(&mut self, _params: &Params, _intermediates: &[u8], _ignore: bool, _c: char) {
- // TBD
+ fn hook(&mut self, params: &Params, intermediates: &[u8], _ignore: bool, c: char) {
+ if c == 'q' {
+ // we only process sixel images if we know the pixel size of each character cell,
+ // otherwise we can't reliably display them
+ if self.current_cursor_pixel_coordinates().is_some() {
+ let max_sixel_height_in_pixels = if self.sixel_scrolling {
+ let character_cell_height = self.character_cell_size.borrow().unwrap().height; // unwrap here is safe because `current_cursor_pixel_coordinates` above is only Some if it exists
+ Some(self.height * character_cell_height)
+ } else {
+ None
+ };
+ self.sixel_grid.start_image(
+ max_sixel_height_in_pixels,
+ intermediates.iter().collect(),
+ params.iter().collect(),
+ );
+ }
+ }
}
- fn put(&mut self, _byte: u8) {
- // TBD
+ fn put(&mut self, byte: u8) {
+ if self.sixel_grid.is_parsing() {
+ self.sixel_grid.handle_byte(byte);
+ // we explicitly set this to false here because in the context of Sixel, we only render the
+ // image when it's done, i.e. in the unhook method
+ self.should_render = false;
+ }
}
fn unhook(&mut self) {
- // TBD
+ if self.sixel_grid.is_parsing() {
+ self.create_sixel_image();
+ }
+ self.mark_for_rerender();
}
fn osc_dispatch(&mut self, params: &[&[u8]], bell_terminated: bool) {
@@ -1588,6 +1763,18 @@ impl Perform for Grid {
}
self.changed_colors.as_mut().unwrap()[i as usize] = Some(c);
return;
+ } else if chunk.get(1).as_ref().and_then(|c| c.get(0)) == Some(&b'?') {
+ if let Some(index) = index {
+ let terminal_emulator_color_codes =
+ self.terminal_emulator_color_codes.borrow();
+ let color = terminal_emulator_color_codes.get(&(index as usize));
+ if let Some(color) = color {
+ let color_response_message =
+ format!("\u{1b}]4;{};{}{}", index, color, terminator);
+ self.pending_messages_to_pty
+ .push(color_response_message.as_bytes().to_vec());
+ }
+ }
}
}
},
@@ -1808,18 +1995,22 @@ impl Perform for Grid {
self.bracketed_paste_mode = false;
},
Some(1049) => {
- // leave alternate buffer
- if let Some((
- alternative_lines_above,
- alternative_viewport,
- alternative_cursor,
- )) = &mut self.alternate_lines_above_viewport_and_cursor
+ if let Some(mut alternate_screen_state) = self.alternate_screen_state.take()
{
- std::mem::swap(&mut self.lines_above, alternative_lines_above);
- std::mem::swap(&mut self.viewport, alternative_viewport);
- std::mem::swap(&mut self.cursor, alternative_cursor);
+ if let Some(image_ids_to_reap) = self.sixel_grid.clear() {
+ // reap images before dropping the alternate_screen_state contents
+ // - we can't implement a drop method for this because the store is
+ // outside of the alternate_screen_state struct
+ self.sixel_grid.reap_images(image_ids_to_reap);
+ }
+ alternate_screen_state.apply_contents_to(
+ &mut self.lines_above,
+ &mut self.viewport,
+ &mut self.cursor,
+ &mut self.sixel_grid,
+ );
}
- self.alternate_lines_above_viewport_and_cursor = None;
+ self.alternate_screen_state = None;
self.clear_viewport_before_rendering = true;
self.force_change_size(self.height, self.width); // the alternative_viewport might have been of a different size...
self.mark_for_rerender();
@@ -1844,6 +2035,9 @@ impl Perform for Grid {
Some(7) => {
self.disable_linewrap = true;
},
+ Some(80) => {
+ self.sixel_scrolling = false;
+ },
Some(1006) => {
self.mouse_mode = false;
},
@@ -1878,8 +2072,17 @@ impl Perform for Grid {
vec![Row::new(self.width).canonical()],
);
let current_cursor = std::mem::replace(&mut self.cursor, Cursor::new(0, 0));
- self.alternate_lines_above_viewport_and_cursor =
- Some((current_lines_above, current_viewport, current_cursor));
+ let sixel_image_store = self.sixel_grid.sixel_image_store.clone();
+ let alternate_sixelgrid = std::mem::replace(
+ &mut self.sixel_grid,
+ SixelGrid::new(self.character_cell_size.clone(), sixel_image_store),
+ );
+ self.alternate_screen_state = Some(AlternateScreenState::new(
+ current_lines_above,
+ current_viewport,
+ current_cursor,
+ alternate_sixelgrid,
+ ));
self.clear_viewport_before_rendering = true;
self.scrollback_buffer_lines = self.recalculate_scrollback_buffer_count();
self.output_buffer.update_all_lines(); // make sure the screen gets cleared in the next render
@@ -1900,6 +2103,9 @@ impl Perform for Grid {
Some(7) => {
self.disable_linewrap = false;
},
+ Some(80) => {
+ self.sixel_scrolling = true;
+ },
Some(1006) => {
self.mouse_mode = true;
},
@@ -1969,9 +2175,45 @@ impl Perform for Grid {
let line_count = next_param_or(1);
self.rotate_scroll_region_up(line_count as usize);
} else if c == 'S' {
- // move scroll up
- let count = next_param_or(1);
- self.rotate_scroll_region_down(count);
+ let first_intermediate_is_questionmark = match intermediates.get(0) {
+ Some(b'?') => true,
+ None => false,
+ _ => false,
+ };
+ if first_intermediate_is_questionmark {
+ let query_type = params_iter.next();
+ let is_query = params_iter.next() == Some(&[1]);
+ if is_query {
+ // XTSMGRAPHICS
+ match query_type {
+ Some(&[1]) => {
+ // number of color registers
+ let response = "\u{1b}[?1;0;65536S";
+ self.pending_messages_to_pty
+ .push(response.as_bytes().to_vec());
+ },
+ Some(&[2]) => {
+ // Sixel graphics geometry in pixels
+ if let Some(character_cell_size) = *self.character_cell_size.borrow() {
+ let sixel_area_geometry = format!(
+ "\u{1b}[?2;0;{};{}S",
+ character_cell_size.width * self.width,
+ character_cell_size.height * self.height,
+ );
+ self.pending_messages_to_pty
+ .push(sixel_area_geometry.as_bytes().to_vec());
+ }
+ },
+ _ => {
+ // unsupported (eg. ReGIS graphics geometry)
+ },
+ }
+ }
+ } else {
+ // move scroll up
+ let count = next_param_or(1);
+ self.rotate_scroll_region_down(count);
+ }
} else if c == 's' {
self.save_cursor_position();
} else if c == 'u' {
@@ -2022,6 +2264,11 @@ impl Perform for Grid {
if let Some(cursor_shape) = shape {
self.cursor.change_shape(cursor_shape);
}
+ } else if matches!(intermediates.get(0), Some(b'>')) {
+ let version = version_number(VERSION);
+ let xtversion = format!("\u{1b}P>|Zellij({})\u{1b}\\", version);
+ self.pending_messages_to_pty
+ .push(xtversion.as_bytes().to_vec());
}
} else if c == 'Z' {
for _ in 0..next_param_or(1) {
@@ -2033,7 +2280,7 @@ impl Perform for Grid {
match intermediates.get(0) {
None | Some(0) => {
// primary device attributes
- let terminal_capabilities = "\u{1b}[?6c";
+ let terminal_capabilities = "\u{1b}[?64;4c";
self.pending_messages_to_pty
.push(terminal_capabilities.as_bytes().to_vec());
},
@@ -2176,6 +2423,41 @@ impl Perform for Grid {
}
#[derive(Clone)]
+pub struct AlternateScreenState {
+ lines_above: VecDeque<Row>,
+ viewport: Vec<Row>,
+ cursor: Cursor,
+ sixel_grid: SixelGrid,
+}
+impl AlternateScreenState {
+ pub fn new(
+ lines_above: VecDeque<Row>,
+ viewport: Vec<Row>,
+ cursor: Cursor,
+ sixel_grid: SixelGrid,
+ ) -> Self {
+ AlternateScreenState {
+ lines_above,
+ viewport,
+ cursor,
+ sixel_grid,
+ }
+ }
+ pub fn apply_contents_to(
+ &mut self,
+ lines_above: &mut VecDeque<Row>,
+ viewport: &mut Vec<Row>,
+ cursor: &mut Cursor,
+ sixel_grid: &mut SixelGrid,
+ ) {
+ std::mem::swap(&mut self.lines_above, lines_above);
+ std::mem::swap(&mut self.viewport, viewport);
+ std::mem::swap(&mut self.cursor, cursor);
+ std::mem::swap(&mut self.sixel_grid, sixel_grid);
+ }
+}
+
+#[derive(Clone)]
pub struct Row {
pub columns: VecDeque<TerminalCharacter>,
pub is_canonical: bool,
diff --git a/zellij-server/src/panes/mod.rs b/zellij-server/src/panes/mod.rs
index c1fb31d1..569dbd42 100644
--- a/zellij-server/src/panes/mod.rs
+++ b/zellij-server/src/panes/mod.rs
@@ -4,6 +4,7 @@ pub mod grid;
pub mod link_handler;
mod plugin_pane;
pub mod selection;
+pub mod sixel;
pub mod terminal_character;
mod terminal_pane;
mod tiled_panes;
@@ -13,6 +14,7 @@ pub use floating_panes::*;
pub use grid::*;
pub use link_handler::*;
pub(crate) use plugin_pane::*;
+pub use sixel::*;
pub(crate) use terminal_character::*;
pub use terminal_pane::*;
pub use tiled_panes::*;
diff --git a/zellij-server/src/panes/plugin_pane.rs b/zellij-server/src/panes/plugin_pane.rs
index 87e0ac7e..7d56b589 100644
--- a/zellij-server/src/panes/plugin_pane.rs
+++ b/zellij-server/src/panes/plugin_pane.rs
@@ -2,7 +2,7 @@ use std::fmt::Write;
use std::sync::mpsc::channel;
use std::time::Instant;
-use crate::output::CharacterChunk;
+use crate::output::{CharacterChunk, SixelImageChunk};
use crate::panes::PaneId;
use crate::pty::VteBytes;
use crate::tab::Pane;
@@ -141,7 +141,7 @@ impl Pane for PluginPane {
fn render(
&mut self,
client_id: Option<ClientId>,
- ) -> Option<(Vec<CharacterChunk>, Option<String>)> {
+ ) -> Option<(Vec<CharacterChunk>, Option<String>, Vec<SixelImageChunk>)> {
// this is a bit of a hack but works in a pinch
client_id?;
let client_id = client_id.unwrap();
@@ -214,7 +214,7 @@ impl Pane for PluginPane {
}
}
}
- Some((vec![], Some(vte_output))) // TODO: PluginPanes should have their own grid so that we can return the non-serialized TerminalCharacters and have them participate in the render buffer
+ Some((vec![], Some(vte_output), vec![])) // TODO: PluginPanes should have their own grid so that we can return the non-serialized TerminalCharacters and have them participate in the render buffer
} else {
None
}
diff --git a/zellij-server/src/panes/sixel.rs b/zellij-server/src/panes/sixel.rs
new file mode 100644
index 00000000..b5cf0bc0
--- /dev/null
+++ b/zellij-server/src/panes/sixel.rs
@@ -0,0 +1,466 @@
+use crate::output::SixelImageChunk;
+use std::cell::RefCell;
+use std::collections::HashMap;
+use std::rc::Rc;
+
+use sixel_image::{SixelDeserializer, SixelImage};
+use sixel_tokenizer::SixelEvent;
+
+use std::fmt::Debug;
+
+use zellij_utils::pane_size::SizeInPixels;
+
+#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
+pub struct PixelRect {
+ pub x: usize,
+ pub y: isize, // this can potentially be negative (eg. when the image top has scrolled past the edge of the scrollbuffer)
+ pub width: usize,
+ pub height: usize,
+}
+
+impl PixelRect {
+ pub fn new(x: usize, y: usize, height: usize, width: usize) -> Self {
+ PixelRect {
+ x,
+ y: y as isize,
+ width,
+ height,
+ }
+ }
+ pub fn intersecting_rect(&self, other: &PixelRect) -> Option<PixelRect> {
+ // if the two rects intersect, this returns a PixelRect *relative to self*
+ let self_top_edge = self.y;
+ let self_bottom_edge = self.y + self.height as isize;
+ let self_left_edge = self.x;
+ let self_right_edge = self.x + self.width;
+ let other_top_edge = other.y;
+ let other_bottom_edge = other.y + other.height as isize;
+ let other_left_edge = other.x;
+ let other_right_edge = other.x + other.width;
+
+ let absolute_x = std::cmp::max(self_left_edge, other_left_edge);
+ let absolute_y = std::cmp::max(self_top_edge, other_top_edge);
+ let absolute_right_edge = std::cmp::min(self_right_edge, other_right_edge);
+ let absolute_bottom_edge = std::cmp::min(self_bottom_edge, other_bottom_edge);
+ let width = absolute_right_edge.saturating_sub(absolute_x);
+ let height = absolute_bottom_edge.saturating_sub(absolute_y);
+ let x = absolute_x - self.x;
+ let y = absolute_y - self.y;
+ if width > 0 && height > 0 {
+ Some(PixelRect {
+ x,
+ y,
+ width,
+ height: height as usize,
+ })
+ } else {
+ None
+ }
+ }
+}
+
+#[derive(Debug, Clone, Default)]
+pub struct SixelGrid {
+ sixel_image_locations: HashMap<usize, PixelRect>,
+ previous_cell_size: Option<SizeInPixels>,
+ character_cell_size: Rc<RefCell<Option<SizeInPixels>>>,
+ currently_parsing: Option<SixelDeserializer>,
+ image_ids_to_reap: Vec<usize>,
+ sixel_parser: Option<sixel_tokenizer::Parser>,
+ pub sixel_image_store: Rc<RefCell<SixelImageStore>>,
+}
+
+impl SixelGrid {
+ pub fn new(
+ character_cell_size: Rc<RefCell<Option<SizeInPixels>>>,
+ sixel_image_store: Rc<RefCell<SixelImageStore>>,
+ ) -> Self {
+ let previous_cell_size = *character_cell_size.borrow();
+ SixelGrid {
+ previous_cell_size,
+ character_cell_size,
+ sixel_image_store,
+ ..Default::default()
+ }
+ }
+ pub fn handle_byte(&mut self, byte: u8) {
+ self.sixel_parser
+ .as_mut()
+ .unwrap()
+ .advance(&byte, |sixel_event| {
+ if let Some(currently_parsing) = self.currently_parsing.as_mut() {
+ let _ = currently_parsing.handle_event(sixel_event);
+ }
+ });
+ }
+ pub fn handle_event(&mut self, sixel_event: SixelEvent) {
+ if let Some(currently_parsing) = self.currently_parsing.as_mut() {
+ let _ = currently_parsing.handle_event(sixel_event);
+ }
+ }
+ pub fn is_parsing(&self) -> bool {
+ self.sixel_parser.is_some()
+ }
+ pub fn start_image(
+ &mut self,
+ max_height_in_pixels: Option<usize>,
+ dcs_intermediates: Vec<&u8>,
+ dcs_params: Vec<&[u16]>,
+ ) {
+ self.sixel_parser = Some(sixel_tokenizer::Parser::new());
+ match max_height_in_pixels {
+ Some(max_height_in_pixels) => {
+ self.currently_parsing =
+ Some(SixelDeserializer::new().max_height(max_height_in_pixels));
+ },
+ None => {
+ self.currently_parsing = Some(SixelDeserializer::new());
+ },
+ }
+
+ self.handle_byte(27);
+ self.handle_byte(b'P');
+
+ for byte in dcs_intermediates {
+ self.handle_byte(*byte);
+ }
+
+ // send DCS event to parser
+ for (i, param) in dcs_params.iter().enumerate() {
+ if i != 0 {
+ self.handle_byte(b';');
+ }
+ for subparam in param.iter() {
+ let mut b = [0; 4];
+ for digit in subparam.to_string().chars() {
+ let len = digit.encode_utf8(&mut b).len();
+ for byte in b.iter().take(len) {
+ self.handle_byte(*byte);
+ }
+ }
+ }
+ }
+ self.handle_byte(b'q');
+ }
+ pub fn end_image(
+ &mut self,
+ new_image_id: usize,
+ x_pixel_coordinates: usize,
+ y_pixel_coordinates: usize,
+ ) -> Option<SixelImage> {
+ // usize is image_id
+ self.sixel_parser = None;
+ if let Some(sixel_deserializer) = self.currently_parsing.as_mut() {
+ if let Ok(sixel_image) = sixel_deserializer.create_image() {
+ let image_pixel_size = sixel_image.pixel_size();
+ let image_size_and_coordinates = PixelRect::new(
+ x_pixel_coordinates,
+ y_pixel_coordinates,
+ image_pixel_size.0,
+ image_pixel_size.1,
+ );
+
+ // here we remove images which this image covers completely to save on system
+ // resources - TODO: also do this with partial covers, eg. if several images
+ // together cover one image
+ for (image_id, pixel_rect) in &self.sixel_image_locations {
+ if let Some(intersecting_rect) =
+ pixel_rect.intersecting_rect(&image_size_and_coordinates)
+ {
+ if intersecting_rect.x == pixel_rect.x
+ && intersecting_rect.y == pixel_rect.y
+ && intersecting_rect.height == pixel_rect.height
+ && intersecting_rect.width == pixel_rect.width
+ {
+ self.image_ids_to_reap.push(*image_id);
+ }
+ }
+ }
+ for image_id in &self.image_ids_to_reap {
+ self.sixel_image_locations.remove(image_id);
+ }
+
+ self.sixel_image_locations
+ .insert(new_image_id, image_size_and_coordinates);
+ self.currently_parsing = None;
+ Some(sixel_image)
+ } else {
+ None
+ }
+ } else {
+ None
+ }
+ }
+ pub fn image_coordinates(&self) -> impl Iterator<Item = (usize, &PixelRect)> {
+ self.sixel_image_locations
+ .iter()
+ .map(|(image_id, pixel_rect)| (*image_id, pixel_rect))
+ }
+ pub fn cut_off_rect_from_images(
+ &mut self,
+ rect_to_cut_out: PixelRect,
+ ) -> Option<Vec<(usize, PixelRect)>> {
+ // if there is an image at this cursor location, this returns the image ID and the PixelRect inside the image to be removed
+ let mut ret = None;
+ for (image_id, pixel_rect) in &self.sixel_image_locations {
+ if let Some(intersecting_rect) = pixel_rect.intersecting_rect(&rect_to_cut_out) {
+ let ret = ret.get_or_insert(vec![]);
+ ret.push((*image_id, intersecting_rect));
+ }
+ }
+ ret
+ }
+ pub fn offset_grid_top(&mut self) {
+ if let Some(character_cell_size) = *self.character_cell_size.borrow() {
+ let height_to_reduce = character_cell_size.height as isize;
+ for (sixel_image_id, pixel_rect) in self.sixel_image_locations.iter_mut() {
+ pixel_rect.y -= height_to_reduce;
+ if pixel_rect.y + pixel_rect.height as isize <= 0 {
+ self.image_ids_to_reap.push(*sixel_image_id);
+ }
+ }
+ for image_id in &self.image_ids_to_reap {
+ self.sixel_image_locations.remove(image_id);
+ }
+ }
+ }
+ pub fn drain_image_ids_to_reap(&mut self) -> Option<Vec<usize>> {
+ let images_to_reap = self.image_ids_to_reap.drain(..);
+ if images_to_reap.len() > 0 {
+ Some(images_to_reap.collect())
+ } else {
+ None
+ }
+ }
+ pub fn character_cell_size_possibly_changed(&mut self) {
+ if let (Some(previous_cell_size), Some(character_cell_size)) =
+ (self.previous_cell_size, *self.character_cell_size.borrow())
+ {
+ if previous_cell_size != character_cell_size {
+ for (_image_id, pixel_rect) in self.sixel_image_locations.iter_mut() {
+ pixel_rect.x =
+ (pixel_rect.x / previous_cell_size.width) * character_cell_size.width;
+ pixel_rect.y = (pixel_rect.y / previous_cell_size.height as isize)
+ * character_cell_size.height as isize;
+ }
+ }
+ }
+ self.previous_cell_size = *self.character_cell_size.borrow();
+ }
+ pub fn clear(&mut self) -> Option<Vec<usize>> {
+ // returns image ids to reap
+ let mut image_ids: Vec<usize> = self
+ .sixel_image_locations
+ .drain()
+ .map(|(image_id, _image_rect)| image_id)
+ .collect();
+ image_ids.append(&mut self.image_ids_to_reap);
+ if !image_ids.is_empty() {
+ Some(image_ids)
+ } else {
+ None
+ }
+ }
+ pub fn next_image_id(&self) -> usize {
+ self.sixel_image_store.borrow().sixel_images.keys().len()
+ }
+ pub fn new_sixel_image(&mut self, sixel_image_id: usize, sixel_image: SixelImage) {
+ self.sixel_image_store
+ .borrow_mut()
+ .sixel_images
+ .insert(sixel_image_id, (sixel_image, HashMap::new()));
+ }
+ pub fn remove_pixels_from_image(&mut self, image_id: usize, pixel_rect: PixelRect) {
+ if let Some((sixel_image, sixel_image_cache)) = self
+ .sixel_image_store
+ .borrow_mut()
+ .sixel_images
+ .get_mut(&image_id)
+ {
+ sixel_image.cut_out(
+ pixel_rect.x,
+ pixel_rect.y as usize,
+ pixel_rect.width,
+ pixel_rect.height,
+ );
+ sixel_image_cache.clear(); // TODO: more intelligent cache clearing
+ }
+ }
+ pub fn reap_images(&mut self, ids_to_reap: Vec<usize>) {
+ for id in ids_to_reap {
+ drop(self.sixel_image_store.borrow_mut().sixel_images.remove(&id));
+ }
+ }
+ pub fn image_cell_coordinates_in_viewport(
+ &self,
+ viewport_height: usize,
+ scrollback_height: usize,
+ ) -> Vec<(usize, usize, usize, usize)> {
+ match *self.character_cell_size.borrow() {
+ Some(character_cell_size) => self
+ .sixel_image_locations
+ .iter()
+ .map(|(_image_id, pixel_rect)| {
+ let scrollback_size_in_pixels = scrollback_height * character_cell_size.height;
+ let y_pixel_coordinates_in_viewport =
+ pixel_rect.y - scrollback_size_in_pixels as isize;
+ let image_y = std::cmp::max(y_pixel_coordinates_in_viewport, 0) as usize
+ / character_cell_size.height;
+ let image_x = pixel_rect.x / character_cell_size.width;
+ let image_height_in_pixels = if y_pixel_coordinates_in_viewport < 0 {
+ pixel_rect.height as isize + y_pixel_coordinates_in_viewport
+ } else {
+ pixel_rect.height as isize
+ };
+ let image_height = image_height_in_pixels as usize / character_cell_size.height;
+ let image_width = pixel_rect.width / character_cell_size.width;
+ let height_remainder =
+ if image_height_in_pixels as usize % character_cell_size.height > 0 {
+ 1
+ } else {
+ 0
+ };
+ let width_remainder = if pixel_rect.width % character_cell_size.width > 0 {
+ 1
+ } else {
+ 0
+ };
+ let image_top_edge = image_y;
+ let image_bottom_edge =
+ std::cmp::min(image_y + image_height + height_remainder, viewport_height);
+ let image_left_edge = image_x;
+ let image_right_edge = image_x + image_width + width_remainder;
+ (
+ image_top_edge,
+ image_bottom_edge,
+ image_left_edge,
+ image_right_edge,
+ )
+ })
+ .collect(),
+ None => vec![],
+ }
+ }
+ pub fn changed_sixel_chunks_in_viewport(
+ &self,
+ changed_rects: HashMap<usize, usize>,
+ scrollback_size_in_lines: usize,
+ viewport_width_in_cells: usize,
+ viewport_x_offset: usize,
+ viewport_y_offset: usize,
+ ) -> Vec<SixelImageChunk> {
+ let mut changed_sixel_image_chunks = vec![];
+ if let Some(character_cell_size) = { *self.character_cell_size.borrow() } {
+ for (sixel_image_id, sixel_image_pixel_rect) in self.image_coordinates() {
+ for (line_index, line_count) in &changed_rects {
+ let changed_rect_pixel_height = line_count * character_cell_size.height;
+ let changed_rect_top_edge = ((line_index + scrollback_size_in_lines)
+ * character_cell_size.height)
+ as isize;
+ let changed_rect_bottom_edge =
+ changed_rect_top_edge + changed_rect_pixel_height as isize;
+ let sixel_image_top_edge = sixel_image_pixel_rect.y;
+ let sixel_image_bottom_edge =
+ sixel_image_pixel_rect.y + sixel_image_pixel_rect.height as isize;
+
+ let cell_x_in_current_pane =
+ sixel_image_pixel_rect.x / character_cell_size.width;
+ let cell_x = viewport_x_offset + cell_x_in_current_pane;
+ let sixel_image_pixel_width = if sixel_image_pixel_rect.x
+ + sixel_image_pixel_rect.width
+ <= (viewport_width_in_cells * character_cell_size.width)
+ {
+ sixel_image_pixel_rect.width
+ } else {
+ (viewport_width_in_cells * character_cell_size.width)
+ .saturating_sub(sixel_image_pixel_rect.x)
+ };
+ if sixel_image_pixel_width == 0 {
+ continue;
+ }
+
+ let sixel_image_cell_distance_from_scrollback_top =
+ sixel_image_top_edge as usize / character_cell_size.height;
+ // if the image is above the rect top, this will be 0
+ let sixel_image_cell_distance_from_changed_rect_top =
+ sixel_image_cell_distance_from_scrollback_top
+ .saturating_sub(line_index + scrollback_size_in_lines);
+ let cell_y = viewport_y_offset
+ + line_index
+ + sixel_image_cell_distance_from_changed_rect_top;
+ let sixel_image_pixel_x = 0;
+ // if the image is above the rect top, this will be 0
+ let sixel_image_pixel_y = (changed_rect_top_edge as usize)
+ .saturating_sub(sixel_image_top_edge as usize)
+ as usize;
+ let sixel_image_pixel_height = std::cmp::min(
+ (std::cmp::min(changed_rect_bottom_edge, sixel_image_bottom_edge)
+ - std::cmp::max(changed_rect_top_edge, sixel_image_top_edge))
+ as usize,
+ sixel_image_pixel_rect.height,
+ );
+
+ if (sixel_image_top_edge >= changed_rect_top_edge
+ && sixel_image_top_edge <= changed_rect_bottom_edge)
+ || (sixel_image_bottom_edge >= changed_rect_top_edge
+ && sixel_image_bottom_edge <= changed_rect_bottom_edge)
+ || (sixel_image_bottom_edge >= changed_rect_bottom_edge
+ && sixel_image_top_edge <= changed_rect_top_edge)
+ {
+ changed_sixel_image_chunks.push(SixelImageChunk {
+ cell_x,
+ cell_y,
+ sixel_image_pixel_x,
+ sixel_image_pixel_y,
+ sixel_image_pixel_width,
+ sixel_image_pixel_height,
+ sixel_image_id,
+ });
+ }
+ }
+ }
+ }
+ changed_sixel_image_chunks
+ }
+}
+
+type SixelImageCache = HashMap<PixelRect, String>;
+#[derive(Debug, Clone, Default)]
+pub struct SixelImageStore {
+ sixel_images: HashMap<usize, (SixelImage, SixelImageCache)>,
+}
+
+impl SixelImageStore {
+ pub fn serialize_image(
+ &mut self,
+ image_id: usize,
+ pixel_x: usize,
+ pixel_y: usize,
+ pixel_width: usize,
+ pixel_height: usize,
+ ) -> Option<String> {
+ self.sixel_images
+ .get_mut(&image_id)
+ .map(|(sixel_image, sixel_image_cache)| {
+ if let Some(cached_image) = sixel_image_cache.get(&PixelRect::new(
+ pixel_x,
+ pixel_y,
+ pixel_height,
+ pixel_width,
+ )) {
+ cached_image.clone()
+ } else {
+ let serialized_image =
+ sixel_image.serialize_range(pixel_x, pixel_y, pixel_width, pixel_height);
+ sixel_image_cache.insert(
+ PixelRect::new(pixel_x, pixel_y, pixel_height, pixel_width),
+ serialized_image.clone(),
+ );
+ serialized_image
+ }
+ })
+ }
+ pub fn image_count(&self) -> usize {
+ self.sixel_images.len()
+ }
+}
diff --git a/zellij-server/src/panes/terminal_pane.rs b/zellij-server/src/panes/terminal_pane.rs
index 64af5859..b6640037 100644
--- a/zellij-server/src/panes/terminal_pane.rs
+++ b/zellij-server/src/panes/terminal_pane.rs
@@ -1,4 +1,5 @@
-use crate::output::CharacterChunk;
+use crate::output::{CharacterChunk, SixelImageChunk};
+use crate::panes::sixel::SixelImageStore;
use crate::panes::{
grid::Grid,
terminal_character::{CursorShape, TerminalCharacter, EMPTY_TERMINAL_CHARACTER},
@@ -99,10 +100,10 @@ impl Pane for TerminalPane {
self.reflow_lines();
}
fn handle_pty_bytes(&mut self, bytes: VteBytes) {
+ self.set_should_render(true);
for &byte in &bytes {
self.vte_parser.advance(&mut self.grid, byte);
}
- self.set_should_render(true);
}
fn cursor_coordinates(&self) -> Option<(usize, usize)> {
// (x, y)
@@ -205,13 +206,14 @@ impl Pane for TerminalPane {
fn render(
&mut self,
_client_id: Option<ClientId>,
- ) -> Option<(Vec<CharacterChunk>, Option<String>)> {
+ ) -> Option<(Vec<CharacterChunk>, Option<String>, Vec<SixelImageChunk>)> {
if self.should_render() {
let mut raw_vte_output = String::new();
let content_x = self.get_content_x();
let content_y = self.get_content_y();
- let mut character_chunks = self.grid.read_changes(content_x, content_y);
+ let (mut character_chunks, sixel_image_chunks) =
+ self.grid.read_changes(content_x, content_y);
for character_chunk in character_chunks.iter_mut() {
character_chunk.add_changed_colors(self.grid.changed_colors);
if self
@@ -237,7 +239,7 @@ impl Pane for TerminalPane {
self.grid.ring_bell = false;
}
self.set_should_render(false);
- Some((character_chunks, Some(raw_vte_output)))
+ Some((character_chunks, Some(raw_vte_output), sixel_image_chunks))
} else {
None
}
@@ -509,15 +511,19 @@ impl TerminalPane {
pane_name: String,
link_handler: Rc<RefCell<LinkHandler>>,
character_cell_size: Rc<RefCell<Option<SizeInPixels>>>,
+ sixel_image_store: Rc<RefCell<SixelImageStore>>,
terminal_emulator_colors: Rc<RefCell<Palette>>,
+ terminal_emulator_color_codes: Rc<RefCell<HashMap<usize, String>>>,
) -> TerminalPane {
let initial_pane_title = format!("Pane #{}", pane_index);
let grid = Grid::new(
position_and_size.rows.as_usize(),
position_and_size.cols.as_usize(),
terminal_emulator_colors,
+ terminal_emulator_color_codes,
link_handler,
character_cell_size,
+ sixel_image_store,
);
TerminalPane {
frame: HashMap::new(),
diff --git a/zellij-server/src/panes/unit/grid_tests.rs b/zellij-server/src/panes/unit/grid_tests.rs
index 057c1466..42e7ff36 100644
--- a/zellij-server/src/panes/unit/grid_tests.rs
+++ b/zellij-server/src/panes/unit/grid_tests.rs
@@ -1,10 +1,14 @@
use super::super::Grid;
+use crate::panes::grid::SixelImageStore;
use crate::panes::link_handler::LinkHandler;
use ::insta::assert_snapshot;
use std::cell::RefCell;
+use std::collections::HashMap;
use std::rc::Rc;
use zellij_utils::{data::Palette, pane_size::SizeInPixels, position::Position, vte};
+use std::fmt::Write;
+
fn read_fixture(fixture_name: &str) -> Vec<u8> {
let mut path_to_file = std::path::PathBuf::new();
path_to_file.push("../src");
@@ -18,12 +22,16 @@ fn read_fixture(fixture_name: &str) -> Vec<u8> {
#[test]
fn vttest1_0() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
41,
110,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "vttest1-0";
let content = read_fixture(fixture_name);
@@ -36,12 +44,16 @@ fn vttest1_0() {
#[test]
fn vttest1_1() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
41,
110,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "vttest1-1";
let content = read_fixture(fixture_name);
@@ -54,12 +66,16 @@ fn vttest1_1() {
#[test]
fn vttest1_2() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
41,
110,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "vttest1-2";
let content = read_fixture(fixture_name);
@@ -72,12 +88,16 @@ fn vttest1_2() {
#[test]
fn vttest1_3() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
41,
110,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "vttest1-3";
let content = read_fixture(fixture_name);
@@ -90,12 +110,16 @@ fn vttest1_3() {
#[test]
fn vttest1_4() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
41,
110,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "vttest1-4";
let content = read_fixture(fixture_name);
@@ -108,12 +132,16 @@ fn vttest1_4() {
#[test]
fn vttest1_5() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
41,
110,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "vttest1-5";
let content = read_fixture(fixture_name);
@@ -126,12 +154,16 @@ fn vttest1_5() {
#[test]
fn vttest2_0() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
41,
110,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "vttest2-0";
let content = read_fixture(fixture_name);
@@ -144,12 +176,16 @@ fn vttest2_0() {
#[test]
fn vttest2_1() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
41,
110,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "vttest2-1";
let content = read_fixture(fixture_name);
@@ -162,12 +198,16 @@ fn vttest2_1() {
#[test]
fn vttest2_2() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
41,
110,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "vttest2-2";
let content = read_fixture(fixture_name);
@@ -180,12 +220,16 @@ fn vttest2_2() {
#[test]
fn vttest2_3() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
41,
110,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "vttest2-3";
let content = read_fixture(fixture_name);
@@ -198,12 +242,16 @@ fn vttest2_3() {
#[test]
fn vttest2_4() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
41,
110,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "vttest2-4";
let content = read_fixture(fixture_name);
@@ -216,12 +264,16 @@ fn vttest2_4() {
#[test]
fn vttest2_5() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
41,
110,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "vttest2-5";
let content = read_fixture(fixture_name);
@@ -234,12 +286,16 @@ fn vttest2_5() {
#[test]
fn vttest2_6() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
41,
110,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "vttest2-6";
let content = read_fixture(fixture_name);
@@ -252,12 +308,16 @@ fn vttest2_6() {
#[test]
fn vttest2_7() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
41,
110,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "vttest2-7";
let content = read_fixture(fixture_name);
@@ -270,12 +330,16 @@ fn vttest2_7() {
#[test]
fn vttest2_8() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
41,
110,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "vttest2-8";
let content = read_fixture(fixture_name);
@@ -288,12 +352,16 @@ fn vttest2_8() {
#[test]
fn vttest2_9() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
41,
110,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "vttest2-9";
let content = read_fixture(fixture_name);
@@ -306,12 +374,16 @@ fn vttest2_9() {
#[test]
fn vttest2_10() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
41,
110,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "vttest2-10";
let content = read_fixture(fixture_name);
@@ -324,12 +396,16 @@ fn vttest2_10() {
#[test]
fn vttest2_11() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
41,
110,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "vttest2-11";
let content = read_fixture(fixture_name);
@@ -342,12 +418,16 @@ fn vttest2_11() {
#[test]
fn vttest2_12() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
41,
110,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "vttest2-12";
let content = read_fixture(fixture_name);
@@ -360,12 +440,16 @@ fn vttest2_12() {
#[test]
fn vttest2_13() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
41,
110,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "vttest2-13";
let content = read_fixture(fixture_name);
@@ -378,12 +462,16 @@ fn vttest2_13() {
#[test]
fn vttest2_14() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
41,
110,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "vttest2-14";
let content = read_fixture(fixture_name);
@@ -396,12 +484,16 @@ fn vttest2_14() {
#[test]
fn vttest3_0() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
41,
110,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "vttest3-0";
let content = read_fixture(fixture_name);
@@ -414,12 +506,16 @@ fn vttest3_0() {
#[test]
fn vttest8_0() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
51,
97,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "vttest8-0";
let content = read_fixture(fixture_name);
@@ -432,12 +528,16 @@ fn vttest8_0() {
#[test]
fn vttest8_1() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
51,
97,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "vttest8-1";
let content = read_fixture(fixture_name);
@@ -450,12 +550,16 @@ fn vttest8_1() {
#[test]
fn vttest8_2() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
51,
97,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "vttest8-2";
let content = read_fixture(fixture_name);
@@ -468,12 +572,16 @@ fn vttest8_2() {
#[test]
fn vttest8_3() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
51,
97,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "vttest8-3";
let content = read_fixture(fixture_name);
@@ -486,12 +594,16 @@ fn vttest8_3() {
#[test]
fn vttest8_4() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
51,
97,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "vttest8-4";
let content = read_fixture(fixture_name);
@@ -504,12 +616,16 @@ fn vttest8_4() {
#[test]
fn vttest8_5() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
51,
97,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "vttest8-5";
let content = read_fixture(fixture_name);
@@ -522,12 +638,16 @@ fn vttest8_5() {
#[test]
fn csi_b() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
51,
97,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "csi-b";
let content = read_fixture(fixture_name);
@@ -540,12 +660,16 @@ fn csi_b() {
#[test]
fn csi_capital_i() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
51,
97,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "csi-capital-i";
let content = read_fixture(fixture_name);
@@ -558,12 +682,16 @@ fn csi_capital_i() {
#[test]
fn csi_capital_z() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
51,
97,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "csi-capital-z";
let content = read_fixture(fixture_name);
@@ -576,12 +704,16 @@ fn csi_capital_z() {
#[test]
fn terminal_reports() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
51,
97,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "terminal_reports";
let content = read_fixture(fixture_name);
@@ -594,12 +726,16 @@ fn terminal_reports() {
#[test]
fn wide_characters() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
21,
104,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "wide_characters";
let content = read_fixture(fixture_name);
@@ -612,12 +748,16 @@ fn wide_characters() {
#[test]
fn wide_characters_line_wrap() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
21,
104,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "wide_characters_line_wrap";
let content = read_fixture(fixture_name);
@@ -630,12 +770,16 @@ fn wide_characters_line_wrap() {
#[test]
fn insert_character_in_line_with_wide_character() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
21,
104,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "wide_characters_middle_line_insert";
let content = read_fixture(fixture_name);
@@ -648,12 +792,16 @@ fn insert_character_in_line_with_wide_character() {
#[test]
fn delete_char_in_middle_of_line_with_widechar() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
21,
104,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "wide-chars-delete-middle";
let content = read_fixture(fixture_name);
@@ -666,12 +814,16 @@ fn delete_char_in_middle_of_line_with_widechar() {
#[test]
fn delete_char_in_middle_of_line_with_multiple_widechars() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
21,
104,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "wide-chars-delete-middle-after-multi";
let content = read_fixture(fixture_name);
@@ -684,12 +836,16 @@ fn delete_char_in_middle_of_line_with_multiple_widechars() {
#[test]
fn fish_wide_characters_override_clock() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
21,
104,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "fish_wide_characters_override_clock";
let content = read_fixture(fixture_name);
@@ -702,12 +858,16 @@ fn fish_wide_characters_override_clock() {
#[test]
fn bash_delete_wide_characters() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
21,
104,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "bash_delete_wide_characters";
let content = read_fixture(fixture_name);
@@ -720,12 +880,16 @@ fn bash_delete_wide_characters() {
#[test]
fn delete_wide_characters_before_cursor() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
21,
104,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "delete_wide_characters_before_cursor";
let content = read_fixture(fixture_name);
@@ -738,12 +902,16 @@ fn delete_wide_characters_before_cursor() {
#[test]
fn delete_wide_characters_before_cursor_when_cursor_is_on_wide_character() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
21,
104,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "delete_wide_characters_before_cursor_when_cursor_is_on_wide_character";
let content = read_fixture(fixture_name);
@@ -756,12 +924,16 @@ fn delete_wide_characters_before_cursor_when_cursor_is_on_wide_character() {
#[test]
fn delete_wide_character_under_cursor() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
21,
104,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "delete_wide_character_under_cursor";
let content = read_fixture(fixture_name);
@@ -774,12 +946,16 @@ fn delete_wide_character_under_cursor() {
#[test]
fn replace_wide_character_under_cursor() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
21,
104,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "replace_wide_character_under_cursor";
let content = read_fixture(fixture_name);
@@ -792,12 +968,16 @@ fn replace_wide_character_under_cursor() {
#[test]
fn wrap_wide_characters() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
21,
90,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "wide_characters_full";
let content = read_fixture(fixture_name);
@@ -810,12 +990,16 @@ fn wrap_wide_characters() {
#[test]
fn wrap_wide_characters_on_size_change() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
21,
93,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "wide_characters_full";
let content = read_fixture(fixture_name);
@@ -829,12 +1013,16 @@ fn wrap_wide_characters_on_size_change() {
#[test]
fn unwrap_wide_characters_on_size_change() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
21,
93,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "wide_characters_full";
let content = read_fixture(fixture_name);
@@ -849,12 +1037,16 @@ fn unwrap_wide_characters_on_size_change() {
#[test]
fn wrap_wide_characters_in_the_middle_of_the_line() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
21,
91,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "wide_characters_line_middle";
let content = read_fixture(fixture_name);
@@ -867,12 +1059,16 @@ fn wrap_wide_characters_in_the_middle_of_the_line() {
#[test]
fn wrap_wide_characters_at_the_end_of_the_line() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
21,
90,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "wide_characters_line_end";
let content = read_fixture(fixture_name);
@@ -885,12 +1081,16 @@ fn wrap_wide_characters_at_the_end_of_the_line() {
#[test]
fn copy_selected_text_from_viewport() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
27,
125,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "grid_copy";
let content = read_fixture(fixture_name);
@@ -911,12 +1111,16 @@ fn copy_selected_text_from_viewport() {
#[test]
fn copy_wrapped_selected_text_from_viewport() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
22,
73,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "grid_copy_wrapped";
let content = read_fixture(fixture_name);
@@ -936,12 +1140,16 @@ fn copy_wrapped_selected_text_from_viewport() {
#[test]
fn copy_selected_text_from_lines_above() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
27,
125,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "grid_copy";
let content = read_fixture(fixture_name);
@@ -962,12 +1170,16 @@ fn copy_selected_text_from_lines_above() {
#[test]
fn copy_selected_text_from_lines_below() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
27,
125,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "grid_copy";
let content = read_fixture(fixture_name);
@@ -996,12 +1208,16 @@ fn copy_selected_text_from_lines_below() {
#[test]
fn run_bandwhich_from_fish_shell() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
28,
116,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "fish_and_bandwhich";
let content = read_fixture(fixture_name);
@@ -1014,12 +1230,16 @@ fn run_bandwhich_from_fish_shell() {
#[test]
fn fish_tab_completion_options() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
28,
116,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "fish_tab_completion_options";
let content = read_fixture(fixture_name);
@@ -1036,13 +1256,18 @@ pub fn fish_select_tab_completion_options() {
// changes.
// this is not clearly seen in the snapshot because it does not include styles,
// but we can see the command line change and the cursor staying in place
+ // terminal_emulator_color_codes,
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
28,
116,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "fish_select_tab_completion_options";
let content = read_fixture(fixture_name);
@@ -1059,16 +1284,22 @@ pub fn vim_scroll_region_down() {
// the region is defined here by vim as 1-26 (there are 28 rows)
// then the cursor is moved to line 26 and a new line is added
// what should happen is that the first line in the scroll region (1) is deleted
+ // terminal_emulator_color_codes,
// and an empty line is inserted in the last scroll region line (26)
// this tests also has other steps afterwards that fills the line with the next line in the
+ // sixel_image_store,
// file
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
28,
116,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "vim_scroll_region_down";
let content = read_fixture(fixture_name);
@@ -1085,14 +1316,19 @@ pub fn vim_ctrl_d() {
// this case) lines inside the scroll region and push the other lines up
// what happens here is that 13 lines are deleted and instead 13 empty lines are added at the
// end of the scroll region
+ // terminal_emulator_color_codes,
// vim makes sure to fill these empty lines with the rest of the file
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
28,
116,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "vim_ctrl_d";
let content = read_fixture(fixture_name);
@@ -1109,13 +1345,18 @@ pub fn vim_ctrl_u() {
// this case) lines at the cursor, pushing away (deleting) the last line in the scroll region
// this causes the effect of scrolling up X lines (vim replaces the lines with the ones in the
// file above the current content)
+ // terminal_emulator_color_codes,
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
28,
116,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "vim_ctrl_u";
let content = read_fixture(fixture_name);
@@ -1128,12 +1369,16 @@ pub fn vim_ctrl_u() {
#[test]
pub fn htop() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
28,
116,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "htop";
let content = read_fixture(fixture_name);
@@ -1146,12 +1391,16 @@ pub fn htop() {
#[test]
pub fn htop_scrolling() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
28,
116,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "htop_scrolling";
let content = read_fixture(fixture_name);
@@ -1164,12 +1413,16 @@ pub fn htop_scrolling() {
#[test]
pub fn htop_right_scrolling() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
28,
116,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "htop_right_scrolling";
let content = read_fixture(fixture_name);
@@ -1186,16 +1439,22 @@ pub fn vim_overwrite() {
// * open a file in vim
// * open the same file in another window
// * change the file in the other window and save
+ // terminal_emulator_color_codes,
// * change the file in the original vim window and save
// * confirm you would like to change the file by pressing 'y' and then ENTER
+ // sixel_image_store,
// * if everything looks fine, this test passed :)
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
28,
116,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "vim_overwrite";
let content = read_fixture(fixture_name);
@@ -1210,12 +1469,16 @@ pub fn clear_scroll_region() {
// this is actually a test of 1049h/l (alternative buffer)
// @imsnif - the name is a monument to the time I didn't fully understand this mechanism :)
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
28,
116,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "clear_scroll_region";
let content = read_fixture(fixture_name);
@@ -1228,12 +1491,16 @@ pub fn clear_scroll_region() {
#[test]
pub fn display_tab_characters_properly() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
28,
116,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "tab_characters";
let content = read_fixture(fixture_name);
@@ -1246,12 +1513,16 @@ pub fn display_tab_characters_properly() {
#[test]
pub fn neovim_insert_mode() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
28,
116,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "nvim_insert";
let content = read_fixture(fixture_name);
@@ -1264,12 +1535,16 @@ pub fn neovim_insert_mode() {
#[test]
pub fn bash_cursor_linewrap() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
28,
116,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "bash_cursor_linewrap";
let content = read_fixture(fixture_name);
@@ -1284,12 +1559,16 @@ pub fn fish_paste_multiline() {
// here we paste a multiline command in fish shell, making sure we support it
// going up and changing the colors of our line-wrapped pasted text
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
28,
149,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "fish_paste_multiline";
let content = read_fixture(fixture_name);
@@ -1302,12 +1581,16 @@ pub fn fish_paste_multiline() {
#[test]
pub fn git_log() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
28,
149,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "git_log";
let content = read_fixture(fixture_name);
@@ -1322,12 +1605,16 @@ pub fn git_diff_scrollup() {
// this tests makes sure that when we have a git diff that exceeds the screen size
// we are able to scroll up
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
28,
149,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "git_diff_scrollup";
let content = read_fixture(fixture_name);
@@ -1340,12 +1627,16 @@ pub fn git_diff_scrollup() {
#[test]
pub fn emacs_longbuf() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
60,
284,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "emacs_longbuf_tutorial";
let content = read_fixture(fixture_name);
@@ -1358,12 +1649,16 @@ pub fn emacs_longbuf() {
#[test]
pub fn top_and_quit() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
56,
235,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "top_and_quit";
let content = read_fixture(fixture_name);
@@ -1380,14 +1675,19 @@ pub fn exa_plus_omf_theme() {
// this is a potential bug because the \t character is a goto
// if we forwarded it as is to the terminal, we would be skipping
// over existing on-screen content without deleting it, so we must
+ // terminal_emulator_color_codes,
// convert it to spaces
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
56,
235,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "exa_plus_omf_theme";
let content = read_fixture(fixture_name);
@@ -1400,12 +1700,16 @@ pub fn exa_plus_omf_theme() {
#[test]
pub fn scroll_up() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
10,
50,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "scrolling";
let content = read_fixture(fixture_name);
@@ -1419,12 +1723,16 @@ pub fn scroll_up() {
#[test]
pub fn scroll_down() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
10,
50,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "scrolling";
let content = read_fixture(fixture_name);
@@ -1439,12 +1747,16 @@ pub fn scroll_down() {
#[test]
pub fn scroll_up_with_line_wraps() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
10,
25,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "scrolling";
let content = read_fixture(fixture_name);
@@ -1458,12 +1770,16 @@ pub fn scroll_up_with_line_wraps() {
#[test]
pub fn scroll_down_with_line_wraps() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
10,
25,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "scrolling";
let content = read_fixture(fixture_name);
@@ -1478,12 +1794,16 @@ pub fn scroll_down_with_line_wraps() {
#[test]
pub fn scroll_up_decrease_width_and_scroll_down() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
10,
50,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "scrolling";
let content = read_fixture(fixture_name);
@@ -1503,12 +1823,16 @@ pub fn scroll_up_decrease_width_and_scroll_down() {
#[test]
pub fn scroll_up_increase_width_and_scroll_down() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
10,
25,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "scrolling";
let content = read_fixture(fixture_name);
@@ -1528,12 +1852,16 @@ pub fn scroll_up_increase_width_and_scroll_down() {
#[test]
pub fn move_cursor_below_scroll_region() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
34,
114,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "move_cursor_below_scroll_region";
let content = read_fixture(fixture_name);
@@ -1546,12 +1874,16 @@ pub fn move_cursor_below_scroll_region() {
#[test]
pub fn insert_wide_characters_in_existing_line() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
21,
86,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "chinese_characters_line_middle";
let content = read_fixture(fixture_name);
@@ -1568,13 +1900,18 @@ pub fn full_screen_scroll_region_and_scroll_up() {
// full viewport and then scrolling up would cause
// lines to get deleted from the viewport rather
// than moving to "lines_above"
+ // terminal_emulator_color_codes,
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
54,
80,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "scroll_region_full_screen";
let content = read_fixture(fixture_name);
@@ -1590,12 +1927,16 @@ pub fn full_screen_scroll_region_and_scroll_up() {
#[test]
pub fn ring_bell() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
134,
64,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "ring_bell";
let content = read_fixture(fixture_name);
@@ -1608,12 +1949,16 @@ pub fn ring_bell() {
#[test]
pub fn alternate_screen_change_size() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
20,
20,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "alternate_screen_change_size";
let content = read_fixture(fixture_name);
@@ -1630,12 +1975,16 @@ pub fn alternate_screen_change_size() {
#[test]
pub fn fzf_fullscreen() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
51,
112,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "fzf_fullscreen";
let content = read_fixture(fixture_name);
@@ -1652,12 +2001,16 @@ pub fn replace_multiple_wide_characters_under_cursor() {
// character if the cursor was "in the middle" of the wide character, or after the character if
// it was "in the beginning" of the wide character)
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
51,
112,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "replace_multiple_wide_characters";
let content = read_fixture(fixture_name);
@@ -1674,12 +2027,16 @@ pub fn replace_non_wide_characters_with_wide_characters() {
// character if the cursor was "in the middle" of the wide character, or after the character if
// it was "in the beginning" of the wide character)
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
51,
112,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "replace_non_wide_characters_with_wide_characters";
let content = read_fixture(fixture_name);
@@ -1692,12 +2049,16 @@ pub fn replace_non_wide_characters_with_wide_characters() {
#[test]
pub fn scroll_down_ansi() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
51,
112,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let fixture_name = "scroll_down";
let content = read_fixture(fixture_name);
@@ -1710,12 +2071,16 @@ pub fn scroll_down_ansi() {
#[test]
pub fn ansi_capital_t() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
51,
112,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let content = "foo\u{1b}[14Tbar".as_bytes();
for byte in content {
@@ -1727,12 +2092,16 @@ pub fn ansi_capital_t() {
#[test]
pub fn ansi_capital_s() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
51,
112,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let content = "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nfoo\u{1b}[14Sbar".as_bytes();
for byte in content {
@@ -1744,15 +2113,19 @@ pub fn ansi_capital_s() {
#[test]
fn terminal_pixel_size_reports() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
51,
97,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(Some(SizeInPixels {
height: 21,
width: 8,
}))),
+ sixel_image_store,
);
let fixture_name = "terminal_pixel_size_reports";
let content = read_fixture(fixture_name);
@@ -1771,12 +2144,16 @@ fn terminal_pixel_size_reports() {
#[test]
fn terminal_pixel_size_reports_in_unsupported_terminals() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
51,
97,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)), // in an unsupported terminal, we don't have this info
+ sixel_image_store,
);
let fixture_name = "terminal_pixel_size_reports";
let content = read_fixture(fixture_name);
@@ -1796,12 +2173,16 @@ fn terminal_pixel_size_reports_in_unsupported_terminals() {
#[test]
pub fn ansi_csi_at_sign() {
let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
51,
112,
Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let content = "foo\u{1b}[2D\u{1b}[2@".as_bytes();
for byte in content {
@@ -1809,3 +2190,326 @@ pub fn ansi_csi_at_sign() {
}
assert_snapshot!(format!("{:?}", grid));
}
+
+#[test]
+pub fn sixel_images_are_reaped_when_scrolled_off() {
+ let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
+ let character_cell_size = Rc::new(RefCell::new(Some(SizeInPixels {
+ width: 8,
+ height: 21,
+ })));
+ let mut grid = Grid::new(
+ 51,
+ 112,
+ Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
+ Rc::new(RefCell::new(LinkHandler::new())),
+ character_cell_size,
+ sixel_image_store.clone(),
+ );
+ let pane_content = read_fixture("sixel-image-500px.six");
+ for byte in pane_content {
+ vte_parser.advance(&mut grid, byte);
+ }
+ for _ in 0..10_051 {
+ // scrollbuffer limit + viewport height
+ grid.add_canonical_line();
+ }
+ let _ = grid.read_changes(0, 0); // we do this because this is where the images are reaped
+ assert_eq!(
+ sixel_image_store.borrow().image_count(),
+ 0,
+ "all images were deleted from the store"
+ );
+}
+
+#[test]
+pub fn sixel_images_are_reaped_when_resetting() {
+ let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
+ let character_cell_size = Rc::new(RefCell::new(Some(SizeInPixels {
+ width: 8,
+ height: 21,
+ })));
+ let mut grid = Grid::new(
+ 51,
+ 112,
+ Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
+ Rc::new(RefCell::new(LinkHandler::new())),
+ character_cell_size,
+ sixel_image_store.clone(),
+ );
+ let pane_content = read_fixture("sixel-image-500px.six");
+ for byte in pane_content {
+ vte_parser.advance(&mut grid, byte);
+ }
+ grid.reset_terminal_state();
+ let _ = grid.read_changes(0, 0); // we do this because this is where the images are reaped
+ assert_eq!(
+ sixel_image_store.borrow().image_count(),
+ 0,
+ "all images were deleted from the store"
+ );
+}
+
+#[test]
+pub fn sixel_image_in_alternate_buffer() {
+ let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
+ let character_cell_size = Rc::new(RefCell::new(Some(SizeInPixels {
+ width: 8,
+ height: 21,
+ })));
+ let mut grid = Grid::new(
+ 30,
+ 112,
+ Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
+ Rc::new(RefCell::new(LinkHandler::new())),
+ character_cell_size,
+ sixel_image_store.clone(),
+ );
+
+ let move_to_alternate_screen = "\u{1b}[?1049h";
+ for byte in move_to_alternate_screen.as_bytes() {
+ vte_parser.advance(&mut grid, *byte);
+ }
+
+ let pane_content = read_fixture("sixel-image-500px.six");
+ for byte in pane_content {
+ vte_parser.advance(&mut grid, byte);
+ }
+ assert_snapshot!(format!("{:?}", grid)); // should include the image
+ //
+ let move_away_from_alternate_screen = "\u{1b}[?1049l";
+ for byte in move_away_from_alternate_screen.as_bytes() {
+ vte_parser.advance(&mut grid, *byte);
+ }
+ assert_snapshot!(format!("{:?}", grid)); // should note include the image
+ assert_eq!(
+ sixel_image_store.borrow().image_count(),
+ 0,
+ "all images were deleted from the store when we moved back from alternate screen"
+ );
+}
+
+#[test]
+pub fn sixel_with_image_scrolling_decsdm() {
+ let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
+ let character_cell_size = Rc::new(RefCell::new(Some(SizeInPixels {
+ width: 8,
+ height: 21,
+ })));
+ let mut grid = Grid::new(
+ 30,
+ 112,
+ Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
+ Rc::new(RefCell::new(LinkHandler::new())),
+ character_cell_size,
+ sixel_image_store,
+ );
+
+ // enter DECSDM
+ let move_to_decsdm = "\u{1b}[?80h";
+ for byte in move_to_decsdm.as_bytes() {
+ vte_parser.advance(&mut grid, *byte);
+ }
+
+ // write some text
+ let mut text_to_fill_pane = String::new();
+ for i in 0..10 {
+ writeln!(&mut text_to_fill_pane, "\rline {}", i + 1).unwrap();
+ }
+ for byte in text_to_fill_pane.as_bytes() {
+ vte_parser.advance(&mut grid, *byte);
+ }
+
+ // render a sixel image (will appear on the top left and partially cover the text)
+ let pane_content = read_fixture("sixel-image-100px.six");
+ for byte in pane_content {
+ vte_parser.advance(&mut grid, byte);
+ }
+ // image should be on the top left corner of the grid
+ assert_snapshot!(format!("{:?}", grid));
+
+ // leave DECSDM
+ let move_away_from_decsdm = "\u{1b}[?80l";
+ for byte in move_away_from_decsdm.as_bytes() {
+ vte_parser.advance(&mut grid, *byte);
+ }
+
+ // Go down to the beginning of the next line
+ let mut go_down_once = String::new();
+ writeln!(&mut go_down_once, "\n\r").unwrap();
+ for byte in go_down_once.as_bytes() {
+ vte_parser.advance(&mut grid, *byte);
+ }
+
+ // render another sixel image, should appear under the cursor
+ let pane_content = read_fixture("sixel-image-100px.six");
+ for byte in pane_content {
+ vte_parser.advance(&mut grid, byte);
+ }
+
+ // image should appear in cursor position
+ assert_snapshot!(format!("{:?}", grid));
+}
+
+#[test]
+pub fn osc_4_background_query() {
+ let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
+ let mut grid = Grid::new(
+ 51,
+ 97,
+ Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
+ Rc::new(RefCell::new(LinkHandler::new())),
+ Rc::new(RefCell::new(None)),
+ sixel_image_store,
+ );
+ let content = "\u{1b}]10;?\u{1b}\\";
+ for byte in content.as_bytes() {
+ vte_parser.advance(&mut grid, *byte);
+ }
+ let message_string = grid
+ .pending_messages_to_pty
+ .iter()
+ .map(|m| String::from_utf8_lossy(m))
+ .fold(String::new(), |mut acc, s| {
+ acc.push_str(&s);
+ acc
+ });
+ assert_eq!(message_string, "\u{1b}]10;rgb:0000/0000/0000\u{1b}\\");
+}
+
+#[test]
+pub fn osc_4_foreground_query() {
+ let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
+ let mut grid = Grid::new(
+ 51,
+ 97,
+ Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
+ Rc::new(RefCell::new(LinkHandler::new())),
+ Rc::new(RefCell::new(None)),
+ sixel_image_store,
+ );
+ let content = "\u{1b}]11;?\u{1b}\\";
+ for byte in content.as_bytes() {
+ vte_parser.advance(&mut grid, *byte);
+ }
+ let message_string = grid
+ .pending_messages_to_pty
+ .iter()
+ .map(|m| String::from_utf8_lossy(m))
+ .fold(String::new(), |mut acc, s| {
+ acc.push_str(&s);
+ acc
+ });
+ assert_eq!(message_string, "\u{1b}]11;rgb:0000/0000/0000\u{1b}\\");
+}
+
+#[test]
+pub fn osc_4_color_query() {
+ let mut color_codes = HashMap::new();
+ color_codes.insert(222, String::from("rgb:ffff/d7d7/8787"));
+ let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(color_codes));
+ let mut grid = Grid::new(
+ 51,
+ 97,
+ Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
+ Rc::new(RefCell::new(LinkHandler::new())),
+ Rc::new(RefCell::new(None)),
+ sixel_image_store,
+ );
+ let content = "\u{1b}]4;222;?\u{1b}\\";
+ for byte in content.as_bytes() {
+ vte_parser.advance(&mut grid, *byte);
+ }
+ let message_string = grid
+ .pending_messages_to_pty
+ .iter()
+ .map(|m| String::from_utf8_lossy(m))
+ .fold(String::new(), |mut acc, s| {
+ acc.push_str(&s);
+ acc
+ });
+ assert_eq!(message_string, "\u{1b}]4;222;rgb:ffff/d7d7/8787\u{1b}\\");
+}
+
+#[test]
+pub fn xtsmgraphics_color_register_count() {
+ let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
+ let mut grid = Grid::new(
+ 51,
+ 97,
+ Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
+ Rc::new(RefCell::new(LinkHandler::new())),
+ Rc::new(RefCell::new(None)),
+ sixel_image_store,
+ );
+ let content = "\u{1b}[?1;1;S\u{1b}\\";
+ for byte in content.as_bytes() {
+ vte_parser.advance(&mut grid, *byte);
+ }
+ let message_string = grid
+ .pending_messages_to_pty
+ .iter()
+ .map(|m| String::from_utf8_lossy(m))
+ .fold(String::new(), |mut acc, s| {
+ acc.push_str(&s);
+ acc
+ });
+ assert_eq!(message_string, "\u{1b}[?1;0;65536S");
+}
+
+#[test]
+pub fn xtsmgraphics_pixel_graphics_geometry() {
+ let mut vte_parser = vte::Parser::new();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
+ let character_cell_size = Rc::new(RefCell::new(Some(SizeInPixels {
+ width: 8,
+ height: 21,
+ })));
+ let mut grid = Grid::new(
+ 51,
+ 97,
+ Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes,
+ Rc::new(RefCell::new(LinkHandler::new())),
+ character_cell_size,
+ sixel_image_store,
+ );
+ let content = "\u{1b}[?2;1;S\u{1b}\\";
+ for byte in content.as_bytes() {
+ vte_parser.advance(&mut grid, *byte);
+ }
+ let message_string = grid
+ .pending_messages_to_pty
+ .iter()
+ .map(|m| String::from_utf8_lossy(m))
+ .fold(String::new(), |mut acc, s| {
+ acc.push_str(&s);
+ acc
+ });
+ assert_eq!(message_string, "\u{1b}[?2;0;776;1071S");
+}
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__ansi_csi_at_sign.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__ansi_csi_at_sign.snap
index 12ec5d49..0802a322 100644
--- a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__ansi_csi_at_sign.snap
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__ansi_csi_at_sign.snap
@@ -1,7 +1,57 @@
---
source: zellij-server/src/panes/./unit/grid_tests.rs
-assertion_line: 1810
+assertion_line: 2189
expression: "format!(\"{:?}\", grid)"
---
00 (C): f oo
+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):
+21 (C):
+22 (C):
+23 (C):
+24 (C):
+25 (C):
+26 (C):
+27 (C):
+28 (C):
+29 (C):
+30 (C):
+31 (C):
+32 (C):
+33 (C):
+34 (C):
+35 (C):
+36 (C):
+37 (C):
+38 (C):
+39 (C):
+40 (C):
+41 (C):
+42 (C):
+43 (C):
+44 (C):
+45 (C):
+46 (C):
+47 (C):
+48 (C):
+49 (C):
+50 (C):
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__bash_cursor_linewrap.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__bash_cursor_linewrap.snap
index 93634316..cb3c0a0b 100644
--- a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__bash_cursor_linewrap.snap
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__bash_cursor_linewrap.snap
@@ -1,10 +1,34 @@
---
source: zellij-server/src/panes/./unit/grid_tests.rs
+assertion_line: 1552
expression: "format!(\"{:?}\", grid)"
-
---
00 (C): Welcome to fish, the friendly interactive shell
01 (C): ⋊> ~/c/mosaic on main ⨯ bash 16:00:06
02 (C): [aram@green mosaic]$ 12345678912345678912345678912345678912345678912345678912345678912345678912345678912345678912345
03 (W):
+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):
+21 (C):
+22 (C):
+23 (C):
+24 (C):
+25 (C):
+26 (C):
+27 (C):
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__bash_delete_wide_characters.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__bash_delete_wide_characters.snap
index acb5a608..92e3c637 100644
--- a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__bash_delete_wide_characters.snap
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__bash_delete_wide_characters.snap
@@ -1,9 +1,27 @@
---
source: zellij-server/src/panes/./unit/grid_tests.rs
+assertion_line: 875
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]$ HHHHHH
+02 (C): [aram@green zellij]$ HHHHHH
+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):
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__clear_scroll_region.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__clear_scroll_region.snap
index e5c302a0..b86ed31c 100644
--- a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__clear_scroll_region.snap
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__clear_scroll_region.snap
@@ -1,9 +1,34 @@
---
source: zellij-server/src/panes/./unit/grid_tests.rs
+assertion_line: 1486
expression: "format!(\"{:?}\", grid)"
-
---
00 (C): Welcome to fish, the friendly interactive shell
01 (C): ⋊> ~/c/mosaic on main ⨯ vim some-file 15:07:22
02 (C): ⋊> ~/c/mosaic on main ⨯ 15:07:29
+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):
+21 (C):
+22 (C):
+23 (C):
+24 (C):
+25 (C):
+26 (C):
+27 (C):
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__csi_b.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__csi_b.snap
index 2be051c5..767f2f1a 100644
--- a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__csi_b.snap
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__csi_b.snap
@@ -1,8 +1,57 @@
---
source: zellij-server/src/panes/./unit/grid_tests.rs
+assertion_line: 655
expression: "format!(\"{:?}\", grid)"
-
---
00 (C): ffffff
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):
+21 (C):
+22 (C):
+23 (C):
+24 (C):
+25 (C):
+26 (C):
+27 (C):
+28 (C):
+29 (C):
+30 (C):
+31 (C):
+32 (C):
+33 (C):
+34 (C):
+35 (C):
+36 (C):
+37 (C):
+38 (C):
+39 (C):
+40 (C):
+41 (C):
+42 (C):
+43 (C):
+44 (C):
+45 (C):
+46 (C):
+47 (C):
+48 (C):
+49 (C):
+50 (C):
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__csi_capital_i.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__csi_capital_i.snap
index 44026d04..4ec1d8e4 100644
--- a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__csi_capital_i.snap
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__csi_capital_i.snap
@@ -1,8 +1,57 @@
---
source: zellij-server/src/panes/./unit/grid_tests.rs
+assertion_line: 677
expression: "format!(\"{:?}\", grid)"
-
---
00 (C): foo
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):
+21 (C):
+22 (C):
+23 (C):
+24 (C):
+25 (C):
+26 (C):
+27 (C):
+28 (C):
+29 (C):
+30 (C):
+31 (C):
+32 (C):
+33 (C):
+34 (C):
+35 (C):
+36 (C):
+37 (C):
+38 (C):
+39 (C):
+40 (C):
+41 (C):
+42 (C):
+43 (C):
+44 (C):
+45 (C):
+46 (C):
+47 (C):
+48 (C):
+49 (C):
+50 (C):
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__csi_capital_z.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__csi_capital_z.snap
index 2411b25f..9d8dc01b 100644
--- a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__csi_capital_z.snap
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__csi_capital_z.snap
@@ -1,8 +1,57 @@
---
source: zellij-server/src/panes/./unit/grid_tests.rs
+assertion_line: 699
expression: "format!(\"{:?}\", grid)"
-
---
00 (C): 12345678foo234567890
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):
+21 (C):
+22 (C):
+23 (C):
+24 (C):
+25 (C):
+26 (C):
+27 (C):
+28 (C):
+29 (C):
+30 (C):
+31 (C):
+32 (C):
+33 (C):
+34 (C):
+35 (C):
+36 (C):
+37 (C):
+38 (C):
+39 (C):
+40 (C):
+41 (C):
+42 (C):
+43 (C):
+44 (C):
+45 (C):
+46 (C):
+47 (C):
+48 (C):
+49 (C):
+50 (C):
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__delete_char_in_middle_of_line_with_multiple_widechars.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__delete_char_in_middle_of_line_with_multiple_widechars.snap
index 75c8a772..240d5fd5 100644
--- a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__delete_char_in_middle_of_line_with_multiple_widechars.snap
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__delete_char_in_middle_of_line_with_multiple_widechars.snap
@@ -1,7 +1,27 @@
---
source: zellij-server/src/panes/./unit/grid_tests.rs
+assertion_line: 831
expression: "format!(\"{:?}\", grid)"
-
---
00 (C): [aram@green zellij]$ 🏠🏠🏠
+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):
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__delete_char_in_middle_of_line_with_widechar.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__delete_char_in_middle_of_line_with_widechar.snap
index 6a442b69..d90531b4 100644
--- a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__delete_char_in_middle_of_line_with_widechar.snap
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__delete_char_in_middle_of_line_with_widechar.snap
@@ -1,7 +1,27 @@
---
source: zellij-server/src/panes/./unit/grid_tests.rs
+assertion_line: 809
expression: "format!(\"{:?}\", grid)"
-
---
00 (C): [aram@green zellij]$ 🏠 def abc
+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):
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__delete_wide_character_under_cursor.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__delete_wide_character_under_cursor.snap
index e6d26254..5606cd37 100644
--- a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__delete_wide_character_under_cursor.snap
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__delete_wide_character_under_cursor.snap
@@ -1,8 +1,27 @@
---
source: zellij-server/src/panes/./unit/grid_tests.rs
+assertion_line: 941
expression: "format!(\"{:?}\", grid)"
-
---
00 (C): 12 4
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):
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__delete_wide_characters_before_cursor.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__delete_wide_characters_before_cursor.snap
index 401650ad..82387285 100644
--- a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__delete_wide_characters_before_cursor.snap
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__delete_wide_characters_before_cursor.snap
@@ -1,7 +1,27 @@
---
source: zellij-server/src/panes/./unit/grid_tests.rs
+assertion_line: 897
expression: "format!(\"{:?}\", grid)"
-
---
00 (C): Hi
+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):
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__delete_wide_characters_before_cursor_when_cursor_is_on_wide_character.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__delete_wide_characters_before_cursor_when_cursor_is_on_wide_character.snap
index ae1d8a65..fc22e7d2 100644
--- a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__delete_wide_characters_before_cursor_when_cursor_is_on_wide_character.snap
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__delete_wide_characters_before_cursor_when_cursor_is_on_wide_character.snap
@@ -1,7 +1,27 @@
---
source: zellij-server/src/panes/./unit/grid_tests.rs
+assertion_line: 919
expression: "format!(\"{:?}\", grid)"
-
---
00 (C): i
+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):
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__display_tab_characters_properly.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__display_tab_characters_properly.snap
index 48c75d6c..1858ccdc 100644
--- a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__display_tab_characters_properly.snap
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__display_tab_characters_properly.snap
@@ -1,7 +1,7 @@
---
source: zellij-server/src/panes/./unit/grid_tests.rs
+assertion_line: 1508
expression: "format!(\"{:?}\", grid)"
-
---
00 (C):
01 (C): OS: 5.9.13-arch1-1 GNU/Linux
@@ -18,4 +18,17 @@ expression: "format!(\"{:?}\", grid)"
12 (C): wlp2s0 192.168.0.3
13 (C):
14 (C): [I] [20:07] kingdom:mosaic (main) |
+15 (C):
+16 (C):
+17 (C):
+18 (C):
+19 (C):
+20 (C):
+21 (C):
+22 (C):
+23 (C):
+24 (C):
+25 (C):
+26 (C):
+27 (C):
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__emacs_longbuf.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__emacs_longbuf.snap
index 71cc9bc8..1168075d 100644
--- a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__emacs_longbuf.snap
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__emacs_longbuf.snap
@@ -1,10 +1,66 @@
---
source: zellij-server/src/panes/./unit/grid_tests.rs
+assertion_line: 1644
expression: "format!(\"{:?}\", grid)"
-
---
00 (C): ➜ mosaic git:(mosaic#130) emacs
01 (C): ➜ mosaic git:(mosaic#130) emacs -nw
02 (C): ➜ mosaic git:(mosaic#130) exit
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):
+21 (C):
+22 (C):
+23 (C):
+24 (C):
+25 (C):
+26 (C):
+27 (C):
+28 (C):
+29 (C):
+30 (C):
+31 (C):
+32 (C):
+33 (C):
+34 (C):
+35 (C):
+36 (C):
+37 (C):
+38 (C):
+39 (C):
+40 (C):
+41 (C):
+42 (C):
+43 (C):
+44 (C):
+45 (C):
+46 (C):
+47 (C):
+48 (C):
+49 (C):
+50 (C):
+51 (C):
+52 (C):
+53 (C):
+54 (C):
+55 (C):
+56 (C):
+57 (C):
+58 (C):
+59 (C):
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__fish_paste_multiline.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__fish_paste_multiline.snap
index faf24017..00949aa2 100644
--- a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__fish_paste_multiline.snap
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__fish_paste_multiline.snap
@@ -1,7 +1,7 @@
---
source: zellij-server/src/panes/./unit/grid_tests.rs
+assertion_line: 1576
expression: "format!(\"{:?}\", grid)"
-
---
00 (C):
01 (C): OS: 5.9.14-arch1-1 GNU/Linux
@@ -24,4 +24,11 @@ expression: "format!(\"{:?}\", grid)"
18 (W): )$/\\\\e[0;33m\1\\\\e[0m/' | \
19 (C): paste -sd ''\
20 (C): )
+21 (C):
+22 (C):
+23 (C):
+24 (C):
+25 (C):
+26 (C):
+27 (C):
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__fish_select_tab_completion_options.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__fish_select_tab_completion_options.snap
index 88addebb..0b6540c6 100644
--- a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__fish_select_tab_completion_options.snap
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__fish_select_tab_completion_options.snap
@@ -1,11 +1,34 @@
---
source: zellij-server/src/panes/./unit/grid_tests.rs
+assertion_line: 1275
expression: "format!(\"{:?}\", grid)"
-
---
00 (C): Welcome to fish, the friendly interactive shell
01 (C): ⋊> ~/c/mosaic on main ⨯ sudo badblocks 11:32:23
02 (C): badblocks (Executable, 33kB) base64 (Executable, 42kB) bash (Executable, 906kB)
03 (C): bandwhich (Executable, 3.0MB) basename (Executable, 38kB) bashbug (Executable, 6.8kB)
04 (C): base32 (Executable, 42kB) basenc (Executable, 50kB) bass
+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):
+21 (C):
+22 (C):
+23 (C):
+24 (C):
+25 (C):
+26 (C):
+27 (C):
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__fish_tab_completion_options.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__fish_tab_completion_options.snap
index a093e708..65a3339a 100644
--- a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__fish_tab_completion_options.snap
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__fish_tab_completion_options.snap
@@ -1,11 +1,34 @@
---
source: zellij-server/src/panes/./unit/grid_tests.rs
+assertion_line: 1247
expression: "format!(\"{:?}\", grid)"
-
---
00 (C): Welcome to fish, the friendly interactive shell
01 (C): ⋊> ~/c/mosaic on main ⨯ sudo bandwhich 11:18:26
02 (C): badblocks (Executable, 33kB) base64 (Executable, 42kB) bash (Executable, 906kB)
03 (C): bandwhich (Executable, 3.0MB) basename (Executable, 38kB) bashbug (Executable, 6.8kB)
04 (C): base32 (Executable, 42kB) basenc (Executable, 50kB) bass
+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):
+21 (C):
+22 (C):
+23 (C):
+24 (C):
+25 (C):
+26 (C):
+27 (C):
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__fish_wide_characters_override_clock.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__fish_wide_characters_override_clock.snap
index a328b18c..4285d8d4 100644
--- a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__fish_wide_characters_override_clock.snap
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__fish_wide_characters_override_clock.snap
@@ -1,8 +1,27 @@
---
source: zellij-server/src/panes/./unit/grid_tests.rs
+assertion_line: 853
expression: "format!(\"{:?}\", grid)"
-
---
00 (C): Welcome to fish, the friendly interactive shell
-01 (C): ⋊> ~/c/zellij on main ⨯ HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
+01 (C): ⋊> ~/c/zellij on main ⨯ HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
+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):
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__insert_character_in_line_with_wide_character.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__insert_character_in_line_with_wide_character.snap
index e278348c..c8eb2a73 100644
--- a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__insert_character_in_line_with_wide_character.snap
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__insert_character_in_line_with_wide_character.snap
@@ -1,7 +1,27 @@
---
source: zellij-server/src/panes/./unit/grid_tests.rs
+assertion_line: 787
expression: "format!(\"{:?}\", grid)"
-
---
00 (C): [aram@green zellij]$ 🏠 xdef abc
+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):
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__replace_multiple_wide_characters_under_cursor.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__replace_multiple_wide_characters_under_cursor.snap
index ca1a76d4..0915c83a 100644
--- a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__replace_multiple_wide_characters_under_cursor.snap
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__replace_multiple_wide_characters_under_cursor.snap
@@ -1,8 +1,57 @@
---
source: zellij-server/src/panes/./unit/grid_tests.rs
+assertion_line: 2018
expression: "format!(\"{:?}\", grid)"
-
---
00 (C): 👨y x🔭
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):
+21 (C):
+22 (C):
+23 (C):
+24 (C):
+25 (C):
+26 (C):
+27 (C):
+28 (C):
+29 (C):
+30 (C):
+31 (C):
+32 (C):
+33 (C):
+34 (C):
+35 (C):
+36 (C):
+37 (C):
+38 (C):
+39 (C):
+40 (C):
+41 (C):
+42 (C):
+43 (C):
+44 (C):
+45 (C):
+46 (C):
+47 (C):
+48 (C):
+49 (C):
+50 (C):
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__replace_non_wide_characters_with_wide_characters.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__replace_non_wide_characters_with_wide_characters.snap
index 60ea74c8..3d542820 100644
--- a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__replace_non_wide_characters_with_wide_characters.snap
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__replace_non_wide_characters_with_wide_characters.snap
@@ -1,8 +1,57 @@
---
source: zellij-server/src/panes/./unit/grid_tests.rs
+assertion_line: 2044
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):
+21 (C):
+22 (C):
+23 (C):
+24 (C):
+25 (C):
+26 (C):
+27 (C):
+28 (C):
+29 (C):
+30 (C):
+31 (C):
+32 (C):
+33 (C):
+34 (C):
+35 (C):
+36 (C):
+37 (C):
+38 (C):
+39 (C):
+40 (C):
+41 (C):
+42 (C):
+43 (C):
+44 (C):
+45 (C):
+46 (C):
+47 (C):
+48 (C):
+49 (C):
+50 (C):
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__replace_wide_character_under_cursor.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__replace_wide_character_under_cursor.snap
index 3b664aaf..32826dc0 100644
--- a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__replace_wide_character_under_cursor.snap
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__replace_wide_character_under_cursor.snap
@@ -1,8 +1,27 @@
---
source: zellij-server/src/panes/./unit/grid_tests.rs
+assertion_line: 963
expression: "format!(\"{:?}\", grid)"
-
---
00 (C): 12 4
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):
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__sixel_image_in_alternate_buffer-2.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__sixel_image_in_alternate_buffer-2.snap
new file mode 100644
index 00000000..e4ba2640
--- /dev/null
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__sixel_image_in_alternate_buffer-2.snap
@@ -0,0 +1,36 @@
+---
+source: zellij-server/src/panes/./unit/grid_tests.rs
+assertion_line: 2273
+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):
+21 (C):
+22 (C):
+23 (C):
+24 (C):
+25 (C):
+26 (C):
+27 (C):
+28 (C):
+29 (C):
+
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__sixel_image_in_alternate_buffer.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__sixel_image_in_alternate_buffer.snap
new file mode 100644
index 00000000..a1473016
--- /dev/null
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__sixel_image_in_alternate_buffer.snap
@@ -0,0 +1,36 @@
+---
+source: zellij-server/src/panes/./unit/grid_tests.rs
+assertion_line: 2267
+expression: "format!(\"{:?}\", grid)"
+---
+00 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+01 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+02 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+03 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+04 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+05 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+06 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+07 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+08 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+09 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+10 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+11 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+12 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+13 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+14 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+15 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+16 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+17 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+18 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+19 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+20 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+21 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+22 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+23 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+24 (C):
+25 (C):
+26 (C):
+27 (C):
+28 (C):
+29 (C):
+
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__sixel_with_image_scrolling_decsdm-2.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__sixel_with_image_scrolling_decsdm-2.snap
new file mode 100644
index 00000000..9fdef65f
--- /dev/null
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__sixel_with_image_scrolling_decsdm-2.snap
@@ -0,0 +1,36 @@
+---
+source: zellij-server/src/panes/./unit/grid_tests.rs
+assertion_line: 2338
+expression: "format!(\"{:?}\", grid)"
+---
+00 (C): SixelSixelSix
+01 (C): SixelSixelSix
+02 (C): SixelSixelSix
+03 (C): SixelSixelSix
+04 (C): SixelSixelSix
+05 (C): line 6
+06 (C): line 7
+07 (C): line 8
+08 (C): line 9
+09 (C): line 10
+10 (C):
+11 (C):
+12 (C): SixelSixelSix
+13 (C): SixelSixelSix
+14 (C): SixelSixelSix
+15 (C): SixelSixelSix
+16 (C): SixelSixelSix
+17 (C):
+18 (C):
+19 (C):
+20 (C):
+21 (C):
+22 (C):
+23 (C):
+24 (C):
+25 (C):
+26 (C):
+27 (C):
+28 (C):
+29 (C):
+
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__sixel_with_image_scrolling_decsdm.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__sixel_with_image_scrolling_decsdm.snap
new file mode 100644
index 00000000..2676595a
--- /dev/null
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__sixel_with_image_scrolling_decsdm.snap
@@ -0,0 +1,36 @@
+---
+source: zellij-server/src/panes/./unit/grid_tests.rs
+assertion_line: 2316
+expression: "format!(\"{:?}\", grid)"
+---
+00 (C): SixelSixelSix
+01 (C): SixelSixelSix
+02 (C): SixelSixelSix
+03 (C): SixelSixelSix
+04 (C): SixelSixelSix
+05 (C): line 6
+06 (C): line 7
+07 (C): line 8
+08 (C): line 9
+09 (C): line 10
+10 (C):
+11 (C):
+12 (C):
+13 (C):
+14 (C):
+15 (C):
+16 (C):
+17 (C):
+18 (C):
+19 (C):
+20 (C):
+21 (C):
+22 (C):
+23 (C):
+24 (C):
+25 (C):
+26 (C):
+27 (C):
+28 (C):
+29 (C):
+
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__terminal_reports.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__terminal_reports.snap
index d289d93f..aef38672 100644
--- a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__terminal_reports.snap
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__terminal_reports.snap
@@ -1,6 +1,6 @@
---
source: zellij-server/src/panes/./unit/grid_tests.rs
-expression: "format!(\"{:?}\", grid . pending_messages_to_pty)"
-
+assertion_line: 721
+expression: "format!(\"{:?}\", grid.pending_messages_to_pty)"
---
-[[27, 91, 63, 54, 99], [27, 91, 56, 59, 53, 49, 59, 57, 55, 116], [27, 91, 63, 54, 99], [27, 91, 48, 110], [27, 91, 49, 59, 49, 82]]
+[[27, 91, 63, 54, 52, 59, 52, 99], [27, 91, 56, 59, 53, 49, 59, 57, 55, 116], [27, 91, 63, 54, 99], [27, 91, 48, 110], [27, 91, 49, 59, 49, 82]]
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__wide_characters.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__wide_characters.snap
index cd549fb3..0fb7477d 100644
--- a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__wide_characters.snap
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__wide_characters.snap
@@ -1,8 +1,27 @@
---
source: zellij-server/src/panes/./unit/grid_tests.rs
+assertion_line: 743
expression: "format!(\"{:?}\", grid)"
-
---
00 (C): Welcome to fish, the friendly interactive shell
01 (C): ⋊> ~/c/zellij on main ⨯ HHHHHHH 15:19:10
+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):
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__wide_characters_line_wrap.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__wide_characters_line_wrap.snap
index e9f0e2db..d7b019fd 100644
--- a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__wide_characters_line_wrap.snap
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__wide_characters_line_wrap.snap
@@ -1,10 +1,27 @@
---
source: zellij-server/src/panes/./unit/grid_tests.rs
+assertion_line: 765
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]$ HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
03 (W): HHHHH
+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):
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__terminal_pane__grid_tests__changing_character_cell_size_with_sixel_images.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__terminal_pane__grid_tests__changing_character_cell_size_with_sixel_images.snap
new file mode 100644
index 00000000..f7b23baf
--- /dev/null
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__terminal_pane__grid_tests__changing_character_cell_size_with_sixel_images.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/panes/./unit/terminal_pane_tests.rs
+assertion_line: 323
+expression: "format!(\"{:?}\", terminal_pane.grid)"
+---
+00 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+01 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+02 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+03 (C): line 5
+04 (C):
+05 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+06 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+07 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+08 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+09 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+10 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+11 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+12 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+13 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+14 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+15 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+16 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+17 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+18 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+19 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__terminal_pane__grid_tests__keep_working_after_corrupted_sixel_image.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__terminal_pane__grid_tests__keep_working_after_corrupted_sixel_image.snap
new file mode 100644
index 00000000..260a1048
--- /dev/null
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__terminal_pane__grid_tests__keep_working_after_corrupted_sixel_image.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/panes/./unit/terminal_pane_tests.rs
+assertion_line: 364
+expression: "format!(\"{:?}\", terminal_pane.grid)"
+---
+00 (C): line 1
+01 (C): line 2
+02 (C): line 3
+03 (C): line 4
+04 (C): line 5
+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):
+
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__terminal_pane__grid_tests__multiple_sixel_images_in_pane.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__terminal_pane__grid_tests__multiple_sixel_images_in_pane.snap
new file mode 100644
index 00000000..7625a75b
--- /dev/null
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__terminal_pane__grid_tests__multiple_sixel_images_in_pane.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/panes/./unit/terminal_pane_tests.rs
+assertion_line: 235
+expression: "format!(\"{:?}\", terminal_pane.grid)"
+---
+00 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+01 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+02 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+03 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+04 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+05 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+06 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+07 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+08 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+09 (C): line 1
+10 (C): line 2
+11 (C): line 3
+12 (C): line 4
+13 (C): line 5
+14 (C):
+15 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+16 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+17 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+18 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+19 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__terminal_pane__grid_tests__overflowing_sixel_image_inside_terminal_pane.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__terminal_pane__grid_tests__overflowing_sixel_image_inside_terminal_pane.snap
new file mode 100644
index 00000000..714e84c7
--- /dev/null
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__terminal_pane__grid_tests__overflowing_sixel_image_inside_terminal_pane.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/panes/./unit/terminal_pane_tests.rs
+assertion_line: 156
+expression: "format!(\"{:?}\", terminal_pane.grid)"
+---
+00 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+01 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+02 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+03 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+04 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+05 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+06 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+07 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+08 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+09 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+10 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+11 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+12 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+13 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+14 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+15 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+16 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+17 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+18 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+19 (C):
+
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__terminal_pane__grid_tests__partial_sixel_image_inside_terminal_pane.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__terminal_pane__grid_tests__partial_sixel_image_inside_terminal_pane.snap
new file mode 100644
index 00000000..c2fdefdf
--- /dev/null
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__terminal_pane__grid_tests__partial_sixel_image_inside_terminal_pane.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/panes/./unit/terminal_pane_tests.rs
+assertion_line: 123
+expression: "format!(\"{:?}\", terminal_pane.grid)"
+---
+00 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+01 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+02 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+03 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+04 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+05 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+06 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+07 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+08 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+09 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+10 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+11 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+12 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+13 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+14 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+15 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+16 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+17 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+18 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+19 (C):
+
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__terminal_pane__grid_tests__resizing_pane_with_sixel_images.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__terminal_pane__grid_tests__resizing_pane_with_sixel_images.snap
new file mode 100644
index 00000000..b013f3ed
--- /dev/null
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__terminal_pane__grid_tests__resizing_pane_with_sixel_images.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/panes/./unit/terminal_pane_tests.rs
+assertion_line: 277
+expression: "format!(\"{:?}\", terminal_pane.grid)"
+---
+00 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+01 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+02 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+03 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+04 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+05 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+06 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+07 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+08 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+09 (C): line 1
+10 (C): line 2
+11 (C): line 3
+12 (C): line 4
+13 (C): line 5
+14 (C):
+15 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+16 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+17 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+18 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+19 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__terminal_pane__grid_tests__scrolling_through_a_sixel_image-2.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__terminal_pane__grid_tests__scrolling_through_a_sixel_image-2.snap
new file mode 100644
index 00000000..1d251353
--- /dev/null
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__terminal_pane__grid_tests__scrolling_through_a_sixel_image-2.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/panes/./unit/terminal_pane_tests.rs
+assertion_line: 195
+expression: "format!(\"{:?}\", terminal_pane.grid)"
+---
+00 (C): line 30
+01 (C):
+02 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+03 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+04 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+05 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+06 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+07 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+08 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+09 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+10 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+11 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+12 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+13 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+14 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+15 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+16 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+17 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+18 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+19 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__terminal_pane__grid_tests__scrolling_through_a_sixel_image-3.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__terminal_pane__grid_tests__scrolling_through_a_sixel_image-3.snap
new file mode 100644
index 00000000..ac5fbc57
--- /dev/null
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__terminal_pane__grid_tests__scrolling_through_a_sixel_image-3.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/panes/./unit/terminal_pane_tests.rs
+assertion_line: 197
+expression: "format!(\"{:?}\", terminal_pane.grid)"
+---
+00 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+01 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+02 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+03 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+04 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+05 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+06 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+07 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+08 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+09 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+10 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+11 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+12 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+13 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+14 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+15 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+16 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+17 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+18 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+19 (C):
+
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__terminal_pane__grid_tests__scrolling_through_a_sixel_image.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__terminal_pane__grid_tests__scrolling_through_a_sixel_image.snap
new file mode 100644
index 00000000..1eaf7066
--- /dev/null
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__terminal_pane__grid_tests__scrolling_through_a_sixel_image.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/panes/./unit/terminal_pane_tests.rs
+assertion_line: 193
+expression: "format!(\"{:?}\", terminal_pane.grid)"
+---
+00 (C): line 27
+01 (C): line 28
+02 (C): line 29
+03 (C): line 30
+04 (C):
+05 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+06 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+07 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+08 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+09 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+10 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+11 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+12 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+13 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+14 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+15 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+16 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+17 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+18 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+19 (C): SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix
+
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__terminal_pane__grid_tests__sixel_image_inside_terminal_pane.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__terminal_pane__grid_tests__sixel_image_inside_terminal_pane.snap
new file mode 100644
index 00000000..339ec9f0
--- /dev/null
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__terminal_pane__grid_tests__sixel_image_inside_terminal_pane.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/panes/./unit/terminal_pane_tests.rs
+assertion_line: 85
+expression: "format!(\"{:?}\", terminal_pane.grid)"
+---
+00 (C): Si
+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):
+
diff --git a/zellij-server/src/panes/unit/terminal_pane_tests.rs b/zellij-server/src/panes/unit/terminal_pane_tests.rs
index 62c2436e..2e29ca34 100644
--- a/zellij-server/src/panes/unit/terminal_pane_tests.rs
+++ b/zellij-server/src/panes/unit/terminal_pane_tests.rs
@@ -1,16 +1,28 @@
use super::super::TerminalPane;
+use crate::panes::sixel::SixelImageStore;
use crate::panes::LinkHandler;
use crate::tab::Pane;
use ::insta::assert_snapshot;
use std::cell::RefCell;
+use std::collections::HashMap;
use std::rc::Rc;
use zellij_utils::{
data::{Palette, Style},
- pane_size::PaneGeom,
+ pane_size::{PaneGeom, SizeInPixels},
};
use std::fmt::Write;
+fn read_fixture(fixture_name: &str) -> Vec<u8> {
+ let mut path_to_file = std::path::PathBuf::new();
+ path_to_file.push("../src");
+ path_to_file.push("tests");
+ path_to_file.push("fixtures");
+ path_to_file.push(fixture_name);
+ std::fs::read(path_to_file)
+ .unwrap_or_else(|_| panic!("could not read fixture {:?}", &fixture_name))
+}
+
#[test]
pub fn scrolling_inside_a_pane() {
let fake_client_id = 1;
@@ -20,6 +32,9 @@ pub fn scrolling_inside_a_pane() {
let pid = 1;
let style = Style::default();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_colors = Rc::new(RefCell::new(Palette::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut terminal_pane = TerminalPane::new(
pid,
fake_win_size,
@@ -28,7 +43,9 @@ pub fn scrolling_inside_a_pane() {
String::new(),
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
- Rc::new(RefCell::new(Palette::default())),
+ sixel_image_store,
+ terminal_emulator_colors,
+ terminal_emulator_color_codes,
); // 0 is the pane index
let mut text_to_fill_pane = String::new();
for i in 0..30 {
@@ -42,3 +59,335 @@ pub fn scrolling_inside_a_pane() {
terminal_pane.clear_scroll();
assert_snapshot!(format!("{:?}", terminal_pane.grid));
}
+
+#[test]
+pub fn sixel_image_inside_terminal_pane() {
+ let mut fake_win_size = PaneGeom::default();
+ fake_win_size.cols.set_inner(121);
+ fake_win_size.rows.set_inner(20);
+
+ let pid = 1;
+ let style = Style::default();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_colors = Rc::new(RefCell::new(Palette::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
+ let character_cell_size = Rc::new(RefCell::new(Some(SizeInPixels {
+ width: 8,
+ height: 21,
+ })));
+ let mut terminal_pane = TerminalPane::new(
+ pid,
+ fake_win_size,
+ style,
+ 0,
+ String::new(),
+ Rc::new(RefCell::new(LinkHandler::new())),
+ character_cell_size,
+ sixel_image_store,
+ terminal_emulator_colors,
+ terminal_emulator_color_codes,
+ ); // 0 is the pane index
+ let sixel_image_bytes = "\u{1b}Pq
+ #0;2;0;0;0#1;2;100;100;0#2;2;0;100;0
+ #1~~@@vv@@~~@@~~$
+ #2??}}GG}}??}}??-
+ #1!14@
+ \u{1b}\\";
+
+ terminal_pane.handle_pty_bytes(Vec::from(sixel_image_bytes.as_bytes()));
+ assert_snapshot!(format!("{:?}", terminal_pane.grid));
+}
+
+#[test]
+pub fn partial_sixel_image_inside_terminal_pane() {
+ // here we test to make sure we partially render an image that is partially hidden in the
+ // scrollbuffer
+ let mut fake_win_size = PaneGeom::default();
+ fake_win_size.cols.set_inner(121);
+ fake_win_size.rows.set_inner(20);
+
+ let pid = 1;
+ let style = Style::default();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_colors = Rc::new(RefCell::new(Palette::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
+ let character_cell_size = Rc::new(RefCell::new(Some(SizeInPixels {
+ width: 8,
+ height: 21,
+ })));
+ let mut terminal_pane = TerminalPane::new(
+ pid,
+ fake_win_size,
+ style,
+ 0,
+ String::new(),
+ Rc::new(RefCell::new(LinkHandler::new())),
+ character_cell_size,
+ sixel_image_store,
+ terminal_emulator_colors,
+ terminal_emulator_color_codes,
+ ); // 0 is the pane index
+ let pane_content = read_fixture("sixel-image-500px.six");
+ terminal_pane.handle_pty_bytes(pane_content);
+ assert_snapshot!(format!("{:?}", terminal_pane.grid));
+}
+
+#[test]
+pub fn overflowing_sixel_image_inside_terminal_pane() {
+ // here we test to make sure we properly render an image that overflows both in the width and
+ // height of the pane
+ let mut fake_win_size = PaneGeom::default();
+ fake_win_size.cols.set_inner(50);
+ fake_win_size.rows.set_inner(20);
+
+ let pid = 1;
+ let style = Style::default();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_colors = Rc::new(RefCell::new(Palette::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
+ let character_cell_size = Rc::new(RefCell::new(Some(SizeInPixels {
+ width: 8,
+ height: 21,
+ })));
+ let mut terminal_pane = TerminalPane::new(
+ pid,
+ fake_win_size,
+ style,
+ 0,
+ String::new(),
+ Rc::new(RefCell::new(LinkHandler::new())),
+ character_cell_size,
+ sixel_image_store,
+ terminal_emulator_colors,
+ terminal_emulator_color_codes,
+ ); // 0 is the pane index
+ let pane_content = read_fixture("sixel-image-500px.six");
+ terminal_pane.handle_pty_bytes(pane_content);
+ assert_snapshot!(format!("{:?}", terminal_pane.grid));
+}
+
+#[test]
+pub fn scrolling_through_a_sixel_image() {
+ let fake_client_id = 1;
+ let mut fake_win_size = PaneGeom::default();
+ fake_win_size.cols.set_inner(121);
+ fake_win_size.rows.set_inner(20);
+
+ let pid = 1;
+ let style = Style::default();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_colors = Rc::new(RefCell::new(Palette::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
+ let character_cell_size = Rc::new(RefCell::new(Some(SizeInPixels {
+ width: 8,
+ height: 21,
+ })));
+ let mut terminal_pane = TerminalPane::new(
+ pid,
+ fake_win_size,
+ style,
+ 0,
+ String::new(),
+ Rc::new(RefCell::new(LinkHandler::new())),
+ character_cell_size,
+ sixel_image_store,
+ terminal_emulator_colors,
+ terminal_emulator_color_codes,
+ ); // 0 is the pane index
+ let mut text_to_fill_pane = String::new();
+ for i in 0..30 {
+ writeln!(&mut text_to_fill_pane, "\rline {}", i + 1).unwrap();
+ }
+ writeln!(&mut text_to_fill_pane, "\r").unwrap();
+ let pane_sixel_content = read_fixture("sixel-image-500px.six");
+ terminal_pane.handle_pty_bytes(text_to_fill_pane.into_bytes());
+ terminal_pane.handle_pty_bytes(pane_sixel_content);
+ terminal_pane.scroll_up(10, fake_client_id);
+ assert_snapshot!(format!("{:?}", terminal_pane.grid));
+ terminal_pane.scroll_down(3, fake_client_id);
+ assert_snapshot!(format!("{:?}", terminal_pane.grid));
+ terminal_pane.clear_scroll();
+ assert_snapshot!(format!("{:?}", terminal_pane.grid));
+}
+
+#[test]
+pub fn multiple_sixel_images_in_pane() {
+ let fake_client_id = 1;
+ let mut fake_win_size = PaneGeom::default();
+ fake_win_size.cols.set_inner(121);
+ fake_win_size.rows.set_inner(20);
+
+ let pid = 1;
+ let style = Style::default();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_colors = Rc::new(RefCell::new(Palette::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
+ let character_cell_size = Rc::new(RefCell::new(Some(SizeInPixels {
+ width: 8,
+ height: 21,
+ })));
+ let mut terminal_pane = TerminalPane::new(
+ pid,
+ fake_win_size,
+ style,
+ 0,
+ String::new(),
+ Rc::new(RefCell::new(LinkHandler::new())),
+ character_cell_size,
+ sixel_image_store,
+ terminal_emulator_colors,
+ terminal_emulator_color_codes,
+ ); // 0 is the pane index
+ let mut text_to_fill_pane = String::new();
+ for i in 0..5 {
+ writeln!(&mut text_to_fill_pane, "\rline {}", i + 1).unwrap();
+ }
+ writeln!(&mut text_to_fill_pane, "\r").unwrap();
+ let pane_sixel_content = read_fixture("sixel-image-500px.six");
+ terminal_pane.handle_pty_bytes(pane_sixel_content.clone()); // one image above text
+ terminal_pane.handle_pty_bytes(text_to_fill_pane.into_bytes());
+ terminal_pane.handle_pty_bytes(pane_sixel_content); // one image below text
+ terminal_pane.scroll_up(20, fake_client_id); // scroll up to see both images
+ assert_snapshot!(format!("{:?}", terminal_pane.grid));
+}
+
+#[test]
+pub fn resizing_pane_with_sixel_images() {
+ // here we test, for example, that sixel images don't wrap with other lines
+ let fake_client_id = 1;
+ let mut fake_win_size = PaneGeom::default();
+ fake_win_size.cols.set_inner(121);
+ fake_win_size.rows.set_inner(20);
+
+ let pid = 1;
+ let style = Style::default();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_colors = Rc::new(RefCell::new(Palette::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
+ let character_cell_size = Rc::new(RefCell::new(Some(SizeInPixels {
+ width: 8,
+ height: 21,
+ })));
+ let mut terminal_pane = TerminalPane::new(
+ pid,
+ fake_win_size,
+ style,
+ 0,
+ String::new(),
+ Rc::new(RefCell::new(LinkHandler::new())),
+ character_cell_size,
+ sixel_image_store,
+ terminal_emulator_colors,
+ terminal_emulator_color_codes,
+ ); // 0 is the pane index
+ let mut text_to_fill_pane = String::new();
+ for i in 0..5 {
+ writeln!(&mut text_to_fill_pane, "\rline {}", i + 1).unwrap();
+ }
+ writeln!(&mut text_to_fill_pane, "\r").unwrap();
+ let pane_sixel_content = read_fixture("sixel-image-500px.six");
+ terminal_pane.handle_pty_bytes(pane_sixel_content.clone());
+ terminal_pane.handle_pty_bytes(text_to_fill_pane.into_bytes());
+ terminal_pane.handle_pty_bytes(pane_sixel_content);
+ let mut new_win_size = PaneGeom::default();
+ new_win_size.cols.set_inner(100);
+ new_win_size.rows.set_inner(20);
+ terminal_pane.set_geom(new_win_size);
+ terminal_pane.scroll_up(20, fake_client_id); // scroll up to see both images
+ assert_snapshot!(format!("{:?}", terminal_pane.grid));
+}
+
+#[test]
+pub fn changing_character_cell_size_with_sixel_images() {
+ let fake_client_id = 1;
+ let mut fake_win_size = PaneGeom::default();
+ fake_win_size.cols.set_inner(121);
+ fake_win_size.rows.set_inner(20);
+
+ let pid = 1;
+ let style = Style::default();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_colors = Rc::new(RefCell::new(Palette::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
+ let character_cell_size = Rc::new(RefCell::new(Some(SizeInPixels {
+ width: 8,
+ height: 21,
+ })));
+ let mut terminal_pane = TerminalPane::new(
+ pid,
+ fake_win_size,
+ style,
+ 0,
+ String::new(),
+ Rc::new(RefCell::new(LinkHandler::new())),
+ character_cell_size.clone(),
+ sixel_image_store,
+ terminal_emulator_colors,
+ terminal_emulator_color_codes,
+ ); // 0 is the pane index
+ let mut text_to_fill_pane = String::new();
+ for i in 0..5 {
+ writeln!(&mut text_to_fill_pane, "\rline {}", i + 1).unwrap();
+ }
+ writeln!(&mut text_to_fill_pane, "\r").unwrap();
+ let pane_sixel_content = read_fixture("sixel-image-500px.six");
+ terminal_pane.handle_pty_bytes(pane_sixel_content.clone());
+ terminal_pane.handle_pty_bytes(text_to_fill_pane.into_bytes());
+ terminal_pane.handle_pty_bytes(pane_sixel_content);
+ // here the new_win_size is the same as the old one, we just update the character_cell_size
+ // which will be picked up upon resize (which is why we're doing set_geom below)
+ let mut new_win_size = PaneGeom::default();
+ new_win_size.cols.set_inner(121);
+ new_win_size.rows.set_inner(20);
+ *character_cell_size.borrow_mut() = Some(SizeInPixels {
+ width: 8,
+ height: 18,
+ });
+ terminal_pane.set_geom(new_win_size);
+ terminal_pane.scroll_up(10, fake_client_id); // scroll up to see both images
+ assert_snapshot!(format!("{:?}", terminal_pane.grid));
+}
+
+#[test]
+pub fn keep_working_after_corrupted_sixel_image() {
+ let mut fake_win_size = PaneGeom::default();
+ fake_win_size.cols.set_inner(121);
+ fake_win_size.rows.set_inner(20);
+
+ let pid = 1;
+ let style = Style::default();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_colors = Rc::new(RefCell::new(Palette::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
+ let character_cell_size = Rc::new(RefCell::new(Some(SizeInPixels {
+ width: 8,
+ height: 21,
+ })));
+ let mut terminal_pane = TerminalPane::new(
+ pid,
+ fake_win_size,
+ style,
+ 0,
+ String::new(),
+ Rc::new(RefCell::new(LinkHandler::new())),
+ character_cell_size,
+ sixel_image_store,
+ terminal_emulator_colors,
+ terminal_emulator_color_codes,
+ ); // 0 is the pane index
+
+ let sixel_image_bytes = "\u{1b}PI AM CORRUPTED BWAHAHAq
+ #0;2;0;0;0#1;2;100;100;0#2;2;0;100;0
+ #1~~@@vv@@~~@@~~$
+ #2??}}GG}}??}}??-
+ #1!14@
+ \u{1b}\\";
+
+ terminal_pane.handle_pty_bytes(Vec::from(sixel_image_bytes.as_bytes()));
+ let mut text_to_fill_pane = String::new();
+ for i in 0..5 {
+ writeln!(&mut text_to_fill_pane, "\rline {}", i + 1).unwrap();
+ }
+ terminal_pane.handle_pty_bytes(text_to_fill_pane.into_bytes());
+ assert_snapshot!(format!("{:?}", terminal_pane.grid));
+}
diff --git a/zellij-server/src/route.rs b/zellij-server/src/route.rs
index 253f62bc..4420cf36 100644
--- a/zellij-server/src/route.rs
+++ b/zellij-server/src/route.rs
@@ -28,14 +28,24 @@ fn route_action(
client_id: ClientId,
) -> bool {
let mut should_break = false;
- session
- .senders
- .send_to_plugin(PluginInstruction::Update(
- None,
- Some(client_id),
- Event::InputReceived,
- ))
- .unwrap();
+
+ // forward the action to plugins unless it is a mousehold
+ // this is a bit of a hack around the unfortunate architecture we use with plugins
+ // this will change as soon as we refactor
+ match action {
+ Action::MouseHold(_) => {},
+ _ => {
+ session
+ .senders
+ .send_to_plugin(PluginInstruction::Update(
+ None,
+ Some(client_id),
+ Event::InputReceived,
+ ))
+ .unwrap();
+ },
+ }
+
match action {
Action::ToggleTab => {
session
@@ -493,6 +503,16 @@ pub(crate) fn route_thread_main(
))
.unwrap();
},
+ ClientToServerMsg::ColorRegisters(color_registers) => {
+ rlocked_sessions
+ .as_ref()
+ .unwrap()
+ .senders
+ .send_to_screen(ScreenInstruction::TerminalColorRegisters(
+ color_registers,
+ ))
+ .unwrap();
+ },
ClientToServerMsg::NewClient(
client_attributes,
cli_args,
diff --git a/zellij-server/src/screen.rs b/zellij-server/src/screen.rs
index 9d284b32..b5ebad53 100644
--- a/zellij-server/src/screen.rs
+++ b/zellij-server/src/screen.rs
@@ -1,7 +1,7 @@
//! Things related to [`Screen`]s.
use std::cell::RefCell;
-use std::collections::{BTreeMap, HashSet};
+use std::collections::{BTreeMap, HashMap, HashSet};
use std::os::unix::io::RawFd;
use std::rc::Rc;
use std::str;
@@ -15,6 +15,7 @@ use crate::panes::terminal_character::AnsiCode;
use crate::{
output::Output,
+ panes::sixel::SixelImageStore,
panes::PaneId,
pty::{ClientOrTabIndex, PtyInstruction, VteBytes},
tab::Tab,
@@ -95,6 +96,7 @@ pub enum ScreenInstruction {
TerminalPixelDimensions(PixelDimensions),
TerminalBackgroundColor(String),
TerminalForegroundColor(String),
+ TerminalColorRegisters(Vec<(usize, String)>),
ChangeMode(ModeInfo, ClientId),
LeftClick(Position, ClientId),
RightClick(Position, ClientId),
@@ -184,6 +186,7 @@ impl From<&ScreenInstruction> for ScreenContext {
ScreenInstruction::TerminalForegroundColor(..) => {
ScreenContext::TerminalForegroundColor
},
+ ScreenInstruction::TerminalColorRegisters(..) => ScreenContext::TerminalColorRegisters,
ScreenInstruction::ChangeMode(..) => ScreenContext::ChangeMode,
ScreenInstruction::ToggleActiveSyncTab(..) => ScreenContext::ToggleActiveSyncTab,
ScreenInstruction::ScrollUpAt(..) => ScreenContext::ScrollUpAt,
@@ -247,9 +250,11 @@ pub(crate) struct Screen {
size: Size,
pixel_dimensions: PixelDimensions,
character_cell_size: Rc<RefCell<Option<SizeInPixels>>>,
+ sixel_image_store: Rc<RefCell<SixelImageStore>>,
/// The overlay that is drawn on top of [`Pane`]'s', [`Tab`]'s and the [`Screen`]
overlay: OverlayWindow,
terminal_emulator_colors: Rc<RefCell<Palette>>,
+ terminal_emulator_color_codes: Rc<RefCell<HashMap<usize, String>>>,
connected_clients: Rc<RefCell<HashSet<ClientId>>>,
/// The indices of this [`Screen`]'s active [`Tab`]s.
active_tab_indices: BTreeMap<ClientId, usize>,
@@ -279,12 +284,14 @@ impl Screen {
size: client_attributes.size,
pixel_dimensions: Default::default(),
character_cell_size: Rc::new(RefCell::new(None)),
+ sixel_image_store: Rc::new(RefCell::new(SixelImageStore::default())),
style: client_attributes.style,
connected_clients: Rc::new(RefCell::new(HashSet::new())),
active_tab_indices: BTreeMap::new(),
tabs: BTreeMap::new(),
overlay: OverlayWindow::default(),
terminal_emulator_colors: Rc::new(RefCell::new(Palette::default())),
+ terminal_emulator_color_codes: Rc::new(RefCell::new(HashMap::new())),
tab_history: BTreeMap::new(),
mode_info: BTreeMap::new(),
default_mode_info: mode_info,
@@ -518,10 +525,19 @@ impl Screen {
self.terminal_emulator_colors.borrow_mut().fg = fg_palette_color;
}
}
+ pub fn update_terminal_color_registers(&mut self, color_registers: Vec<(usize, String)>) {
+ let mut terminal_emulator_color_codes = self.terminal_emulator_color_codes.borrow_mut();
+ for (color_register, color_sequence) in color_registers {
+ terminal_emulator_color_codes.insert(color_register, color_sequence);
+ }
+ }
/// Renders this [`Screen`], which amounts to rendering its active [`Tab`].
pub fn render(&mut self) {
- let mut output = Output::default();
+ let mut output = Output::new(
+ self.sixel_image_store.clone(),
+ self.character_cell_size.clone(),
+ );
let mut tabs_to_close = vec![];
let size = self.size;
let overlay = self.overlay.clone();
@@ -599,6 +615,7 @@ impl Screen {
String::new(),
self.size,
self.character_cell_size.clone(),
+ self.sixel_image_store.clone(),
self.bus.os_input.as_ref().unwrap().clone(),
self.bus.senders.clone(),
self.max_panes,
@@ -610,6 +627,7 @@ impl Screen {
client_id,
self.copy_options.clone(),
self.terminal_emulator_colors.clone(),
+ self.terminal_emulator_color_codes.clone(),
);
tab.apply_layout(layout, new_pids, tab_index, client_id);
if self.session_is_mirrored {
@@ -793,7 +811,6 @@ impl Screen {
pub fn move_focus_left_or_previous_tab(&mut self, client_id: ClientId) {
if let Some(active_tab) = self.get_active_tab_mut(client_id) {
if !active_tab.move_focus_left(client_id) {
- println!("can has true");
self.switch_tab_prev(client_id);
}
} else {
@@ -1236,6 +1253,9 @@ pub(crate) fn screen_thread_main(
ScreenInstruction::TerminalForegroundColor(background_color_instruction) => {
screen.update_terminal_foreground_color(background_color_instruction);
},
+ ScreenInstruction::TerminalColorRegisters(color_registers) => {
+ screen.update_terminal_color_registers(color_registers);
+ },
ScreenInstruction::ChangeMode(mode_info, client_id) => {
screen.change_mode(mode_info, client_id);
screen.render();
@@ -1264,8 +1284,9 @@ pub(crate) fn screen_thread_main(
screen.render();
},
ScreenInstruction::MouseHold(point, client_id) => {
- active_tab!(screen, client_id, |tab: &mut Tab| tab
- .handle_mouse_hold(&point, client_id));
+ active_tab!(screen, client_id, |tab: &mut Tab| {
+ tab.handle_mouse_hold(&point, client_id);
+ });
screen.render();
},
ScreenInstruction::Copy(client_id) => {
diff --git a/zellij-server/src/tab/mod.rs b/zellij-server/src/tab/mod.rs
index 10ed525f..6c5c2c6b 100644
--- a/zellij-server/src/tab/mod.rs
+++ b/zellij-server/src/tab/mod.rs
@@ -17,7 +17,8 @@ use crate::ui::pane_boundaries_frame::FrameParams;
use self::clipboard::ClipboardProvider;
use crate::{
os_input_output::ServerOsApi,
- output::{CharacterChunk, Output},
+ output::{CharacterChunk, Output, SixelImageChunk},
+ panes::sixel::SixelImageStore,
panes::{FloatingPanes, TiledPanes},
panes::{LinkHandler, PaneId, PluginPane, TerminalPane},
pty::{ClientOrTabIndex, PtyInstruction, VteBytes},
@@ -77,6 +78,7 @@ pub(crate) struct Tab {
viewport: Rc<RefCell<Viewport>>, // includes all non-UI panes
display_area: Rc<RefCell<Size>>, // includes all panes (including eg. the status bar and tab bar in the default layout)
character_cell_size: Rc<RefCell<Option<SizeInPixels>>>,
+ sixel_image_store: Rc<RefCell<SixelImageStore>>,
os_api: Box<dyn ServerOsApi>,
pub senders: ThreadSenders,
synchronize_is_active: bool,
@@ -96,6 +98,7 @@ pub(crate) struct Tab {
copy_on_select: bool,
last_mouse_hold_position: Option<Position>,
terminal_emulator_colors: Rc<RefCell<Palette>>,
+ terminal_emulator_color_codes: Rc<RefCell<HashMap<usize, String>>>,
}
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
@@ -135,7 +138,7 @@ pub trait Pane {
fn render(
&mut self,
client_id: Option<ClientId>,
- ) -> Option<(Vec<CharacterChunk>, Option<String>)>; // TODO: better
+ ) -> Option<(Vec<CharacterChunk>, Option<String>, Vec<SixelImageChunk>)>; // TODO: better
fn render_frame(
&mut self,
client_id: ClientId,
@@ -287,6 +290,7 @@ impl Tab {
name: String,
display_area: Size,
character_cell_size: Rc<RefCell<Option<SizeInPixels>>>,
+ sixel_image_store: Rc<RefCell<SixelImageStore>>,
os_api: Box<dyn ServerOsApi>,
senders: ThreadSenders,
max_panes: Option<usize>,
@@ -298,6 +302,7 @@ impl Tab {
client_id: ClientId,
copy_options: CopyOptions,
terminal_emulator_colors: Rc<RefCell<Palette>>,
+ terminal_emulator_color_codes: Rc<RefCell<HashMap<usize, String>>>,
) -> Self {
let name = if name.is_empty() {
format!("Tab #{}", index + 1)
@@ -354,6 +359,7 @@ impl Tab {
viewport,
display_area,
character_cell_size,
+ sixel_image_store,
synchronize_is_active: false,
os_api,
senders,
@@ -371,6 +377,7 @@ impl Tab {
copy_on_select: copy_options.copy_on_select,
last_mouse_hold_position: None,
terminal_emulator_colors,
+ terminal_emulator_color_codes,
}
}
@@ -438,7 +445,9 @@ impl Tab {
layout.pane_name.clone().unwrap_or_default(),
self.link_handler.clone(),
self.character_cell_size.clone(),
+ self.sixel_image_store.clone(),
self.terminal_emulator_colors.clone(),
+ self.terminal_emulator_color_codes.clone(),
);
new_pane.set_borderless(layout.borderless);
self.tiled_panes
@@ -668,7 +677,9 @@ impl Tab {
String::new(),
self.link_handler.clone(),
self.character_cell_size.clone(),
+ self.sixel_image_store.clone(),
self.terminal_emulator_colors.clone(),
+ self.terminal_emulator_color_codes.clone(),
);
new_pane.set_content_offset(Offset::frame(1)); // floating panes always have a frame
resize_pty!(new_pane, self.os_api);
@@ -691,7 +702,9 @@ impl Tab {
String::new(),
self.link_handler.clone(),
self.character_cell_size.clone(),
+ self.sixel_image_store.clone(),
self.terminal_emulator_colors.clone(),
+ self.terminal_emulator_color_codes.clone(),
);
self.tiled_panes.insert_pane(pid, Box::new(new_terminal));
self.should_clear_display_before_rendering = true;
@@ -717,7 +730,9 @@ impl Tab {
String::new(),
self.link_handler.clone(),
self.character_cell_size.clone(),
+ self.sixel_image_store.clone(),
self.terminal_emulator_colors.clone(),
+ self.terminal_emulator_color_codes.clone(),
);
let replaced_pane = if self.floating_panes.panes_are_visible() {
self.floating_panes
@@ -762,7 +777,9 @@ impl Tab {
String::new(),
self.link_handler.clone(),
self.character_cell_size.clone(),
+ self.sixel_image_store.clone(),
self.terminal_emulator_colors.clone(),
+ self.terminal_emulator_color_codes.clone(),
);
self.tiled_panes
.split_pane_horizontally(pid, Box::new(new_terminal), client_id);
@@ -790,7 +807,9 @@ impl Tab {
String::new(),
self.link_handler.clone(),
self.character_cell_size.clone(),
+ self.sixel_image_store.clone(),
self.terminal_emulator_colors.clone(),
+ self.terminal_emulator_color_codes.clone(),
);
self.tiled_panes
.split_pane_vertically(pid, Box::new(new_terminal), client_id);
@@ -1787,7 +1806,12 @@ impl Tab {
}
}
}
- pub fn handle_mouse_hold(&mut self, position_on_screen: &Position, client_id: ClientId) {
+ pub fn handle_mouse_hold(
+ &mut self,
+ position_on_screen: &Position,
+ client_id: ClientId,
+ ) -> bool {
+ // return value indicates whether we should trigger a render
// determine if event is repeated to enable smooth scrolling
let is_repeated = if let Some(last_position) = self.last_mouse_hold_position {
position_on_screen == &last_position
@@ -1805,7 +1829,8 @@ impl Tab {
.move_pane_with_mouse(*position_on_screen, search_selectable)
{
self.set_force_render();
- return;
+ return !is_repeated; // we don't need to re-render in this case if the pane did not move
+ // return;
}
let selecting = self.selecting_with_mouse;
@@ -1825,10 +1850,13 @@ impl Tab {
let mouse_event = format!("\u{1b}[<32;{:?};{:?}M", col, line);
self.write_to_active_terminal(mouse_event.into_bytes(), client_id);
+ return true; // we need to re-render in this case so the selection disappears
} else if selecting {
active_pane.update_selection(&relative_position, client_id);
+ return true; // we need to re-render in this case so the selection is updated
}
}
+ false // we shouldn't even get here, but might as well not needlessly render if we do
}
pub fn copy_selection(&self, client_id: ClientId) {
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__floating_pane_above_sixel_image.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__floating_pane_above_sixel_image.snap
new file mode 100644
index 00000000..19d6feb8
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__floating_pane_above_sixel_image.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 1343
+expression: snapshot
+---
+00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────── SCROLL: 0/7 ┐
+01 (C): │ixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixe │
+02 (C): │ixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixe │
+03 (C): │ixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixe │
+04 (C): │ixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixe │
+05 (C): │ixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixe │
+06 (C): │ixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixe │
+07 (C): │ixelSixelSixelSixelSixelSixelSixe┌ Pane #2 ─────────────────────────────────────────────────┐ │
+08 (C): │ixelSixelSixelSixelSixelSixelSixe│ │ │
+09 (C): │ixelSixelSixelSixelSixelSixelSixe│ │ │
+10 (C): │ixelSixelSixelSixelSixelSixelSixe│ │ │
+11 (C): │ixelSixelSixelSixelSixelSixelSixe│ │ │
+12 (C): │ixelSixelSixelSixelSixelSixelSixe│ │ │
+13 (C): │ixelSixelSixelSixelSixelSixelSixe│ │ │
+14 (C): │ixelSixelSixelSixelSixelSixelSixe│ │ │
+15 (C): │ixelSixelSixelSixelSixelSixelSixe│ │ │
+16 (C): │ixelSixelSixelSixelSixelSixelSixe└──────────────────────────────────────────────────────────┘ │
+17 (C): │ixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixe │
+18 (C): │ │
+19 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_floating_pane_with_sixel_image.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_floating_pane_with_sixel_image.snap
new file mode 100644
index 00000000..df091cdb
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__move_floating_pane_with_sixel_image.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 1312
+expression: snapshot
+---
+00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+01 (C): │ │
+02 (C): │ │
+03 (C): │ │
+04 (C): │ │
+05 (C): │ │
+06 (C): │ │
+07 (C): │ ┌ Pane #2 ────────────────────────────────── SCROLL: 0/17 ┐ │
+08 (C): │ │SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix│ │
+09 (C): │ │SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix│ │
+10 (C): │ │SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix│ │
+11 (C): │ │SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix│ │
+12 (C): │ │SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix│ │
+13 (C): │ │SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix│ │
+14 (C): │ │SixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSixelSix│ │
+15 (C): │ │ │ │
+16 (C): │ └──────────────────────────────────────────────────────────┘ │
+17 (C): │ │
+18 (C): │ │
+19 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/tab_integration_tests.rs b/zellij-server/src/tab/unit/tab_integration_tests.rs
index efb8909d..24edc91a 100644
--- a/zellij-server/src/tab/unit/tab_integration_tests.rs
+++ b/zellij-server/src/tab/unit/tab_integration_tests.rs
@@ -1,4 +1,5 @@
use super::{Output, Tab};
+use crate::panes::sixel::SixelImageStore;
use crate::screen::CopyOptions;
use crate::Arc;
use crate::Mutex;
@@ -13,12 +14,11 @@ use std::path::PathBuf;
use zellij_utils::envs::set_session_name;
use zellij_utils::input::layout::LayoutTemplate;
use zellij_utils::ipc::IpcReceiverWithContext;
-use zellij_utils::pane_size::Size;
+use zellij_utils::pane_size::{Size, SizeInPixels};
use zellij_utils::position::Position;
use std::cell::RefCell;
-use std::collections::HashMap;
-use std::collections::HashSet;
+use std::collections::{HashMap, HashSet};
use std::os::unix::io::RawFd;
use std::rc::Rc;
@@ -119,12 +119,15 @@ fn create_new_tab(size: Size) -> Tab {
let character_cell_info = Rc::new(RefCell::new(None));
let terminal_emulator_colors = Rc::new(RefCell::new(Palette::default()));
let copy_options = CopyOptions::default();
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
let mut tab = Tab::new(
index,
position,
name,
size,
character_cell_info,
+ sixel_image_store,
os_api,
senders,
max_panes,
@@ -136,6 +139,66 @@ fn create_new_tab(size: Size) -> Tab {
client_id,
copy_options,
terminal_emulator_colors,
+ terminal_emulator_color_codes,
+ );
+ tab.apply_layout(
+ LayoutTemplate::default().try_into().unwrap(),
+ vec![1],
+ index,
+ client_id,
+ );
+ tab
+}
+
+fn create_new_tab_with_sixel_support(
+ size: Size,
+ sixel_image_store: Rc<RefCell<SixelImageStore>>,
+) -> Tab {
+ // this is like the create_new_tab function but includes stuff needed for sixel,
+ // eg. character_cell_size
+ set_session_name("test".into());
+ let index = 0;
+ let position = 0;
+ let name = String::new();
+ let os_api = Box::new(FakeInputOutput {
+ file_dumps: Arc::new(Mutex::new(HashMap::new())),
+ });
+ let senders = ThreadSenders::default().silently_fail_on_send();
+ let max_panes = None;
+ let mode_info = ModeInfo::default();
+ let style = Style::default();
+ let draw_pane_frames = true;
+ let client_id = 1;
+ let session_is_mirrored = true;
+ let mut connected_clients = HashSet::new();
+ connected_clients.insert(client_id);
+ let connected_clients = Rc::new(RefCell::new(connected_clients));
+ let character_cell_size = Rc::new(RefCell::new(Some(SizeInPixels {
+ width: 8,
+ height: 21,
+ })));
+ let terminal_emulator_colors = Rc::new(RefCell::new(Palette::default()));
+ let copy_options = CopyOptions::default();
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
+ let mut tab = Tab::new(
+ index,
+ position,
+ name,
+ size,
+ character_cell_size,
+ sixel_image_store,
+ os_api,
+ senders,
+ max_panes,
+ style,
+ mode_info,
+ draw_pane_frames,
+ connected_clients,
+ session_is_mirrored,
+ client_id,
+ copy_options,
+ terminal_emulator_colors,
+ terminal_emulator_color_codes,
);
tab.apply_layout(
LayoutTemplate::default().try_into().unwrap(),
@@ -162,12 +225,48 @@ use ::insta::assert_snapshot;
use zellij_utils::vte;
fn take_snapshot(ansi_instructions: &str, rows: usize, columns: usize, palette: Palette) -> String {
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
+ let character_cell_size = Rc::new(RefCell::new(Some(SizeInPixels {
+ width: 8,
+ height: 21,
+ })));
let mut grid = Grid::new(
rows,
columns,
Rc::new(RefCell::new(palette)),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
- Rc::new(RefCell::new(None)),
+ character_cell_size,
+ sixel_image_store,
+ );
+ let mut vte_parser = vte::Parser::new();
+ for &byte in ansi_instructions.as_bytes() {
+ vte_parser.advance(&mut grid, byte);
+ }
+ format!("{:?}", grid)
+}
+
+fn take_snapshot_with_sixel(
+ ansi_instructions: &str,
+ rows: usize,
+ columns: usize,
+ palette: Palette,
+ sixel_image_store: Rc<RefCell<SixelImageStore>>,
+) -> String {
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
+ let character_cell_size = Rc::new(RefCell::new(Some(SizeInPixels {
+ width: 8,
+ height: 21,
+ })));
+ let mut grid = Grid::new(
+ rows,
+ columns,
+ Rc::new(RefCell::new(palette)),
+ terminal_emulator_color_codes,
+ Rc::new(RefCell::new(LinkHandler::new())),
+ character_cell_size,
+ sixel_image_store,
);
let mut vte_parser = vte::Parser::new();
for &byte in ansi_instructions.as_bytes() {
@@ -183,12 +282,16 @@ fn take_snapshot_and_cursor_position(
palette: Palette,
) -> (String, Option<(usize, usize)>) {
// snapshot, x_coordinates, y_coordinates
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut grid = Grid::new(
rows,
columns,
Rc::new(RefCell::new(palette)),
+ terminal_emulator_color_codes,
Rc::new(RefCell::new(LinkHandler::new())),
Rc::new(RefCell::new(None)),
+ sixel_image_store,
);
let mut vte_parser = vte::Parser::new();
for &byte in ansi_instructions.as_bytes() {
@@ -1234,6 +1337,76 @@ fn save_cursor_position_across_resizes() {
}
#[test]
+fn move_floating_pane_with_sixel_image() {
+ let new_pane_id = PaneId::Terminal(2);
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 1;
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let mut tab = create_new_tab_with_sixel_support(size, sixel_image_store.clone());
+ let character_cell_size = Rc::new(RefCell::new(Some(SizeInPixels {
+ width: 8,
+ height: 21,
+ })));
+ let mut output = Output::new(sixel_image_store.clone(), character_cell_size);
+
+ tab.toggle_floating_panes(client_id, None);
+ tab.new_pane(new_pane_id, Some(client_id));
+ let fixture = read_fixture("sixel-image-500px.six");
+ tab.handle_pty_bytes(2, fixture);
+ tab.handle_left_click(&Position::new(5, 71), client_id);
+ tab.handle_mouse_release(&Position::new(7, 75), client_id);
+
+ tab.render(&mut output, None);
+ let snapshot = take_snapshot_with_sixel(
+ output.serialize().get(&client_id).unwrap(),
+ size.rows,
+ size.cols,
+ Palette::default(),
+ sixel_image_store,
+ );
+
+ assert_snapshot!(snapshot);
+}
+
+#[test]
+fn floating_pane_above_sixel_image() {
+ let new_pane_id = PaneId::Terminal(2);
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 1;
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let mut tab = create_new_tab_with_sixel_support(size, sixel_image_store.clone());
+ let character_cell_size = Rc::new(RefCell::new(Some(SizeInPixels {
+ width: 8,
+ height: 21,
+ })));
+ let mut output = Output::new(sixel_image_store.clone(), character_cell_size);
+
+ tab.toggle_floating_panes(client_id, None);
+ tab.new_pane(new_pane_id, Some(client_id));
+ let fixture = read_fixture("sixel-image-500px.six");
+ tab.handle_pty_bytes(1, fixture);
+ tab.handle_left_click(&Position::new(5, 71), client_id);
+ tab.handle_mouse_release(&Position::new(7, 75), client_id);
+
+ tab.render(&mut output, None);
+ let snapshot = take_snapshot_with_sixel(
+ output.serialize().get(&client_id).unwrap(),
+ size.rows,
+ size.cols,
+ Palette::default(),
+ sixel_image_store,
+ );
+
+ assert_snapshot!(snapshot);
+}
+
+#[test]
fn suppress_tiled_pane() {
let size = Size {
cols: 121,
diff --git a/zellij-server/src/tab/unit/tab_tests.rs b/zellij-server/src/tab/unit/tab_tests.rs
index 045515fa..719f9ce9 100644
--- a/zellij-server/src/tab/unit/tab_tests.rs
+++ b/zellij-server/src/tab/unit/tab_tests.rs
@@ -1,4 +1,5 @@
use super::Tab;
+use crate::panes::sixel::SixelImageStore;
use crate::screen::CopyOptions;
use crate::{
os_input_output::{AsyncReader, Pid, ServerOsApi},
@@ -13,7 +14,7 @@ use zellij_utils::ipc::IpcReceiverWithContext;
use zellij_utils::pane_size::{Size, SizeInPixels};
use std::cell::RefCell;
-use std::collections::HashSet;
+use std::collections::{HashMap, HashSet};
use std::os::unix::io::RawFd;
use std::rc::Rc;
@@ -105,12 +106,15 @@ fn create_new_tab(size: Size) -> Tab {
let connected_clients = Rc::new(RefCell::new(connected_clients));
let terminal_emulator_colors = Rc::new(RefCell::new(Palette::default()));
let copy_options = CopyOptions::default();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut tab = Tab::new(
index,
position,
name,
size,
character_cell_info,
+ sixel_image_store,
os_api,
senders,
max_panes,
@@ -122,6 +126,7 @@ fn create_new_tab(size: Size) -> Tab {
client_id,
copy_options,
terminal_emulator_colors,
+ terminal_emulator_color_codes,
);
tab.apply_layout(
LayoutTemplate::default().try_into().unwrap(),
@@ -152,12 +157,15 @@ fn create_new_tab_with_cell_size(
let connected_clients = Rc::new(RefCell::new(connected_clients));
let terminal_emulator_colors = Rc::new(RefCell::new(Palette::default()));
let copy_options = CopyOptions::default();
+ let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default()));
+ let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new()));
let mut tab = Tab::new(
index,
position,
name,
size,
character_cell_size,
+ sixel_image_store,
os_api,
senders,
max_panes,
@@ -169,6 +177,7 @@ fn create_new_tab_with_cell_size(
client_id,
copy_options,
terminal_emulator_colors,
+ terminal_emulator_color_codes,
);
tab.apply_layout(
LayoutTemplate::default().try_into().unwrap(),
diff --git a/zellij-server/src/ui/pane_contents_and_ui.rs b/zellij-server/src/ui/pane_contents_and_ui.rs
index 50f76316..b0eae8e8 100644
--- a/zellij-server/src/ui/pane_contents_and_ui.rs
+++ b/zellij-server/src/ui/pane_contents_and_ui.rs
@@ -44,13 +44,19 @@ impl<'a> PaneContentsAndUi<'a> {
&mut self,
clients: impl Iterator<Item = ClientId>,
) {
- if let Some((character_chunks, raw_vte_output)) = self.pane.render(None) {
+ if let Some((character_chunks, raw_vte_output, sixel_image_chunks)) = self.pane.render(None)
+ {
let clients: Vec<ClientId> = clients.collect();
self.output.add_character_chunks_to_multiple_clients(
character_chunks,
clients.iter().copied(),
self.z_index,
);
+ self.output.add_sixel_image_chunks_to_multiple_clients(
+ sixel_image_chunks,
+ clients.iter().copied(),
+ self.z_index,
+ );
if let Some(raw_vte_output) = raw_vte_output {
self.output.add_post_vte_instruction_to_multiple_clients(
clients.iter().copied(),
@@ -65,9 +71,16 @@ impl<'a> PaneContentsAndUi<'a> {
}
}
pub fn render_pane_contents_for_client(&mut self, client_id: ClientId) {
- if let Some((character_chunks, raw_vte_output)) = self.pane.render(Some(client_id)) {
+ if let Some((character_chunks, raw_vte_output, sixel_image_chunks)) =
+ self.pane.render(Some(client_id))
+ {
self.output
.add_character_chunks_to_client(client_id, character_chunks, self.z_index);
+ self.output.add_sixel_image_chunks_to_client(
+ client_id,
+ sixel_image_chunks,
+ self.z_index,
+ );
if let Some(raw_vte_output) = raw_vte_output {
self.output.add_post_vte_instruction_to_client(
client_id,