summaryrefslogtreecommitdiffstats
path: root/zellij-server/src/screen.rs
diff options
context:
space:
mode:
Diffstat (limited to 'zellij-server/src/screen.rs')
-rw-r--r--zellij-server/src/screen.rs100
1 files changed, 100 insertions, 0 deletions
diff --git a/zellij-server/src/screen.rs b/zellij-server/src/screen.rs
index 2e351cff4..4594fe3cb 100644
--- a/zellij-server/src/screen.rs
+++ b/zellij-server/src/screen.rs
@@ -7,6 +7,7 @@ use std::rc::Rc;
use std::str;
use std::time::Duration;
+use log::{debug, warn};
use zellij_utils::data::{
Direction, PaneManifest, PluginPermission, Resize, ResizeStrategy, SessionInfo,
};
@@ -238,6 +239,8 @@ pub enum ScreenInstruction {
ToggleTab(ClientId),
UpdateTabName(Vec<u8>, ClientId),
UndoRenameTab(ClientId),
+ MoveTabLeft(ClientId),
+ MoveTabRight(ClientId),
TerminalResize(Size),
TerminalPixelDimensions(PixelDimensions),
TerminalBackgroundColor(String),
@@ -447,6 +450,8 @@ impl From<&ScreenInstruction> for ScreenContext {
ScreenInstruction::GoToTabName(..) => ScreenContext::GoToTabName,
ScreenInstruction::UpdateTabName(..) => ScreenContext::UpdateTabName,
ScreenInstruction::UndoRenameTab(..) => ScreenContext::UndoRenameTab,
+ ScreenInstruction::MoveTabLeft(..) => ScreenContext::MoveTabLeft,
+ ScreenInstruction::MoveTabRight(..) => ScreenContext::MoveTabRight,
ScreenInstruction::TerminalResize(..) => ScreenContext::TerminalResize,
ScreenInstruction::TerminalPixelDimensions(..) => {
ScreenContext::TerminalPixelDimensions
@@ -1585,6 +1590,91 @@ impl Screen {
}
}
+ pub fn move_active_tab_to_left(&mut self, client_id: ClientId) -> Result<()> {
+ if self.tabs.len() < 2 {
+ debug!("cannot move tab to left: only one tab exists");
+ return Ok(());
+ }
+ let Some(client_id) = self.client_id(client_id) else {
+ return Ok(());
+ };
+ let Some(&active_tab_idx) = self.active_tab_indices.get(&client_id) else {
+ return Ok(());
+ };
+
+ // wraps around: [tab1, tab2, tab3] => [tab1, tab2, tab3]
+ // ^ ^
+ // active_tab_idx left_tab_idx
+ let left_tab_idx = (active_tab_idx + self.tabs.len() - 1) % self.tabs.len();
+
+ self.switch_tabs(active_tab_idx, left_tab_idx, client_id);
+ self.log_and_report_session_state()
+ .context("failed to move tab to left")?;
+ Ok(())
+ }
+
+ fn client_id(&mut self, client_id: ClientId) -> Option<u16> {
+ if self.get_active_tab(client_id).is_ok() {
+ Some(client_id)
+ } else {
+ self.get_first_client_id()
+ }
+ }
+
+ fn switch_tabs(&mut self, active_tab_idx: usize, other_tab_idx: usize, client_id: u16) {
+ if !self.tabs.contains_key(&active_tab_idx) || !self.tabs.contains_key(&other_tab_idx) {
+ warn!(
+ "failed to switch tabs: index {} or {} not found in {:?}",
+ active_tab_idx,
+ other_tab_idx,
+ self.tabs.keys()
+ );
+ return;
+ }
+
+ // NOTE: Can `expect` here, because we checked that the keys exist above
+ let mut active_tab = self
+ .tabs
+ .remove(&active_tab_idx)
+ .expect("active tab not found");
+ let mut other_tab = self
+ .tabs
+ .remove(&other_tab_idx)
+ .expect("other tab not found");
+
+ std::mem::swap(&mut active_tab.index, &mut other_tab.index);
+ std::mem::swap(&mut active_tab.position, &mut other_tab.position);
+
+ // now, `active_tab.index` is changed, so we need to update it
+ self.active_tab_indices.insert(client_id, active_tab.index);
+
+ self.tabs.insert(active_tab.index, active_tab);
+ self.tabs.insert(other_tab.index, other_tab);
+ }
+
+ pub fn move_active_tab_to_right(&mut self, client_id: ClientId) -> Result<()> {
+ if self.tabs.len() < 2 {
+ debug!("cannot move tab to right: only one tab exists");
+ return Ok(());
+ }
+ let Some(client_id) = self.client_id(client_id) else {
+ return Ok(());
+ };
+ let Some(&active_tab_idx) = self.active_tab_indices.get(&client_id) else {
+ return Ok(());
+ };
+
+ // wraps around: [tab1, tab2, tab3] => [tab1, tab2, tab3]
+ // ^ ^
+ // active_tab_idx right_tab_idx
+ let right_tab_idx = (active_tab_idx + 1) % self.tabs.len();
+
+ self.switch_tabs(active_tab_idx, right_tab_idx, client_id);
+ self.log_and_report_session_state()
+ .context("failed to move active tab to right")?;
+ Ok(())
+ }
+
pub fn change_mode(&mut self, mut mode_info: ModeInfo, client_id: ClientId) -> Result<()> {
if mode_info.session_name.as_ref() != Some(&self.session_name) {
mode_info.session_name = Some(self.session_name.clone());
@@ -2989,6 +3079,16 @@ pub(crate) fn screen_thread_main(
screen.unblock_input()?;
screen.render(None)?;
},
+ ScreenInstruction::MoveTabLeft(client_id) => {
+ screen.move_active_tab_to_left(client_id)?;
+ screen.unblock_input()?;
+ screen.render(None)?;
+ },
+ ScreenInstruction::MoveTabRight(client_id) => {
+ screen.move_active_tab_to_right(client_id)?;
+ screen.unblock_input()?;
+ screen.render(None)?;
+ },
ScreenInstruction::TerminalResize(new_size) => {
screen.resize_to_screen(new_size)?;
screen.log_and_report_session_state()?; // update tabs so that the ui indication will be send to the plugins