summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
author哇呜哇呜呀咦耶 <pingao777@gmail.com>2023-02-07 22:45:59 +0800
committerGitHub <noreply@github.com>2023-02-07 15:45:59 +0100
commit99e8d56adb50b1b2921d4af01972c4b9fd8b6105 (patch)
tree4dc9da5729cd083c5ff1219aa1b4ec3b3573db15
parent601eee8bb3e1d57d8a5df2b04d15506bc2aa92eb (diff)
feat(cli): add `GoToTabName` action to switch tab by name (#2120)
* Add `GoToTabName` action to switch tab by name * rm blank file * add --create option * format * add some doc * add test case * format * add test case * change variable name
-rw-r--r--zellij-client/src/input_handler.rs1
-rw-r--r--zellij-server/src/route.rs10
-rw-r--r--zellij-server/src/screen.rs51
-rw-r--r--zellij-server/src/unit/screen_tests.rs34
-rw-r--r--zellij-utils/src/cli.rs7
-rw-r--r--zellij-utils/src/errors.rs1
-rw-r--r--zellij-utils/src/input/actions.rs2
7 files changed, 106 insertions, 0 deletions
diff --git a/zellij-client/src/input_handler.rs b/zellij-client/src/input_handler.rs
index eb711fa3a..e764786c4 100644
--- a/zellij-client/src/input_handler.rs
+++ b/zellij-client/src/input_handler.rs
@@ -307,6 +307,7 @@ impl InputHandler {
| Action::GoToPreviousTab
| Action::CloseTab
| Action::GoToTab(_)
+ | Action::GoToTabName(_, _)
| Action::ToggleTab
| Action::MoveFocusOrTab(_) => {
self.command_is_executing.blocking_input_thread();
diff --git a/zellij-server/src/route.rs b/zellij-server/src/route.rs
index 2ca58cc44..dce1c9ac0 100644
--- a/zellij-server/src/route.rs
+++ b/zellij-server/src/route.rs
@@ -479,6 +479,16 @@ pub(crate) fn route_action(
.send_to_screen(ScreenInstruction::GoToTab(i, Some(client_id)))
.with_context(err_context)?;
},
+ Action::GoToTabName(name, create) => {
+ session
+ .senders
+ .send_to_screen(ScreenInstruction::GoToTabName(
+ name,
+ create,
+ Some(client_id),
+ ))
+ .with_context(err_context)?;
+ },
Action::TabNameInput(c) => {
session
.senders
diff --git a/zellij-server/src/screen.rs b/zellij-server/src/screen.rs
index fdca620d9..9a196f35d 100644
--- a/zellij-server/src/screen.rs
+++ b/zellij-server/src/screen.rs
@@ -196,6 +196,7 @@ 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, bool, Option<ClientId>),
ToggleTab(ClientId),
UpdateTabName(Vec<u8>, ClientId),
UndoRenameTab(ClientId),
@@ -317,6 +318,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,
@@ -623,6 +625,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}");
@@ -678,6 +692,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:?}");
@@ -1981,6 +1999,39 @@ pub(crate) fn screen_thread_main(
screen.render()?;
}
},
+ ScreenInstruction::GoToTabName(tab_name, 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, 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()?;
diff --git a/zellij-server/src/unit/screen_tests.rs b/zellij-server/src/unit/screen_tests.rs
index e9b399618..7b1be55e0 100644
--- a/zellij-server/src/unit/screen_tests.rs
+++ b/zellij-server/src/unit/screen_tests.rs
@@ -547,6 +547,40 @@ pub fn switch_to_next_tab() {
}
#[test]
+pub fn switch_to_tab_name() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let mut screen = create_new_screen(size);
+
+ new_tab(&mut screen, 1, 1);
+ new_tab(&mut screen, 2, 2);
+
+ assert_eq!(
+ screen
+ .switch_active_tab_name("Tab #1".to_string(), 1)
+ .expect("TEST"),
+ false,
+ "Active tab switched to tab by name"
+ );
+ assert_eq!(
+ screen
+ .switch_active_tab_name("Tab #2".to_string(), 1)
+ .expect("TEST"),
+ true,
+ "Active tab switched to tab by name"
+ );
+ assert_eq!(
+ screen
+ .switch_active_tab_name("Tab #3".to_string(), 1)
+ .expect("TEST"),
+ true,
+ "Active tab switched to tab by name"
+ );
+}
+
+#[test]
pub fn close_tab() {
let size = Size {
cols: 121,
diff --git a/zellij-utils/src/cli.rs b/zellij-utils/src/cli.rs
index 82c34eecd..1ef43e27f 100644
--- a/zellij-utils/src/cli.rs
+++ b/zellij-utils/src/cli.rs
@@ -315,6 +315,13 @@ pub enum CliAction {
CloseTab,
/// Go to tab with index [index]
GoToTab { index: u32 },
+ /// Go to tab with name [name]
+ GoToTabName {
+ name: String,
+ /// Create a tab if one does not exist.
+ #[clap(short, long, value_parser)]
+ create: bool,
+ },
/// Renames the focused pane
RenameTab { name: String },
/// Remove a previously set tab name
diff --git a/zellij-utils/src/errors.rs b/zellij-utils/src/errors.rs
index 50c8f9b28..a7986de8d 100644
--- a/zellij-utils/src/errors.rs
+++ b/zellij-utils/src/errors.rs
@@ -285,6 +285,7 @@ pub enum ScreenContext {
SwitchTabPrev,
CloseTab,
GoToTab,
+ GoToTabName,
UpdateTabName,
UndoRenameTab,
TerminalResize,
diff --git a/zellij-utils/src/input/actions.rs b/zellij-utils/src/input/actions.rs
index 1207023aa..b5d6acb13 100644
--- a/zellij-utils/src/input/actions.rs
+++ b/zellij-utils/src/input/actions.rs
@@ -174,6 +174,7 @@ pub enum Action {
/// Close the current tab.
CloseTab,
GoToTab(u32),
+ GoToTabName(String, bool),
ToggleTab,
TabNameInput(Vec<u8>),
UndoRenameTab,
@@ -321,6 +322,7 @@ impl Action {
CliAction::GoToPreviousTab => Ok(vec![Action::GoToPreviousTab]),
CliAction::CloseTab => Ok(vec![Action::CloseTab]),
CliAction::GoToTab { index } => Ok(vec![Action::GoToTab(index)]),
+ CliAction::GoToTabName { name, create } => Ok(vec![Action::GoToTabName(name, create)]),
CliAction::RenameTab { name } => Ok(vec![
Action::TabNameInput(vec![0]),
Action::TabNameInput(name.as_bytes().to_vec()),