diff --git a/zellij-server/src/panes/unit/terminal_pane_tests.rs b/zellij-server/src/panes/unit/terminal_pane_tests.rs index 2e29ca34..e5b17081 100644 --- a/zellij-server/src/panes/unit/terminal_pane_tests.rs +++ b/zellij-server/src/panes/unit/terminal_pane_tests.rs @@ -8,7 +8,8 @@ use std::collections::HashMap; use std::rc::Rc; use zellij_utils::{ data::{Palette, Style}, - pane_size::{PaneGeom, SizeInPixels}, + pane_size::{Offset, PaneGeom, SizeInPixels}, + position::Position, }; use std::fmt::Write; @@ -391,3 +392,255 @@ pub fn keep_working_after_corrupted_sixel_image() { terminal_pane.handle_pty_bytes(text_to_fill_pane.into_bytes()); assert_snapshot!(format!("{:?}", terminal_pane.grid)); } + +#[test] +pub fn pane_with_frame_position_is_on_frame() { + let mut fake_win_size = PaneGeom { + x: 10, + y: 10, + ..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 + + terminal_pane.set_content_offset(Offset::frame(1)); + + // row above pane: no border + assert!(!terminal_pane.position_is_on_frame(&Position::new(9, 9))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(9, 10))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(9, 11))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(9, 70))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(9, 129))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(9, 130))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(9, 131))); + + // first row: border for 10 <= col <= 130 + assert!(!terminal_pane.position_is_on_frame(&Position::new(10, 9))); + assert!(terminal_pane.position_is_on_frame(&Position::new(10, 10))); + assert!(terminal_pane.position_is_on_frame(&Position::new(10, 11))); + assert!(terminal_pane.position_is_on_frame(&Position::new(10, 70))); + assert!(terminal_pane.position_is_on_frame(&Position::new(10, 129))); + assert!(terminal_pane.position_is_on_frame(&Position::new(10, 130))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(10, 131))); + + // second row: border only at col=10,130 + assert!(!terminal_pane.position_is_on_frame(&Position::new(11, 9))); + assert!(terminal_pane.position_is_on_frame(&Position::new(11, 10))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(11, 11))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(11, 70))); + assert!(terminal_pane.position_is_on_frame(&Position::new(11, 130))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(11, 131))); + + // row in the middle: border only at col=10,130 + assert!(!terminal_pane.position_is_on_frame(&Position::new(15, 9))); + assert!(terminal_pane.position_is_on_frame(&Position::new(15, 10))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(15, 11))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(15, 70))); + assert!(terminal_pane.position_is_on_frame(&Position::new(15, 130))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(15, 131))); + + // last row: border for 10 <= col <= 130 + assert!(!terminal_pane.position_is_on_frame(&Position::new(29, 9))); + assert!(terminal_pane.position_is_on_frame(&Position::new(29, 10))); + assert!(terminal_pane.position_is_on_frame(&Position::new(29, 11))); + assert!(terminal_pane.position_is_on_frame(&Position::new(29, 70))); + assert!(terminal_pane.position_is_on_frame(&Position::new(29, 130))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(29, 131))); + + // row below pane: no border + assert!(!terminal_pane.position_is_on_frame(&Position::new(30, 10))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(30, 11))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(30, 70))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(30, 130))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(30, 131))); +} + +#[test] +pub fn pane_with_bottom_and_right_borders_position_is_on_frame() { + let mut fake_win_size = PaneGeom { + x: 10, + y: 10, + ..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 + + terminal_pane.set_content_offset(Offset::shift(1, 1)); + + // row above pane: no border + assert!(!terminal_pane.position_is_on_frame(&Position::new(9, 9))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(9, 10))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(9, 11))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(9, 70))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(9, 129))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(9, 130))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(9, 131))); + + // first row: border only at col=130 + assert!(!terminal_pane.position_is_on_frame(&Position::new(10, 9))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(10, 10))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(10, 11))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(10, 70))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(10, 129))); + assert!(terminal_pane.position_is_on_frame(&Position::new(10, 130))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(10, 131))); + + // second row: border only at col=130 + assert!(!terminal_pane.position_is_on_frame(&Position::new(11, 9))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(11, 10))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(11, 11))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(11, 70))); + assert!(terminal_pane.position_is_on_frame(&Position::new(11, 130))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(11, 131))); + + // row in the middle: border only at col=130 + assert!(!terminal_pane.position_is_on_frame(&Position::new(15, 9))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(15, 10))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(15, 11))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(15, 70))); + assert!(terminal_pane.position_is_on_frame(&Position::new(15, 130))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(15, 131))); + + // last row: border for 10 <= col <= 130 + assert!(!terminal_pane.position_is_on_frame(&Position::new(29, 9))); + assert!(terminal_pane.position_is_on_frame(&Position::new(29, 10))); + assert!(terminal_pane.position_is_on_frame(&Position::new(29, 11))); + assert!(terminal_pane.position_is_on_frame(&Position::new(29, 70))); + assert!(terminal_pane.position_is_on_frame(&Position::new(29, 130))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(29, 131))); + + // row below pane: no border + assert!(!terminal_pane.position_is_on_frame(&Position::new(30, 10))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(30, 11))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(30, 70))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(30, 130))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(30, 131))); +} + +#[test] +pub fn frameless_pane_position_is_on_frame() { + let mut fake_win_size = PaneGeom { + x: 10, + y: 10, + ..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 + + terminal_pane.set_content_offset(Offset::default()); + + // row above pane: no border + assert!(!terminal_pane.position_is_on_frame(&Position::new(9, 9))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(9, 10))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(9, 11))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(9, 70))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(9, 129))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(9, 130))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(9, 131))); + + // first row: no border + assert!(!terminal_pane.position_is_on_frame(&Position::new(10, 9))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(10, 10))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(10, 11))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(10, 70))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(10, 129))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(10, 130))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(10, 131))); + + // second row: no border + assert!(!terminal_pane.position_is_on_frame(&Position::new(11, 9))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(11, 10))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(11, 11))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(11, 70))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(11, 130))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(11, 131))); + + // random row in the middle: no border + assert!(!terminal_pane.position_is_on_frame(&Position::new(15, 9))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(15, 10))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(15, 11))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(15, 70))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(15, 130))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(15, 131))); + + // last row: no border + assert!(!terminal_pane.position_is_on_frame(&Position::new(29, 9))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(29, 10))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(29, 11))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(29, 70))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(29, 130))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(29, 131))); + + // row below pane: no border + assert!(!terminal_pane.position_is_on_frame(&Position::new(30, 10))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(30, 11))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(30, 70))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(30, 130))); + assert!(!terminal_pane.position_is_on_frame(&Position::new(30, 131))); +} diff --git a/zellij-server/src/tab/mod.rs b/zellij-server/src/tab/mod.rs index 6c5c2c6b..2c4aa5ed 100644 --- a/zellij-server/src/tab/mod.rs +++ b/zellij-server/src/tab/mod.rs @@ -262,13 +262,32 @@ pub trait Pane { fn relative_position(&self, position_on_screen: &Position) -> Position { position_on_screen.relative_to(self.get_content_y(), self.get_content_x()) } - fn position_is_on_frame(&self, position_on_screen: &Position) -> bool { - // TODO: handle cases where we have no frame - position_on_screen.line() == self.y() as isize - || position_on_screen.line() - == (self.y() as isize + self.rows() as isize).saturating_sub(1) - || position_on_screen.column() == self.x() - || position_on_screen.column() == (self.x() + self.cols()).saturating_sub(1) + fn position_is_on_frame(&self, position: &Position) -> bool { + if !self.contains(position) { + return false; + } + if (self.x()..self.get_content_x()).contains(&position.column()) { + // position is on left border + return true; + } + if (self.get_content_x() + self.get_content_columns()..(self.x() + self.cols())) + .contains(&position.column()) + { + // position is on right border + return true; + } + if (self.y() as isize..self.get_content_y() as isize).contains(&position.line()) { + // position is on top border + return true; + } + if ((self.get_content_y() + self.get_content_rows()) as isize + ..(self.y() + self.rows()) as isize) + .contains(&position.line()) + { + // position is on bottom border + return true; + } + false } fn store_pane_name(&mut self); fn load_pane_name(&mut self); @@ -1709,12 +1728,14 @@ impl Tab { let relative_position = pane.relative_position(position); if pane.mouse_mode() { - let mouse_event = format!( - "\u{1b}[<0;{:?};{:?}M", - relative_position.column.0 + 1, - relative_position.line.0 + 1 - ); - self.write_to_active_terminal(mouse_event.into_bytes(), client_id); + if !pane.position_is_on_frame(position) { + let mouse_event = format!( + "\u{1b}[<0;{:?};{:?}M", + relative_position.column() + 1, + relative_position.line() + 1 + ); + self.write_to_active_terminal(mouse_event.into_bytes(), client_id); + } } else { // TODO: rename this method, it is used to forward click events to plugin panes pane.start_selection(&relative_position, client_id); @@ -1730,12 +1751,14 @@ impl Tab { if let Some(pane) = self.get_pane_at(position, false) { let relative_position = pane.relative_position(position); if pane.mouse_mode() { - let mouse_event = format!( - "\u{1b}[<2;{:?};{:?}M", - relative_position.column.0 + 1, - relative_position.line.0 + 1 - ); - self.write_to_active_terminal(mouse_event.into_bytes(), client_id); + if !pane.position_is_on_frame(position) { + let mouse_event = format!( + "\u{1b}[<2;{:?};{:?}M", + relative_position.column() + 1, + relative_position.line() + 1 + ); + self.write_to_active_terminal(mouse_event.into_bytes(), client_id); + } } else { pane.handle_right_click(&relative_position, client_id); } @@ -1777,11 +1800,11 @@ impl Tab { let relative_position = active_pane.relative_position(position); if active_pane.mouse_mode() { // ensure that coordinates are valid - let col = (relative_position.column.0 + 1) + let col = (relative_position.column() + 1) .max(1) .min(active_pane.get_content_columns()); - let line = (relative_position.line.0 + 1) + let line = (relative_position.line() + 1) .max(1) .min(active_pane.get_content_rows() as isize); let mouse_event = format!("\u{1b}[<0;{:?};{:?}m", col, line); @@ -1840,11 +1863,11 @@ impl Tab { let relative_position = active_pane.relative_position(position_on_screen); if active_pane.mouse_mode() && !is_repeated { // ensure that coordinates are valid - let col = (relative_position.column.0 + 1) + let col = (relative_position.column() + 1) .max(1) .min(active_pane.get_content_columns()); - let line = (relative_position.line.0 + 1) + let line = (relative_position.line() + 1) .max(1) .min(active_pane.get_content_rows() as isize);