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.rs162
1 files changed, 128 insertions, 34 deletions
diff --git a/zellij-server/src/screen.rs b/zellij-server/src/screen.rs
index 39431ea7f..b5e5ee2b2 100644
--- a/zellij-server/src/screen.rs
+++ b/zellij-server/src/screen.rs
@@ -164,6 +164,7 @@ pub enum ScreenInstruction {
ScrollDown(ClientId),
ScrollDownAt(Position, ClientId),
ScrollToBottom(ClientId),
+ ScrollToTop(ClientId),
PageScrollUp(ClientId),
PageScrollDown(ClientId),
HalfPageScrollUp(ClientId),
@@ -199,6 +200,12 @@ pub enum ScreenInstruction {
ToggleActiveSyncTab(ClientId),
CloseTab(ClientId),
GoToTab(u32, Option<ClientId>), // this Option is a hacky workaround, please do not copy this behaviour
+ GoToTabName(
+ String,
+ (Vec<SwapTiledLayout>, Vec<SwapFloatingLayout>), // swap layouts
+ bool,
+ Option<ClientId>
+ ),
ToggleTab(ClientId),
UpdateTabName(Vec<u8>, ClientId),
UndoRenameTab(ClientId),
@@ -301,6 +308,7 @@ impl From<&ScreenInstruction> for ScreenContext {
ScreenInstruction::ScrollUp(..) => ScreenContext::ScrollUp,
ScreenInstruction::ScrollDown(..) => ScreenContext::ScrollDown,
ScreenInstruction::ScrollToBottom(..) => ScreenContext::ScrollToBottom,
+ ScreenInstruction::ScrollToTop(..) => ScreenContext::ScrollToTop,
ScreenInstruction::PageScrollUp(..) => ScreenContext::PageScrollUp,
ScreenInstruction::PageScrollDown(..) => ScreenContext::PageScrollDown,
ScreenInstruction::HalfPageScrollUp(..) => ScreenContext::HalfPageScrollUp,
@@ -322,6 +330,7 @@ impl From<&ScreenInstruction> for ScreenContext {
ScreenInstruction::SwitchTabPrev(..) => ScreenContext::SwitchTabPrev,
ScreenInstruction::CloseTab(..) => ScreenContext::CloseTab,
ScreenInstruction::GoToTab(..) => ScreenContext::GoToTab,
+ ScreenInstruction::GoToTabName(..) => ScreenContext::GoToTabName,
ScreenInstruction::UpdateTabName(..) => ScreenContext::UpdateTabName,
ScreenInstruction::UndoRenameTab(..) => ScreenContext::UndoRenameTab,
ScreenInstruction::TerminalResize(..) => ScreenContext::TerminalResize,
@@ -633,6 +642,18 @@ impl Screen {
Ok(())
}
+ /// A helper function to switch to a new tab with specified name. Return true if tab [name] has
+ /// been created, else false.
+ fn switch_active_tab_name(&mut self, name: String, client_id: ClientId) -> Result<bool> {
+ match self.tabs.values().find(|t| t.name == name) {
+ Some(new_tab) => {
+ self.switch_active_tab(new_tab.position, client_id)?;
+ Ok(true)
+ },
+ None => Ok(false),
+ }
+ }
+
/// Sets this [`Screen`]'s active [`Tab`] to the next tab.
pub fn switch_tab_next(&mut self, client_id: ClientId) -> Result<()> {
let err_context = || format!("failed to switch to next tab for client {client_id}");
@@ -688,6 +709,10 @@ impl Screen {
self.switch_active_tab(tab_index.saturating_sub(1), client_id)
}
+ pub fn go_to_tab_name(&mut self, name: String, client_id: ClientId) -> Result<bool> {
+ self.switch_active_tab_name(name, client_id)
+ }
+
fn close_tab_at_index(&mut self, tab_index: usize) -> Result<()> {
let err_context = || format!("failed to close tab at index {tab_index:?}");
@@ -750,13 +775,15 @@ impl Screen {
}
pub fn resize_to_screen(&mut self, new_screen_size: Size) -> Result<()> {
+ let err_context = || format!("failed to resize to screen size: {new_screen_size:#?}");
+
self.size = new_screen_size;
for tab in self.tabs.values_mut() {
- tab.resize_whole_tab(new_screen_size);
+ tab.resize_whole_tab(new_screen_size)
+ .with_context(err_context)?;
tab.set_force_render();
}
- self.render()
- .with_context(|| format!("failed to resize to screen size: {new_screen_size:#?}"))
+ self.render().with_context(err_context)
}
pub fn update_pixel_dimensions(&mut self, pixel_dimensions: PixelDimensions) {
@@ -989,29 +1016,35 @@ impl Screen {
};
// apply the layout to the new tab
- let tab = self.tabs.get_mut(&tab_index).unwrap(); // TODO: no unwrap
- tab.apply_layout(
- layout,
- floating_panes_layout,
- new_terminal_ids,
- new_floating_terminal_ids,
- new_plugin_ids,
- client_id,
- )
- .with_context(err_context)?;
- tab.update_input_modes().with_context(err_context)?;
- tab.visible(true).with_context(err_context)?;
- if let Some(drained_clients) = drained_clients {
- tab.add_multiple_clients(drained_clients)
- .with_context(err_context)?;
- }
+ self.tabs
+ .get_mut(&tab_index)
+ .context("couldn't find tab with index {tab_index}")
+ .and_then(|tab| {
+ tab.apply_layout(
+ layout,
+ floating_panes_layout,
+ new_terminal_ids,
+ new_floating_terminal_ids,
+ new_plugin_ids,
+ client_id,
+ )?;
+ tab.update_input_modes()?;
+ tab.visible(true)?;
+ if let Some(drained_clients) = drained_clients {
+ tab.add_multiple_clients(drained_clients)?;
+ }
+ Ok(())
+ })
+ .with_context(err_context)?;
+
if !self.active_tab_indices.contains_key(&client_id) {
// this means this is a new client and we need to add it to our state properly
self.add_client(client_id).with_context(err_context)?;
}
- self.update_tabs().with_context(err_context)?;
- self.render().with_context(err_context)
+ self.update_tabs()
+ .and_then(|_| self.render())
+ .with_context(err_context)
}
pub fn add_client(&mut self, client_id: ClientId) -> Result<()> {
@@ -1132,7 +1165,7 @@ impl Screen {
},
c => {
// It only allows printable unicode
- if buf.iter().all(|u| matches!(u, 0x20..=0x7E)) {
+ if buf.iter().all(|u| matches!(u, 0x20..=0x7E | 0xA0..=0xFF)) {
active_tab.name.push_str(c);
}
},
@@ -1265,10 +1298,17 @@ impl Screen {
if let Some(client_id) = client_id {
match self.get_active_tab_mut(client_id) {
Ok(active_tab) => {
- if !active_tab.move_focus_left(client_id) {
- self.switch_tab_prev(client_id)
- .context("failed to move focus left")?;
- }
+ active_tab
+ .move_focus_left(client_id)
+ .and_then(|success| {
+ if !success {
+ self.switch_tab_prev(client_id)
+ .context("failed to move focus to previous tab")
+ } else {
+ Ok(())
+ }
+ })
+ .with_context(err_context)?;
},
Err(err) => Err::<(), _>(err).with_context(err_context).non_fatal(),
};
@@ -1292,10 +1332,17 @@ impl Screen {
if let Some(client_id) = client_id {
match self.get_active_tab_mut(client_id) {
Ok(active_tab) => {
- if !active_tab.move_focus_right(client_id) {
- self.switch_tab_next(client_id)
- .context("failed to move focus right")?;
- }
+ active_tab
+ .move_focus_right(client_id)
+ .and_then(|success| {
+ if !success {
+ self.switch_tab_next(client_id)
+ .context("failed to move focus to next tab")
+ } else {
+ Ok(())
+ }
+ })
+ .with_context(err_context)?;
},
Err(err) => Err::<(), _>(err).with_context(err_context).non_fatal(),
};
@@ -1585,7 +1632,8 @@ pub(crate) fn screen_thread_main(
active_tab_and_connected_client_id!(
screen,
client_id,
- |tab: &mut Tab, client_id: ClientId| tab.move_focus_left(client_id)
+ |tab: &mut Tab, client_id: ClientId| tab.move_focus_left(client_id),
+ ?
);
screen.render()?;
screen.unblock_input()?;
@@ -1599,7 +1647,8 @@ pub(crate) fn screen_thread_main(
active_tab_and_connected_client_id!(
screen,
client_id,
- |tab: &mut Tab, client_id: ClientId| tab.move_focus_down(client_id)
+ |tab: &mut Tab, client_id: ClientId| tab.move_focus_down(client_id),
+ ?
);
screen.render()?;
screen.unblock_input()?;
@@ -1608,7 +1657,8 @@ pub(crate) fn screen_thread_main(
active_tab_and_connected_client_id!(
screen,
client_id,
- |tab: &mut Tab, client_id: ClientId| tab.move_focus_right(client_id)
+ |tab: &mut Tab, client_id: ClientId| tab.move_focus_right(client_id),
+ ?
);
screen.render()?;
screen.unblock_input()?;
@@ -1622,7 +1672,8 @@ pub(crate) fn screen_thread_main(
active_tab_and_connected_client_id!(
screen,
client_id,
- |tab: &mut Tab, client_id: ClientId| tab.move_focus_up(client_id)
+ |tab: &mut Tab, client_id: ClientId| tab.move_focus_up(client_id),
+ ?
);
screen.render()?;
screen.unblock_input()?;
@@ -1758,6 +1809,16 @@ pub(crate) fn screen_thread_main(
screen.render()?;
screen.unblock_input()?;
},
+ ScreenInstruction::ScrollToTop(client_id) => {
+ active_tab_and_connected_client_id!(
+ screen,
+ client_id,
+ |tab: &mut Tab, client_id: ClientId| tab
+ .scroll_active_terminal_to_top(client_id), ?
+ );
+ screen.render()?;
+ screen.unblock_input()?;
+ },
ScreenInstruction::PageScrollUp(client_id) => {
active_tab_and_connected_client_id!(
screen,
@@ -1988,6 +2049,39 @@ pub(crate) fn screen_thread_main(
screen.render()?;
}
},
+ ScreenInstruction::GoToTabName(tab_name, swap_layouts, create, client_id) => {
+ let client_id = if client_id.is_none() {
+ None
+ } else if screen
+ .active_tab_indices
+ .contains_key(&client_id.expect("This is checked above"))
+ {
+ client_id
+ } else {
+ screen.active_tab_indices.keys().next().copied()
+ };
+ if let Some(client_id) = client_id {
+ if let Ok(tab_exists) = screen.go_to_tab_name(tab_name.clone(), client_id) {
+ screen.unblock_input()?;
+ screen.render()?;
+ if create && !tab_exists {
+ let tab_index = screen.get_new_tab_index();
+ screen.new_tab(tab_index, swap_layouts, client_id)?;
+ screen
+ .bus
+ .senders
+ .send_to_plugin(PluginInstruction::NewTab(
+ None,
+ None,
+ vec![],
+ Some(tab_name),
+ tab_index,
+ client_id,
+ ))?;
+ }
+ }
+ }
+ },
ScreenInstruction::UpdateTabName(c, client_id) => {
screen.update_active_tab_name(c, client_id)?;
screen.unblock_input()?;