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
This commit is contained in:
parent
601eee8bb3
commit
99e8d56adb
7 changed files with 106 additions and 0 deletions
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()?;
|
||||
|
|
|
|||
|
|
@ -546,6 +546,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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -285,6 +285,7 @@ pub enum ScreenContext {
|
|||
SwitchTabPrev,
|
||||
CloseTab,
|
||||
GoToTab,
|
||||
GoToTabName,
|
||||
UpdateTabName,
|
||||
UndoRenameTab,
|
||||
TerminalResize,
|
||||
|
|
|
|||
|
|
@ -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()),
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue