diff options
| author | Aram Drevekenin <aram@poor.dev> | 2022-07-08 17:19:42 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-07-08 17:19:42 +0200 |
| commit | c89b416d764d80a72130821506f36157a08321e9 (patch) | |
| tree | 6d1cc2d7fd5fddbb33fcbff192153700a9788bec /zellij-server | |
| parent | fix: typo (#1567) (diff) | |
| download | sl0ppij-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')
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(¤t_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. "[D") 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, |
