diff --git a/assets/plugins/status-bar.wasm b/assets/plugins/status-bar.wasm index 01424587..68ff8a32 100755 Binary files a/assets/plugins/status-bar.wasm and b/assets/plugins/status-bar.wasm differ diff --git a/assets/plugins/strider.wasm b/assets/plugins/strider.wasm index 6c75575e..b32dcf9d 100755 Binary files a/assets/plugins/strider.wasm and b/assets/plugins/strider.wasm differ diff --git a/assets/plugins/tab-bar.wasm b/assets/plugins/tab-bar.wasm index ffdb5548..a7b2244c 100755 Binary files a/assets/plugins/tab-bar.wasm and b/assets/plugins/tab-bar.wasm differ diff --git a/src/tests/e2e/remote_runner.rs b/src/tests/e2e/remote_runner.rs index 5a3faaff..05f4bf2a 100644 --- a/src/tests/e2e/remote_runner.rs +++ b/src/tests/e2e/remote_runner.rs @@ -4,6 +4,7 @@ use std::sync::{Arc, Mutex}; use zellij_server::panes::{LinkHandler, TerminalPane}; use zellij_utils::pane_size::{Dimension, PaneGeom, Size}; use zellij_utils::vte; +use zellij_utils::zellij_tile::data::Palette; use zellij_utils::zellij_tile::prelude::Style; use ssh2::Session; @@ -162,6 +163,7 @@ fn read_from_channel( String::new(), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), + Rc::new(RefCell::new(Palette::default())), ); // 0 is the pane index loop { if !should_keep_running.load(Ordering::SeqCst) { diff --git a/zellij-client/src/input_handler.rs b/zellij-client/src/input_handler.rs index b2ef1e58..6b89a3f9 100644 --- a/zellij-client/src/input_handler.rs +++ b/zellij-client/src/input_handler.rs @@ -10,7 +10,7 @@ use zellij_utils::{ use crate::{ os_input_output::ClientOsApi, - pixel_csi_parser::{PixelCsiParser, PixelDimensionsOrKeys}, + stdin_ansi_parser::{AnsiStdinInstructionOrKeys, StdinAnsiParser}, ClientInstruction, CommandIsExecuting, InputInstruction, }; use zellij_utils::{ @@ -71,15 +71,19 @@ impl InputHandler { if self.options.mouse_mode.unwrap_or(true) { self.os_input.enable_mouse(); } - // [14t => get text area size in pixels, [16t => get character cell size in pixels - let get_cell_pixel_info = "\u{1b}[14t\u{1b}[16t"; + // [14t => get text area size in pixels, + // [16t => get character cell size in pixels + // ]11;?\ => get background color + // ]10;?\ => get foreground color + let get_cell_pixel_info = + "\u{1b}[14t\u{1b}[16t\u{1b}]11;?\u{1b}\u{5c}\u{1b}]10;?\u{1b}\u{5c}"; let _ = self .os_input .get_stdout_writer() .write(get_cell_pixel_info.as_bytes()) .unwrap(); - let mut pixel_csi_parser = PixelCsiParser::new(); - pixel_csi_parser.increment_expected_csi_instructions(2); + let mut ansi_stdin_parser = StdinAnsiParser::new(); + ansi_stdin_parser.increment_expected_ansi_instructions(4); loop { if self.should_exit { break; @@ -89,9 +93,9 @@ impl InputHandler { match input_event { InputEvent::Key(key_event) => { let key = cast_termwiz_key(key_event, &raw_bytes); - if pixel_csi_parser.expected_instructions() > 0 { + if ansi_stdin_parser.expected_instructions() > 0 { self.handle_possible_pixel_instruction( - pixel_csi_parser.parse(key, raw_bytes), + ansi_stdin_parser.parse(key, raw_bytes), ); } else { self.handle_key(&key, raw_bytes); @@ -123,7 +127,7 @@ impl InputHandler { .get_stdout_writer() .write(get_cell_pixel_info.as_bytes()) .unwrap(); - pixel_csi_parser.increment_expected_csi_instructions(2); + ansi_stdin_parser.increment_expected_ansi_instructions(4); } Err(err) => panic!("Encountered read error: {:?}", err), } @@ -140,14 +144,26 @@ impl InputHandler { } fn handle_possible_pixel_instruction( &mut self, - pixel_instruction_or_keys: Option, + pixel_instruction_or_keys: Option, ) { match pixel_instruction_or_keys { - Some(PixelDimensionsOrKeys::PixelDimensions(pixel_dimensions)) => { + Some(AnsiStdinInstructionOrKeys::PixelDimensions(pixel_dimensions)) => { self.os_input .send_to_server(ClientToServerMsg::TerminalPixelDimensions(pixel_dimensions)); } - Some(PixelDimensionsOrKeys::Keys(keys)) => { + Some(AnsiStdinInstructionOrKeys::BackgroundColor(background_color_instruction)) => { + self.os_input + .send_to_server(ClientToServerMsg::BackgroundColor( + background_color_instruction, + )); + } + Some(AnsiStdinInstructionOrKeys::ForegroundColor(foreground_color_instruction)) => { + self.os_input + .send_to_server(ClientToServerMsg::ForegroundColor( + foreground_color_instruction, + )); + } + Some(AnsiStdinInstructionOrKeys::Keys(keys)) => { for (key, raw_bytes) in keys { self.handle_key(&key, raw_bytes); } @@ -281,4 +297,4 @@ pub(crate) fn input_loop( #[cfg(test)] #[path = "./unit/input_handler_tests.rs"] -mod grid_tests; +mod input_handler_tests; diff --git a/zellij-client/src/lib.rs b/zellij-client/src/lib.rs index 1f05a9eb..bd5b04f5 100644 --- a/zellij-client/src/lib.rs +++ b/zellij-client/src/lib.rs @@ -2,7 +2,7 @@ pub mod os_input_output; mod command_is_executing; mod input_handler; -mod pixel_csi_parser; +mod stdin_ansi_parser; mod stdin_handler; use log::info; diff --git a/zellij-client/src/pixel_csi_parser.rs b/zellij-client/src/pixel_csi_parser.rs deleted file mode 100644 index fc2df627..00000000 --- a/zellij-client/src/pixel_csi_parser.rs +++ /dev/null @@ -1,146 +0,0 @@ -use zellij_utils::pane_size::SizeInPixels; - -use zellij_utils::{ipc::PixelDimensions, lazy_static::lazy_static, regex::Regex}; - -use zellij_tile::data::Key; - -pub struct PixelCsiParser { - expected_pixel_csi_instructions: usize, - current_buffer: Vec<(Key, Vec)>, -} - -impl PixelCsiParser { - pub fn new() -> Self { - PixelCsiParser { - expected_pixel_csi_instructions: 0, - current_buffer: vec![], - } - } - pub fn increment_expected_csi_instructions(&mut self, by: usize) { - self.expected_pixel_csi_instructions += by; - } - pub fn decrement_expected_csi_instructions(&mut self, by: usize) { - self.expected_pixel_csi_instructions = - self.expected_pixel_csi_instructions.saturating_sub(by); - } - pub fn expected_instructions(&self) -> usize { - self.expected_pixel_csi_instructions - } - pub fn parse(&mut self, key: Key, raw_bytes: Vec) -> Option { - if let Key::Char('t') = key { - self.current_buffer.push((key, raw_bytes)); - match PixelDimensionsOrKeys::pixel_dimensions_from_keys(&self.current_buffer) { - Ok(pixel_instruction) => { - self.decrement_expected_csi_instructions(1); - self.current_buffer.clear(); - Some(pixel_instruction) - } - Err(_) => { - self.expected_pixel_csi_instructions = 0; - Some(PixelDimensionsOrKeys::Keys( - self.current_buffer.drain(..).collect(), - )) - } - } - } else if self.key_is_valid(key) { - self.current_buffer.push((key, raw_bytes)); - None - } else { - self.current_buffer.push((key, raw_bytes)); - self.expected_pixel_csi_instructions = 0; - Some(PixelDimensionsOrKeys::Keys( - self.current_buffer.drain(..).collect(), - )) - } - } - fn key_is_valid(&self, key: Key) -> bool { - match key { - Key::Esc => { - // this is a UX improvement - // in case the user's terminal doesn't support one or more of these signals, - // if they spam ESC they need to be able to get back to normal mode and not "us - // waiting for pixel instructions" mode - if self - .current_buffer - .iter() - .find(|(key, _)| *key == Key::Esc) - .is_none() - { - true - } else { - false - } - } - Key::Char(';') | Key::Char('[') => true, - Key::Char(c) => { - if let '0'..='9' = c { - true - } else { - false - } - } - _ => false, - } - } -} - -#[derive(Debug)] -pub enum PixelDimensionsOrKeys { - // TODO: rename to PixelDimensionsOrKeys - PixelDimensions(PixelDimensions), - Keys(Vec<(Key, Vec)>), -} - -impl PixelDimensionsOrKeys { - pub fn pixel_dimensions_from_keys(keys: &Vec<(Key, Vec)>) -> Result { - lazy_static! { - static ref RE: Regex = Regex::new(r"^\u{1b}\[(\d+);(\d+);(\d+)t$").unwrap(); - } - let key_sequence: Vec> = keys - .iter() - .map(|(key, _)| match key { - Key::Char(c) => Some(*c), - Key::Esc => Some('\u{1b}'), - _ => None, - }) - .collect(); - if key_sequence.iter().all(|k| k.is_some()) { - let key_string: String = key_sequence.iter().map(|k| k.unwrap()).collect(); - let captures = RE - .captures_iter(&key_string) - .next() - .ok_or("invalid_instruction")?; - let csi_index = captures[1].parse::(); - let first_field = captures[2].parse::(); - let second_field = captures[3].parse::(); - if csi_index.is_err() || first_field.is_err() || second_field.is_err() { - return Err("invalid_instruction"); - } - match csi_index { - Ok(4) => { - // text area size - Ok(PixelDimensionsOrKeys::PixelDimensions(PixelDimensions { - character_cell_size: None, - text_area_size: Some(SizeInPixels { - height: first_field.unwrap(), - width: second_field.unwrap(), - }), - })) - } - Ok(6) => { - // character cell size - Ok(PixelDimensionsOrKeys::PixelDimensions(PixelDimensions { - character_cell_size: Some(SizeInPixels { - height: first_field.unwrap(), - width: second_field.unwrap(), - }), - text_area_size: None, - })) - } - _ => Err("invalid sequence"), - } - } else { - Err("invalid sequence") - } - } -} diff --git a/zellij-client/src/stdin_ansi_parser.rs b/zellij-client/src/stdin_ansi_parser.rs new file mode 100644 index 00000000..efffffc8 --- /dev/null +++ b/zellij-client/src/stdin_ansi_parser.rs @@ -0,0 +1,199 @@ +use zellij_utils::pane_size::SizeInPixels; + +use zellij_utils::{ipc::PixelDimensions, lazy_static::lazy_static, regex::Regex}; + +use zellij_tile::data::{CharOrArrow, Key}; + +pub struct StdinAnsiParser { + expected_ansi_instructions: usize, + current_buffer: Vec<(Key, Vec)>, +} + +impl StdinAnsiParser { + pub fn new() -> Self { + StdinAnsiParser { + expected_ansi_instructions: 0, + current_buffer: vec![], + } + } + pub fn increment_expected_ansi_instructions(&mut self, to: usize) { + self.expected_ansi_instructions = to; + } + pub fn decrement_expected_ansi_instructions(&mut self, by: usize) { + self.expected_ansi_instructions = self.expected_ansi_instructions.saturating_sub(by); + } + pub fn expected_instructions(&self) -> usize { + self.expected_ansi_instructions + } + pub fn parse(&mut self, key: Key, raw_bytes: Vec) -> Option { + if let Key::Char('t') = key { + self.current_buffer.push((key, raw_bytes)); + match AnsiStdinInstructionOrKeys::pixel_dimensions_from_keys(&self.current_buffer) { + Ok(pixel_instruction) => { + self.decrement_expected_ansi_instructions(1); + self.current_buffer.clear(); + Some(pixel_instruction) + } + Err(_) => { + self.expected_ansi_instructions = 0; + Some(AnsiStdinInstructionOrKeys::Keys( + self.current_buffer.drain(..).collect(), + )) + } + } + } else if let Key::Alt(CharOrArrow::Char('\\')) = key { + match AnsiStdinInstructionOrKeys::color_sequence_from_keys(&self.current_buffer) { + Ok(color_instruction) => { + self.decrement_expected_ansi_instructions(1); + self.current_buffer.clear(); + Some(color_instruction) + } + Err(_) => { + self.expected_ansi_instructions = 0; + Some(AnsiStdinInstructionOrKeys::Keys( + self.current_buffer.drain(..).collect(), + )) + } + } + } else if self.key_is_valid(key) { + self.current_buffer.push((key, raw_bytes)); + None + } else { + self.current_buffer.push((key, raw_bytes)); + self.expected_ansi_instructions = 0; + Some(AnsiStdinInstructionOrKeys::Keys( + self.current_buffer.drain(..).collect(), + )) + } + } + fn key_is_valid(&self, key: Key) -> bool { + if self.current_buffer.is_empty() + && (key != Key::Esc && key != Key::Alt(CharOrArrow::Char(']'))) + { + // the first key of a sequence is always Esc, but termwiz interprets esc + ] as Alt+] + return false; + } + match key { + Key::Esc => { + // this is a UX improvement + // in case the user's terminal doesn't support one or more of these signals, + // if they spam ESC they need to be able to get back to normal mode and not "us + // waiting for ansi instructions" mode + !self.current_buffer.iter().any(|(key, _)| *key == Key::Esc) + } + Key::Char(';') + | Key::Char('[') + | Key::Char(']') + | Key::Char('r') + | Key::Char('g') + | Key::Char('b') + | Key::Char('\\') + | Key::Char(':') + | Key::Char('/') => true, + Key::Alt(CharOrArrow::Char(']')) => true, + Key::Alt(CharOrArrow::Char('\\')) => true, + Key::Char(c) => { + if let '0'..='9' | 'a'..='f' = c { + true + } else { + false + } + } + _ => false, + } + } +} + +#[derive(Debug)] +pub enum AnsiStdinInstructionOrKeys { + PixelDimensions(PixelDimensions), + BackgroundColor(String), + ForegroundColor(String), + Keys(Vec<(Key, Vec)>), +} + +impl AnsiStdinInstructionOrKeys { + pub fn pixel_dimensions_from_keys(keys: &Vec<(Key, Vec)>) -> Result { + lazy_static! { + static ref RE: Regex = Regex::new(r"^\u{1b}\[(\d+);(\d+);(\d+)t$").unwrap(); + } + let key_sequence: Vec> = keys + .iter() + .map(|(key, _)| match key { + Key::Char(c) => Some(*c), + Key::Esc => Some('\u{1b}'), + _ => None, + }) + .collect(); + if key_sequence.iter().all(|k| k.is_some()) { + let key_string: String = key_sequence.iter().map(|k| k.unwrap()).collect(); + let captures = RE + .captures_iter(&key_string) + .next() + .ok_or("invalid_instruction")?; + let csi_index = captures[1].parse::(); + let first_field = captures[2].parse::(); + let second_field = captures[3].parse::(); + if csi_index.is_err() || first_field.is_err() || second_field.is_err() { + return Err("invalid_instruction"); + } + match csi_index { + Ok(4) => { + // text area size + Ok(AnsiStdinInstructionOrKeys::PixelDimensions( + PixelDimensions { + character_cell_size: None, + text_area_size: Some(SizeInPixels { + height: first_field.unwrap(), + width: second_field.unwrap(), + }), + }, + )) + } + Ok(6) => { + // character cell size + Ok(AnsiStdinInstructionOrKeys::PixelDimensions( + PixelDimensions { + character_cell_size: Some(SizeInPixels { + height: first_field.unwrap(), + width: second_field.unwrap(), + }), + text_area_size: None, + }, + )) + } + _ => Err("invalid sequence"), + } + } else { + Err("invalid sequence") + } + } + pub fn color_sequence_from_keys(keys: &Vec<(Key, Vec)>) -> Result { + lazy_static! { + static ref BACKGROUND_RE: Regex = Regex::new(r"11;(.*)$").unwrap(); + } + lazy_static! { + static ref FOREGROUND_RE: Regex = Regex::new(r"10;(.*)$").unwrap(); + } + let key_string = keys.iter().fold(String::new(), |mut acc, (key, _)| { + match key { + Key::Char(c) => acc.push(*c), + _ => {} + }; + acc + }); + if let Some(captures) = BACKGROUND_RE.captures_iter(&key_string).next() { + let background_query_response = captures[1].parse::(); + Ok(AnsiStdinInstructionOrKeys::BackgroundColor( + background_query_response.unwrap(), + )) + } else if let Some(captures) = FOREGROUND_RE.captures_iter(&key_string).next() { + let foreground_query_response = captures[1].parse::(); + Ok(AnsiStdinInstructionOrKeys::ForegroundColor( + foreground_query_response.unwrap(), + )) + } else { + Err("invalid_instruction") + } + } +} diff --git a/zellij-client/src/unit/input_handler_tests.rs b/zellij-client/src/unit/input_handler_tests.rs index a8b99713..4b830656 100644 --- a/zellij-client/src/unit/input_handler_tests.rs +++ b/zellij-client/src/unit/input_handler_tests.rs @@ -81,8 +81,8 @@ impl FakeStdoutWriter { } } impl io::Write for FakeStdoutWriter { - fn write(&mut self, mut buf: &[u8]) -> Result { - self.buffer.lock().unwrap().extend_from_slice(&mut buf); + fn write(&mut self, buf: &[u8]) -> Result { + self.buffer.lock().unwrap().extend_from_slice(buf); Ok(buf.len()) } fn flush(&mut self) -> Result<(), io::Error> { @@ -188,7 +188,7 @@ fn extract_pixel_events_sent_to_server( let events_sent_to_server = events_sent_to_server.lock().unwrap(); events_sent_to_server.iter().fold(vec![], |mut acc, event| { if let ClientToServerMsg::TerminalPixelDimensions(pixel_dimensions) = event { - acc.push(pixel_dimensions.clone()); + acc.push(*pixel_dimensions); } acc }) @@ -319,8 +319,7 @@ pub fn pixel_info_queried_from_terminal_emulator() { let events_sent_to_server = Arc::new(Mutex::new(vec![])); let command_is_executing = CommandIsExecuting::new(); - let client_os_api = - FakeClientOsApi::new(events_sent_to_server.clone(), command_is_executing.clone()); + let client_os_api = FakeClientOsApi::new(events_sent_to_server, command_is_executing.clone()); let config = Config::from_default_assets().unwrap(); let options = Options::default(); @@ -353,7 +352,9 @@ pub fn pixel_info_queried_from_terminal_emulator() { let extracted_stdout_buffer = client_os_api_clone.stdout_buffer(); assert_eq!( String::from_utf8(extracted_stdout_buffer), - Ok(String::from("\u{1b}[14t\u{1b}[16t")), + Ok(String::from( + "\u{1b}[14t\u{1b}[16t\u{1b}]11;?\u{1b}\\\u{1b}]10;?\u{1b}\\" + )), ); } @@ -465,8 +466,7 @@ pub fn pixel_info_sent_to_server() { receive_input_instructions, ); let actions_sent_to_server = extract_actions_sent_to_server(events_sent_to_server.clone()); - let pixel_events_sent_to_server = - extract_pixel_events_sent_to_server(events_sent_to_server.clone()); + let pixel_events_sent_to_server = extract_pixel_events_sent_to_server(events_sent_to_server); assert_eq!(actions_sent_to_server, vec![Action::Quit]); assert_eq!( pixel_events_sent_to_server, @@ -588,8 +588,7 @@ pub fn corrupted_pixel_info_sent_as_key_events() { receive_input_instructions, ); let actions_sent_to_server = extract_actions_sent_to_server(events_sent_to_server.clone()); - let pixel_events_sent_to_server = - extract_pixel_events_sent_to_server(events_sent_to_server.clone()); + let pixel_events_sent_to_server = extract_pixel_events_sent_to_server(events_sent_to_server); assert_eq!( actions_sent_to_server, vec![ @@ -716,8 +715,7 @@ pub fn esc_in_the_middle_of_pixelinfo_breaks_out_of_it() { receive_input_instructions, ); let actions_sent_to_server = extract_actions_sent_to_server(events_sent_to_server.clone()); - let pixel_events_sent_to_server = - extract_pixel_events_sent_to_server(events_sent_to_server.clone()); + let pixel_events_sent_to_server = extract_pixel_events_sent_to_server(events_sent_to_server); assert_eq!( actions_sent_to_server, vec![ diff --git a/zellij-server/src/panes/grid.rs b/zellij-server/src/panes/grid.rs index 4a569bb1..f34ad143 100644 --- a/zellij-server/src/panes/grid.rs +++ b/zellij-server/src/panes/grid.rs @@ -287,7 +287,7 @@ pub struct Grid { scroll_region: Option<(usize, usize)>, active_charset: CharsetIndex, preceding_char: Option, - colors: Palette, + terminal_emulator_colors: Rc>, output_buffer: OutputBuffer, title_stack: Vec, character_cell_size: Rc>>, @@ -328,7 +328,7 @@ impl Grid { pub fn new( rows: usize, columns: usize, - colors: Palette, + terminal_emulator_colors: Rc>, link_handler: Rc>, character_cell_size: Rc>>, ) -> Self { @@ -357,7 +357,7 @@ impl Grid { clear_viewport_before_rendering: false, active_charset: Default::default(), pending_messages_to_pty: vec![], - colors, + terminal_emulator_colors, output_buffer: Default::default(), selection: Default::default(), title_stack: vec![], @@ -1553,16 +1553,23 @@ impl Perform for Grid { self.link_handler.borrow_mut().dispatch_osc8(params); } - // Get/set Foreground, Background, Cursor colors. - b"10" | b"11" | b"12" => { + // Get/set Foreground (b"10") or background (b"11") colors + b"10" | b"11" => { if params.len() >= 2 { if let Some(mut dynamic_code) = parse_number(params[0]) { for param in ¶ms[1..] { // currently only getting the color sequence is supported, // setting still isn't if param == b"?" { - let color_response_message = match self.colors.bg { - PaletteColor::Rgb((r, g, b)) => { + let saved_terminal_color = if dynamic_code == 10 { + Some(self.terminal_emulator_colors.borrow().fg) + } else if dynamic_code == 11 { + Some(self.terminal_emulator_colors.borrow().bg) + } else { + None + }; + let color_response_message = match saved_terminal_color { + Some(PaletteColor::Rgb((r, g, b))) => { format!( "\u{1b}]{};rgb:{1:02x}{1:02x}/{2:02x}{2:02x}/{3:02x}{3:02x}{4}", // dynamic_code, color.r, color.g, color.b, terminator @@ -1586,6 +1593,10 @@ impl Perform for Grid { } } + b"12" => { + // get/set cursor color currently unimplemented + } + // Set cursor style. b"50" => { if params.len() >= 2 diff --git a/zellij-server/src/panes/mod.rs b/zellij-server/src/panes/mod.rs index b9e7d8d0..c1fb31d1 100644 --- a/zellij-server/src/panes/mod.rs +++ b/zellij-server/src/panes/mod.rs @@ -1,4 +1,4 @@ -mod alacritty_functions; +pub mod alacritty_functions; mod floating_panes; pub mod grid; pub mod link_handler; diff --git a/zellij-server/src/panes/terminal_pane.rs b/zellij-server/src/panes/terminal_pane.rs index 26b4ac30..2b68ea33 100644 --- a/zellij-server/src/panes/terminal_pane.rs +++ b/zellij-server/src/panes/terminal_pane.rs @@ -21,7 +21,7 @@ use zellij_utils::{ position::Position, shared::make_terminal_title, vte, - zellij_tile::data::{InputMode, PaletteColor}, + zellij_tile::data::{InputMode, Palette, PaletteColor}, }; pub const SELECTION_SCROLL_INTERVAL_MS: u64 = 10; @@ -489,12 +489,13 @@ impl TerminalPane { pane_name: String, link_handler: Rc>, character_cell_size: Rc>>, + terminal_emulator_colors: Rc>, ) -> 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(), - style.colors, + terminal_emulator_colors, link_handler, character_cell_size, ); diff --git a/zellij-server/src/panes/unit/grid_tests.rs b/zellij-server/src/panes/unit/grid_tests.rs index eac87284..42c4e329 100644 --- a/zellij-server/src/panes/unit/grid_tests.rs +++ b/zellij-server/src/panes/unit/grid_tests.rs @@ -21,7 +21,7 @@ fn vttest1_0() { let mut grid = Grid::new( 41, 110, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -39,7 +39,7 @@ fn vttest1_1() { let mut grid = Grid::new( 41, 110, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -57,7 +57,7 @@ fn vttest1_2() { let mut grid = Grid::new( 41, 110, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -75,7 +75,7 @@ fn vttest1_3() { let mut grid = Grid::new( 41, 110, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -93,7 +93,7 @@ fn vttest1_4() { let mut grid = Grid::new( 41, 110, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -111,7 +111,7 @@ fn vttest1_5() { let mut grid = Grid::new( 41, 110, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -129,7 +129,7 @@ fn vttest2_0() { let mut grid = Grid::new( 41, 110, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -147,7 +147,7 @@ fn vttest2_1() { let mut grid = Grid::new( 41, 110, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -165,7 +165,7 @@ fn vttest2_2() { let mut grid = Grid::new( 41, 110, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -183,7 +183,7 @@ fn vttest2_3() { let mut grid = Grid::new( 41, 110, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -201,7 +201,7 @@ fn vttest2_4() { let mut grid = Grid::new( 41, 110, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -219,7 +219,7 @@ fn vttest2_5() { let mut grid = Grid::new( 41, 110, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -237,7 +237,7 @@ fn vttest2_6() { let mut grid = Grid::new( 41, 110, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -255,7 +255,7 @@ fn vttest2_7() { let mut grid = Grid::new( 41, 110, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -273,7 +273,7 @@ fn vttest2_8() { let mut grid = Grid::new( 41, 110, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -291,7 +291,7 @@ fn vttest2_9() { let mut grid = Grid::new( 41, 110, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -309,7 +309,7 @@ fn vttest2_10() { let mut grid = Grid::new( 41, 110, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -327,7 +327,7 @@ fn vttest2_11() { let mut grid = Grid::new( 41, 110, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -345,7 +345,7 @@ fn vttest2_12() { let mut grid = Grid::new( 41, 110, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -363,7 +363,7 @@ fn vttest2_13() { let mut grid = Grid::new( 41, 110, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -381,7 +381,7 @@ fn vttest2_14() { let mut grid = Grid::new( 41, 110, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -399,7 +399,7 @@ fn vttest3_0() { let mut grid = Grid::new( 41, 110, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -417,7 +417,7 @@ fn vttest8_0() { let mut grid = Grid::new( 51, 97, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -435,7 +435,7 @@ fn vttest8_1() { let mut grid = Grid::new( 51, 97, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -453,7 +453,7 @@ fn vttest8_2() { let mut grid = Grid::new( 51, 97, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -471,7 +471,7 @@ fn vttest8_3() { let mut grid = Grid::new( 51, 97, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -489,7 +489,7 @@ fn vttest8_4() { let mut grid = Grid::new( 51, 97, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -507,7 +507,7 @@ fn vttest8_5() { let mut grid = Grid::new( 51, 97, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -525,7 +525,7 @@ fn csi_b() { let mut grid = Grid::new( 51, 97, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -543,7 +543,7 @@ fn csi_capital_i() { let mut grid = Grid::new( 51, 97, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -561,7 +561,7 @@ fn csi_capital_z() { let mut grid = Grid::new( 51, 97, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -579,7 +579,7 @@ fn terminal_reports() { let mut grid = Grid::new( 51, 97, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -597,7 +597,7 @@ fn wide_characters() { let mut grid = Grid::new( 21, 104, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -615,7 +615,7 @@ fn wide_characters_line_wrap() { let mut grid = Grid::new( 21, 104, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -633,7 +633,7 @@ fn insert_character_in_line_with_wide_character() { let mut grid = Grid::new( 21, 104, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -651,7 +651,7 @@ fn delete_char_in_middle_of_line_with_widechar() { let mut grid = Grid::new( 21, 104, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -669,7 +669,7 @@ fn delete_char_in_middle_of_line_with_multiple_widechars() { let mut grid = Grid::new( 21, 104, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -687,7 +687,7 @@ fn fish_wide_characters_override_clock() { let mut grid = Grid::new( 21, 104, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -705,7 +705,7 @@ fn bash_delete_wide_characters() { let mut grid = Grid::new( 21, 104, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -723,7 +723,7 @@ fn delete_wide_characters_before_cursor() { let mut grid = Grid::new( 21, 104, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -741,7 +741,7 @@ fn delete_wide_characters_before_cursor_when_cursor_is_on_wide_character() { let mut grid = Grid::new( 21, 104, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -759,7 +759,7 @@ fn delete_wide_character_under_cursor() { let mut grid = Grid::new( 21, 104, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -777,7 +777,7 @@ fn replace_wide_character_under_cursor() { let mut grid = Grid::new( 21, 104, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -795,7 +795,7 @@ fn wrap_wide_characters() { let mut grid = Grid::new( 21, 90, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -813,7 +813,7 @@ fn wrap_wide_characters_on_size_change() { let mut grid = Grid::new( 21, 93, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -832,7 +832,7 @@ fn unwrap_wide_characters_on_size_change() { let mut grid = Grid::new( 21, 93, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -852,7 +852,7 @@ fn wrap_wide_characters_in_the_middle_of_the_line() { let mut grid = Grid::new( 21, 91, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -870,7 +870,7 @@ fn wrap_wide_characters_at_the_end_of_the_line() { let mut grid = Grid::new( 21, 90, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -888,7 +888,7 @@ fn copy_selected_text_from_viewport() { let mut grid = Grid::new( 27, 125, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -914,7 +914,7 @@ fn copy_wrapped_selected_text_from_viewport() { let mut grid = Grid::new( 22, 73, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -939,7 +939,7 @@ fn copy_selected_text_from_lines_above() { let mut grid = Grid::new( 27, 125, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -965,7 +965,7 @@ fn copy_selected_text_from_lines_below() { let mut grid = Grid::new( 27, 125, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -999,7 +999,7 @@ fn run_bandwhich_from_fish_shell() { let mut grid = Grid::new( 28, 116, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -1017,7 +1017,7 @@ fn fish_tab_completion_options() { let mut grid = Grid::new( 28, 116, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -1040,7 +1040,7 @@ pub fn fish_select_tab_completion_options() { let mut grid = Grid::new( 28, 116, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -1066,7 +1066,7 @@ pub fn vim_scroll_region_down() { let mut grid = Grid::new( 28, 116, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -1090,7 +1090,7 @@ pub fn vim_ctrl_d() { let mut grid = Grid::new( 28, 116, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -1113,7 +1113,7 @@ pub fn vim_ctrl_u() { let mut grid = Grid::new( 28, 116, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -1131,7 +1131,7 @@ pub fn htop() { let mut grid = Grid::new( 28, 116, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -1149,7 +1149,7 @@ pub fn htop_scrolling() { let mut grid = Grid::new( 28, 116, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -1167,7 +1167,7 @@ pub fn htop_right_scrolling() { let mut grid = Grid::new( 28, 116, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -1193,7 +1193,7 @@ pub fn vim_overwrite() { let mut grid = Grid::new( 28, 116, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -1213,7 +1213,7 @@ pub fn clear_scroll_region() { let mut grid = Grid::new( 28, 116, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -1231,7 +1231,7 @@ pub fn display_tab_characters_properly() { let mut grid = Grid::new( 28, 116, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -1249,7 +1249,7 @@ pub fn neovim_insert_mode() { let mut grid = Grid::new( 28, 116, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -1267,7 +1267,7 @@ pub fn bash_cursor_linewrap() { let mut grid = Grid::new( 28, 116, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -1287,7 +1287,7 @@ pub fn fish_paste_multiline() { let mut grid = Grid::new( 28, 149, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -1305,7 +1305,7 @@ pub fn git_log() { let mut grid = Grid::new( 28, 149, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -1325,7 +1325,7 @@ pub fn git_diff_scrollup() { let mut grid = Grid::new( 28, 149, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -1343,7 +1343,7 @@ pub fn emacs_longbuf() { let mut grid = Grid::new( 60, 284, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -1361,7 +1361,7 @@ pub fn top_and_quit() { let mut grid = Grid::new( 56, 235, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -1385,7 +1385,7 @@ pub fn exa_plus_omf_theme() { let mut grid = Grid::new( 56, 235, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -1403,7 +1403,7 @@ pub fn scroll_up() { let mut grid = Grid::new( 10, 50, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -1422,7 +1422,7 @@ pub fn scroll_down() { let mut grid = Grid::new( 10, 50, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -1442,7 +1442,7 @@ pub fn scroll_up_with_line_wraps() { let mut grid = Grid::new( 10, 25, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -1461,7 +1461,7 @@ pub fn scroll_down_with_line_wraps() { let mut grid = Grid::new( 10, 25, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -1481,7 +1481,7 @@ pub fn scroll_up_decrease_width_and_scroll_down() { let mut grid = Grid::new( 10, 50, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -1506,7 +1506,7 @@ pub fn scroll_up_increase_width_and_scroll_down() { let mut grid = Grid::new( 10, 25, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -1531,7 +1531,7 @@ pub fn move_cursor_below_scroll_region() { let mut grid = Grid::new( 34, 114, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -1549,7 +1549,7 @@ pub fn insert_wide_characters_in_existing_line() { let mut grid = Grid::new( 21, 86, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -1572,7 +1572,7 @@ pub fn full_screen_scroll_region_and_scroll_up() { let mut grid = Grid::new( 54, 80, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -1593,7 +1593,7 @@ pub fn ring_bell() { let mut grid = Grid::new( 134, 64, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -1611,7 +1611,7 @@ pub fn alternate_screen_change_size() { let mut grid = Grid::new( 20, 20, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -1633,7 +1633,7 @@ pub fn fzf_fullscreen() { let mut grid = Grid::new( 51, 112, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -1655,7 +1655,7 @@ pub fn replace_multiple_wide_characters_under_cursor() { let mut grid = Grid::new( 51, 112, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -1677,7 +1677,7 @@ pub fn replace_non_wide_characters_with_wide_characters() { let mut grid = Grid::new( 51, 112, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -1695,7 +1695,7 @@ pub fn scroll_down_ansi() { let mut grid = Grid::new( 51, 112, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -1713,7 +1713,7 @@ pub fn ansi_capital_t() { let mut grid = Grid::new( 51, 112, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -1730,7 +1730,7 @@ pub fn ansi_capital_s() { let mut grid = Grid::new( 51, 112, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -1747,7 +1747,7 @@ fn terminal_pixel_size_reports() { let mut grid = Grid::new( 51, 97, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(Some(SizeInPixels { height: 21, @@ -1774,7 +1774,7 @@ fn terminal_pixel_size_reports_in_unsupported_terminals() { let mut grid = Grid::new( 51, 97, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), // in an unsupported terminal, we don't have this info ); @@ -1799,7 +1799,7 @@ pub fn ansi_csi_at_sign() { let mut grid = Grid::new( 51, 112, - Palette::default(), + Rc::new(RefCell::new(Palette::default())), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); diff --git a/zellij-server/src/panes/unit/terminal_pane_tests.rs b/zellij-server/src/panes/unit/terminal_pane_tests.rs index f03f170c..efb83db9 100644 --- a/zellij-server/src/panes/unit/terminal_pane_tests.rs +++ b/zellij-server/src/panes/unit/terminal_pane_tests.rs @@ -4,6 +4,7 @@ use crate::tab::Pane; use ::insta::assert_snapshot; use std::cell::RefCell; use std::rc::Rc; +use zellij_tile::data::Palette; use zellij_tile::prelude::Style; use zellij_utils::pane_size::PaneGeom; @@ -26,6 +27,7 @@ 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())), ); // 0 is the pane index let mut text_to_fill_pane = String::new(); for i in 0..30 { diff --git a/zellij-server/src/route.rs b/zellij-server/src/route.rs index af31523a..a6315447 100644 --- a/zellij-server/src/route.rs +++ b/zellij-server/src/route.rs @@ -449,6 +449,26 @@ pub(crate) fn route_thread_main( )) .unwrap(); } + ClientToServerMsg::BackgroundColor(background_color_instruction) => { + rlocked_sessions + .as_ref() + .unwrap() + .senders + .send_to_screen(ScreenInstruction::TerminalBackgroundColor( + background_color_instruction, + )) + .unwrap(); + } + ClientToServerMsg::ForegroundColor(foreground_color_instruction) => { + rlocked_sessions + .as_ref() + .unwrap() + .senders + .send_to_screen(ScreenInstruction::TerminalForegroundColor( + foreground_color_instruction, + )) + .unwrap(); + } ClientToServerMsg::NewClient( client_attributes, cli_args, diff --git a/zellij-server/src/screen.rs b/zellij-server/src/screen.rs index aa8b9c82..52b4af87 100644 --- a/zellij-server/src/screen.rs +++ b/zellij-server/src/screen.rs @@ -6,6 +6,7 @@ use std::os::unix::io::RawFd; use std::rc::Rc; use std::str; +use zellij_tile::data::{Palette, PaletteColor}; use zellij_tile::prelude::Style; use zellij_utils::input::options::Clipboard; use zellij_utils::pane_size::{Size, SizeInPixels}; @@ -13,6 +14,9 @@ use zellij_utils::{ input::command::TerminalAction, input::layout::Layout, position::Position, zellij_tile, }; +use crate::panes::alacritty_functions::xparse_color; +use crate::panes::terminal_character::AnsiCode; + use crate::{ output::Output, panes::PaneId, @@ -88,6 +92,8 @@ pub enum ScreenInstruction { UpdateTabName(Vec, ClientId), TerminalResize(Size), TerminalPixelDimensions(PixelDimensions), + TerminalBackgroundColor(String), + TerminalForegroundColor(String), ChangeMode(ModeInfo, ClientId), LeftClick(Position, ClientId), RightClick(Position, ClientId), @@ -166,6 +172,12 @@ impl From<&ScreenInstruction> for ScreenContext { ScreenInstruction::TerminalPixelDimensions(..) => { ScreenContext::TerminalPixelDimensions } + ScreenInstruction::TerminalBackgroundColor(..) => { + ScreenContext::TerminalBackgroundColor + } + ScreenInstruction::TerminalForegroundColor(..) => { + ScreenContext::TerminalForegroundColor + } ScreenInstruction::ChangeMode(..) => ScreenContext::ChangeMode, ScreenInstruction::ToggleActiveSyncTab(..) => ScreenContext::ToggleActiveSyncTab, ScreenInstruction::ScrollUpAt(..) => ScreenContext::ScrollUpAt, @@ -231,6 +243,7 @@ pub(crate) struct Screen { character_cell_size: Rc>>, /// The overlay that is drawn on top of [`Pane`]'s', [`Tab`]'s and the [`Screen`] overlay: OverlayWindow, + terminal_emulator_colors: Rc>, connected_clients: Rc>>, /// The indices of this [`Screen`]'s active [`Tab`]s. active_tab_indices: BTreeMap, @@ -265,6 +278,7 @@ impl Screen { active_tab_indices: BTreeMap::new(), tabs: BTreeMap::new(), overlay: OverlayWindow::default(), + terminal_emulator_colors: Rc::new(RefCell::new(Palette::default())), tab_history: BTreeMap::new(), mode_info: BTreeMap::new(), default_mode_info: mode_info, @@ -482,6 +496,22 @@ impl Screen { *self.character_cell_size.borrow_mut() = Some(character_cell_size); } } + pub fn update_terminal_background_color(&mut self, background_color_instruction: String) { + if let Some(AnsiCode::RgbCode((r, g, b))) = + xparse_color(background_color_instruction.as_bytes()) + { + let bg_palette_color = PaletteColor::Rgb((r, g, b)); + self.terminal_emulator_colors.borrow_mut().bg = bg_palette_color; + } + } + pub fn update_terminal_foreground_color(&mut self, foreground_color_instruction: String) { + if let Some(AnsiCode::RgbCode((r, g, b))) = + xparse_color(foreground_color_instruction.as_bytes()) + { + let fg_palette_color = PaletteColor::Rgb((r, g, b)); + self.terminal_emulator_colors.borrow_mut().fg = fg_palette_color; + } + } /// Renders this [`Screen`], which amounts to rendering its active [`Tab`]. pub fn render(&mut self) { @@ -573,6 +603,7 @@ impl Screen { self.session_is_mirrored, client_id, self.copy_options.clone(), + self.terminal_emulator_colors.clone(), ); tab.apply_layout(layout, new_pids, tab_index, client_id); if self.session_is_mirrored { @@ -1309,6 +1340,12 @@ pub(crate) fn screen_thread_main( ScreenInstruction::TerminalPixelDimensions(pixel_dimensions) => { screen.update_pixel_dimensions(pixel_dimensions); } + ScreenInstruction::TerminalBackgroundColor(background_color_instruction) => { + screen.update_terminal_background_color(background_color_instruction); + } + ScreenInstruction::TerminalForegroundColor(background_color_instruction) => { + screen.update_terminal_foreground_color(background_color_instruction); + } ScreenInstruction::ChangeMode(mode_info, client_id) => { screen.change_mode(mode_info, client_id); diff --git a/zellij-server/src/tab/mod.rs b/zellij-server/src/tab/mod.rs index 8a9fb0ea..a32964de 100644 --- a/zellij-server/src/tab/mod.rs +++ b/zellij-server/src/tab/mod.rs @@ -90,6 +90,7 @@ pub(crate) struct Tab { // it seems that optimization is possible using `active_panes` focus_pane_id: Option, copy_on_select: bool, + terminal_emulator_colors: Rc>, } #[derive(Clone, Debug, Default, Serialize, Deserialize)] @@ -283,6 +284,7 @@ impl Tab { session_is_mirrored: bool, client_id: ClientId, copy_options: CopyOptions, + terminal_emulator_colors: Rc>, ) -> Self { let name = if name.is_empty() { format!("Tab #{}", index + 1) @@ -352,6 +354,7 @@ impl Tab { clipboard_provider, focus_pane_id: None, copy_on_select: copy_options.copy_on_select, + terminal_emulator_colors, } } @@ -419,6 +422,7 @@ impl Tab { layout.pane_name.clone().unwrap_or_default(), self.link_handler.clone(), self.character_cell_size.clone(), + self.terminal_emulator_colors.clone(), ); new_pane.set_borderless(layout.borderless); self.tiled_panes @@ -647,6 +651,7 @@ impl Tab { String::new(), self.link_handler.clone(), self.character_cell_size.clone(), + self.terminal_emulator_colors.clone(), ); new_pane.set_content_offset(Offset::frame(1)); // floating panes always have a frame resize_pty!(new_pane, self.os_api); @@ -669,6 +674,7 @@ impl Tab { String::new(), self.link_handler.clone(), self.character_cell_size.clone(), + self.terminal_emulator_colors.clone(), ); self.tiled_panes.insert_pane(pid, Box::new(new_terminal)); self.should_clear_display_before_rendering = true; @@ -698,6 +704,7 @@ impl Tab { String::new(), self.link_handler.clone(), self.character_cell_size.clone(), + self.terminal_emulator_colors.clone(), ); self.tiled_panes .split_pane_horizontally(pid, Box::new(new_terminal), client_id); @@ -725,6 +732,7 @@ impl Tab { String::new(), self.link_handler.clone(), self.character_cell_size.clone(), + self.terminal_emulator_colors.clone(), ); self.tiled_panes .split_pane_vertically(pid, Box::new(new_terminal), client_id); diff --git a/zellij-server/src/tab/unit/tab_integration_tests.rs b/zellij-server/src/tab/unit/tab_integration_tests.rs index ba6fc8f2..c9f3fcf7 100644 --- a/zellij-server/src/tab/unit/tab_integration_tests.rs +++ b/zellij-server/src/tab/unit/tab_integration_tests.rs @@ -103,6 +103,7 @@ fn create_new_tab(size: Size) -> Tab { connected_clients.insert(client_id); let connected_clients = Rc::new(RefCell::new(connected_clients)); 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 mut tab = Tab::new( index, @@ -120,6 +121,7 @@ fn create_new_tab(size: Size) -> Tab { session_is_mirrored, client_id, copy_options, + terminal_emulator_colors, ); tab.apply_layout( LayoutTemplate::default().try_into().unwrap(), @@ -149,7 +151,7 @@ fn take_snapshot(ansi_instructions: &str, rows: usize, columns: usize, palette: let mut grid = Grid::new( rows, columns, - palette, + Rc::new(RefCell::new(palette)), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); @@ -170,7 +172,7 @@ fn take_snapshot_and_cursor_position( let mut grid = Grid::new( rows, columns, - palette, + Rc::new(RefCell::new(palette)), Rc::new(RefCell::new(LinkHandler::new())), Rc::new(RefCell::new(None)), ); diff --git a/zellij-server/src/tab/unit/tab_tests.rs b/zellij-server/src/tab/unit/tab_tests.rs index 62dfdc01..c68d77bf 100644 --- a/zellij-server/src/tab/unit/tab_tests.rs +++ b/zellij-server/src/tab/unit/tab_tests.rs @@ -99,6 +99,7 @@ fn create_new_tab(size: Size) -> Tab { let character_cell_info = Rc::new(RefCell::new(None)); connected_clients.insert(client_id); 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 mut tab = Tab::new( index, @@ -116,6 +117,7 @@ fn create_new_tab(size: Size) -> Tab { session_is_mirrored, client_id, copy_options, + terminal_emulator_colors, ); tab.apply_layout( LayoutTemplate::default().try_into().unwrap(), @@ -144,6 +146,7 @@ fn create_new_tab_with_cell_size( let mut connected_clients = HashSet::new(); connected_clients.insert(client_id); 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 mut tab = Tab::new( index, @@ -161,6 +164,7 @@ fn create_new_tab_with_cell_size( session_is_mirrored, client_id, copy_options, + terminal_emulator_colors, ); tab.apply_layout( LayoutTemplate::default().try_into().unwrap(), diff --git a/zellij-utils/src/errors.rs b/zellij-utils/src/errors.rs index 4dca51fd..396fc9c5 100644 --- a/zellij-utils/src/errors.rs +++ b/zellij-utils/src/errors.rs @@ -268,6 +268,8 @@ pub enum ScreenContext { UpdateTabName, TerminalResize, TerminalPixelDimensions, + TerminalBackgroundColor, + TerminalForegroundColor, ChangeMode, LeftClick, RightClick, diff --git a/zellij-utils/src/ipc.rs b/zellij-utils/src/ipc.rs index 8a3dafd3..4d76c088 100644 --- a/zellij-utils/src/ipc.rs +++ b/zellij-utils/src/ipc.rs @@ -75,6 +75,8 @@ pub enum ClientToServerMsg { // Disconnect from the session we're connected to DisconnectFromSession,*/ TerminalPixelDimensions(PixelDimensions), + BackgroundColor(String), + ForegroundColor(String), TerminalResize(Size), NewClient( ClientAttributes,