mirror of
https://github.com/zellij-org/zellij.git
synced 2024-11-22 22:26:54 +03:00
feat: add action to undo rename (#1513)
This commit is contained in:
parent
8da6207849
commit
8e2be2c61e
@ -32,6 +32,7 @@ pub const MOVE_FOCUS_DOWN_IN_PANE_MODE: [u8; 1] = [106]; // j
|
||||
pub const MOVE_FOCUS_UP_IN_PANE_MODE: [u8; 1] = [107]; // k
|
||||
pub const MOVE_FOCUS_LEFT_IN_PANE_MODE: [u8; 1] = [104]; // h
|
||||
pub const MOVE_FOCUS_RIGHT_IN_PANE_MODE: [u8; 1] = [108]; // l
|
||||
pub const RENAME_PANE_MODE: [u8; 1] = [99]; // c
|
||||
|
||||
pub const SCROLL_MODE: [u8; 1] = [19]; // ctrl-s
|
||||
pub const SCROLL_UP_IN_SCROLL_MODE: [u8; 1] = [107]; // k
|
||||
@ -51,6 +52,7 @@ pub const NEW_TAB_IN_TAB_MODE: [u8; 1] = [110]; // n
|
||||
pub const SWITCH_NEXT_TAB_IN_TAB_MODE: [u8; 1] = [108]; // l
|
||||
pub const SWITCH_PREV_TAB_IN_TAB_MODE: [u8; 1] = [104]; // h
|
||||
pub const CLOSE_TAB_IN_TAB_MODE: [u8; 1] = [120]; // x
|
||||
pub const RENAME_TAB_MODE: [u8; 1] = [114]; // r
|
||||
|
||||
pub const SESSION_MODE: [u8; 1] = [15]; // ctrl-o
|
||||
pub const DETACH_IN_SESSION_MODE: [u8; 1] = [100]; // d
|
||||
@ -1853,3 +1855,102 @@ pub fn edit_scrollback() {
|
||||
};
|
||||
assert!(last_snapshot.contains(".dump"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
pub fn undo_rename_tab() {
|
||||
let fake_win_size = Size {
|
||||
cols: 120,
|
||||
rows: 24,
|
||||
};
|
||||
|
||||
let mut test_attempts = 10;
|
||||
let last_snapshot = loop {
|
||||
RemoteRunner::kill_running_sessions(fake_win_size);
|
||||
let mut runner = RemoteRunner::new(fake_win_size).add_step(Step {
|
||||
name: "Undo tab name change",
|
||||
instruction: |mut remote_terminal: RemoteTerminal| -> bool {
|
||||
let mut step_is_complete = false;
|
||||
if remote_terminal.status_bar_appears()
|
||||
&& remote_terminal.snapshot_contains("Tab #1")
|
||||
{
|
||||
remote_terminal.send_key(&TAB_MODE);
|
||||
remote_terminal.send_key(&RENAME_TAB_MODE);
|
||||
remote_terminal.send_key(&[97, 97]);
|
||||
remote_terminal.send_key(&ESC);
|
||||
step_is_complete = true;
|
||||
}
|
||||
step_is_complete
|
||||
},
|
||||
});
|
||||
runner.run_all_steps();
|
||||
|
||||
let last_snapshot = runner.take_snapshot_after(Step {
|
||||
name: "Wait for tab name to apper on screen",
|
||||
instruction: |remote_terminal: RemoteTerminal| -> bool {
|
||||
let mut step_is_complete = false;
|
||||
if remote_terminal.snapshot_contains("Tab #1") {
|
||||
step_is_complete = true
|
||||
}
|
||||
step_is_complete
|
||||
},
|
||||
});
|
||||
|
||||
if runner.test_timed_out && test_attempts > 0 {
|
||||
test_attempts -= 1;
|
||||
continue;
|
||||
} else {
|
||||
break last_snapshot;
|
||||
}
|
||||
};
|
||||
assert_snapshot!(last_snapshot);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
pub fn undo_rename_pane() {
|
||||
let fake_win_size = Size {
|
||||
cols: 120,
|
||||
rows: 24,
|
||||
};
|
||||
|
||||
let mut test_attempts = 10;
|
||||
let last_snapshot = loop {
|
||||
RemoteRunner::kill_running_sessions(fake_win_size);
|
||||
let mut runner = RemoteRunner::new(fake_win_size).add_step(Step {
|
||||
name: "Undo pane name change",
|
||||
instruction: |mut remote_terminal: RemoteTerminal| -> bool {
|
||||
let mut step_is_complete = false;
|
||||
if remote_terminal.status_bar_appears() && remote_terminal.cursor_position_is(3, 2)
|
||||
{
|
||||
remote_terminal.send_key(&PANE_MODE);
|
||||
remote_terminal.send_key(&RENAME_PANE_MODE);
|
||||
remote_terminal.send_key(&[97, 97]);
|
||||
remote_terminal.send_key(&ESC);
|
||||
step_is_complete = true;
|
||||
}
|
||||
step_is_complete
|
||||
},
|
||||
});
|
||||
runner.run_all_steps();
|
||||
|
||||
let last_snapshot = runner.take_snapshot_after(Step {
|
||||
name: "Wait for pane name to apper on screen",
|
||||
instruction: |remote_terminal: RemoteTerminal| -> bool {
|
||||
let mut step_is_complete = false;
|
||||
if remote_terminal.snapshot_contains("Pane #1") {
|
||||
step_is_complete = true
|
||||
}
|
||||
step_is_complete
|
||||
},
|
||||
});
|
||||
|
||||
if runner.test_timed_out && test_attempts > 0 {
|
||||
test_attempts -= 1;
|
||||
continue;
|
||||
} else {
|
||||
break last_snapshot;
|
||||
}
|
||||
};
|
||||
assert_snapshot!(last_snapshot);
|
||||
}
|
||||
|
@ -0,0 +1,28 @@
|
||||
---
|
||||
source: src/tests/e2e/cases.rs
|
||||
expression: last_snapshot
|
||||
---
|
||||
Zellij (e2e-test) Tab #1
|
||||
┌ Pane #1 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||||
│$ █ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SCROLL <o> SESSION <q> QUIT
|
||||
Tip: Alt + <n> => new pane. Alt + <←↓↑→ or hjkl> => navigate. Alt + <+-> => resize pane.
|
@ -0,0 +1,28 @@
|
||||
---
|
||||
source: src/tests/e2e/cases.rs
|
||||
expression: last_snapshot
|
||||
---
|
||||
Zellij (e2e-test) Tab #1
|
||||
┌ Pane #1 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||||
│$ █ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SCROLL <o> SESSION <q> QUIT
|
||||
Tip: Alt + <n> => new pane. Alt + <←↓↑→ or hjkl> => navigate. Alt + <+-> => resize pane.
|
@ -30,6 +30,7 @@ pub(crate) struct PluginPane {
|
||||
pub active_at: Instant,
|
||||
pub pane_title: String,
|
||||
pub pane_name: String,
|
||||
prev_pane_name: String,
|
||||
frame: bool,
|
||||
borderless: bool,
|
||||
}
|
||||
@ -54,7 +55,8 @@ impl PluginPane {
|
||||
content_offset: Offset::default(),
|
||||
pane_title: title,
|
||||
borderless: false,
|
||||
pane_name,
|
||||
pane_name: pane_name.clone(),
|
||||
prev_pane_name: pane_name,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -386,6 +388,18 @@ impl Pane for PluginPane {
|
||||
fn set_content_offset(&mut self, offset: Offset) {
|
||||
self.content_offset = offset;
|
||||
}
|
||||
|
||||
fn store_pane_name(&mut self) {
|
||||
if self.pane_name != self.prev_pane_name {
|
||||
self.prev_pane_name = self.pane_name.clone()
|
||||
}
|
||||
}
|
||||
fn load_pane_name(&mut self) {
|
||||
if self.pane_name != self.prev_pane_name {
|
||||
self.pane_name = self.prev_pane_name.clone()
|
||||
}
|
||||
}
|
||||
|
||||
fn set_borderless(&mut self, borderless: bool) {
|
||||
self.borderless = borderless;
|
||||
}
|
||||
|
@ -50,6 +50,7 @@ pub struct TerminalPane {
|
||||
content_offset: Offset,
|
||||
pane_title: String,
|
||||
pane_name: String,
|
||||
prev_pane_name: String,
|
||||
frame: HashMap<ClientId, PaneFrame>,
|
||||
borderless: bool,
|
||||
fake_cursor_locations: HashSet<(usize, usize)>, // (x, y) - these hold a record of previous fake cursors which we need to clear on render
|
||||
@ -472,6 +473,17 @@ impl Pane for TerminalPane {
|
||||
self.reflow_lines();
|
||||
}
|
||||
|
||||
fn store_pane_name(&mut self) {
|
||||
if self.pane_name != self.prev_pane_name {
|
||||
self.prev_pane_name = self.pane_name.clone()
|
||||
}
|
||||
}
|
||||
fn load_pane_name(&mut self) {
|
||||
if self.pane_name != self.prev_pane_name {
|
||||
self.pane_name = self.prev_pane_name.clone()
|
||||
}
|
||||
}
|
||||
|
||||
fn set_borderless(&mut self, borderless: bool) {
|
||||
self.borderless = borderless;
|
||||
}
|
||||
@ -521,7 +533,8 @@ impl TerminalPane {
|
||||
style,
|
||||
selection_scrolled_at: time::Instant::now(),
|
||||
pane_title: initial_pane_title,
|
||||
pane_name,
|
||||
pane_name: pane_name.clone(),
|
||||
prev_pane_name: pane_name,
|
||||
borderless: false,
|
||||
fake_cursor_locations: HashSet::new(),
|
||||
}
|
||||
|
@ -259,6 +259,12 @@ fn route_action(
|
||||
.send_to_screen(ScreenInstruction::UpdatePaneName(c, client_id))
|
||||
.unwrap();
|
||||
},
|
||||
Action::UndoRenamePane => {
|
||||
session
|
||||
.senders
|
||||
.send_to_screen(ScreenInstruction::UndoRenamePane(client_id))
|
||||
.unwrap();
|
||||
},
|
||||
Action::Run(command) => {
|
||||
let run_cmd = Some(TerminalAction::RunCommand(command.clone().into()));
|
||||
let pty_instr = match command.direction {
|
||||
@ -330,6 +336,12 @@ fn route_action(
|
||||
.send_to_screen(ScreenInstruction::UpdateTabName(c, client_id))
|
||||
.unwrap();
|
||||
},
|
||||
Action::UndoRenameTab => {
|
||||
session
|
||||
.senders
|
||||
.send_to_screen(ScreenInstruction::UndoRenameTab(client_id))
|
||||
.unwrap();
|
||||
},
|
||||
Action::Quit => {
|
||||
to_server
|
||||
.send(ServerInstruction::ClientExit(client_id))
|
||||
|
@ -85,6 +85,7 @@ pub enum ScreenInstruction {
|
||||
SetSelectable(PaneId, bool, usize),
|
||||
ClosePane(PaneId, Option<ClientId>),
|
||||
UpdatePaneName(Vec<u8>, ClientId),
|
||||
UndoRenamePane(ClientId),
|
||||
NewTab(Layout, Vec<RawFd>, ClientId),
|
||||
SwitchTabNext(ClientId),
|
||||
SwitchTabPrev(ClientId),
|
||||
@ -93,6 +94,7 @@ pub enum ScreenInstruction {
|
||||
GoToTab(u32, Option<ClientId>), // this Option is a hacky workaround, please do not copy thie behaviour
|
||||
ToggleTab(ClientId),
|
||||
UpdateTabName(Vec<u8>, ClientId),
|
||||
UndoRenameTab(ClientId),
|
||||
TerminalResize(Size),
|
||||
TerminalPixelDimensions(PixelDimensions),
|
||||
TerminalBackgroundColor(String),
|
||||
@ -168,12 +170,14 @@ impl From<&ScreenInstruction> for ScreenContext {
|
||||
ScreenInstruction::SetSelectable(..) => ScreenContext::SetSelectable,
|
||||
ScreenInstruction::ClosePane(..) => ScreenContext::ClosePane,
|
||||
ScreenInstruction::UpdatePaneName(..) => ScreenContext::UpdatePaneName,
|
||||
ScreenInstruction::UndoRenamePane(..) => ScreenContext::UndoRenamePane,
|
||||
ScreenInstruction::NewTab(..) => ScreenContext::NewTab,
|
||||
ScreenInstruction::SwitchTabNext(..) => ScreenContext::SwitchTabNext,
|
||||
ScreenInstruction::SwitchTabPrev(..) => ScreenContext::SwitchTabPrev,
|
||||
ScreenInstruction::CloseTab(..) => ScreenContext::CloseTab,
|
||||
ScreenInstruction::GoToTab(..) => ScreenContext::GoToTab,
|
||||
ScreenInstruction::UpdateTabName(..) => ScreenContext::UpdateTabName,
|
||||
ScreenInstruction::UndoRenameTab(..) => ScreenContext::UndoRenameTab,
|
||||
ScreenInstruction::TerminalResize(..) => ScreenContext::TerminalResize,
|
||||
ScreenInstruction::TerminalPixelDimensions(..) => {
|
||||
ScreenContext::TerminalPixelDimensions
|
||||
@ -742,12 +746,23 @@ impl Screen {
|
||||
log::error!("Active tab not found for client id: {:?}", client_id);
|
||||
}
|
||||
}
|
||||
pub fn undo_active_rename_tab(&mut self, client_id: ClientId) {
|
||||
if let Some(active_tab) = self.get_active_tab_mut(client_id) {
|
||||
if active_tab.name != active_tab.prev_name {
|
||||
active_tab.name = active_tab.prev_name.clone();
|
||||
self.update_tabs();
|
||||
}
|
||||
} else {
|
||||
log::error!("Active tab not found for client id: {:?}", client_id);
|
||||
}
|
||||
}
|
||||
pub fn change_mode(&mut self, mode_info: ModeInfo, client_id: ClientId) {
|
||||
let previous_mode = self
|
||||
.mode_info
|
||||
.get(&client_id)
|
||||
.unwrap_or(&self.default_mode_info)
|
||||
.mode;
|
||||
|
||||
if previous_mode == InputMode::Scroll
|
||||
&& (mode_info.mode == InputMode::Normal || mode_info.mode == InputMode::Locked)
|
||||
{
|
||||
@ -755,6 +770,23 @@ impl Screen {
|
||||
active_tab.clear_active_terminal_scroll(client_id);
|
||||
}
|
||||
}
|
||||
|
||||
if mode_info.mode == InputMode::RenameTab {
|
||||
if let Some(active_tab) = self.get_active_tab_mut(client_id) {
|
||||
active_tab.prev_name = active_tab.name.clone();
|
||||
}
|
||||
}
|
||||
|
||||
if mode_info.mode == InputMode::RenamePane {
|
||||
if let Some(active_tab) = self.get_active_tab_mut(client_id) {
|
||||
if let Some(active_pane) =
|
||||
active_tab.get_active_pane_or_floating_pane_mut(client_id)
|
||||
{
|
||||
active_pane.store_pane_name();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.style = mode_info.style;
|
||||
self.mode_info.insert(client_id, mode_info.clone());
|
||||
for tab in self.tabs.values_mut() {
|
||||
@ -1140,6 +1172,11 @@ pub(crate) fn screen_thread_main(
|
||||
.update_active_pane_name(c, client_id));
|
||||
screen.render();
|
||||
},
|
||||
ScreenInstruction::UndoRenamePane(client_id) => {
|
||||
active_tab!(screen, client_id, |tab: &mut Tab| tab
|
||||
.undo_active_rename_pane(client_id));
|
||||
screen.render();
|
||||
},
|
||||
ScreenInstruction::ToggleActiveTerminalFullscreen(client_id) => {
|
||||
active_tab!(screen, client_id, |tab: &mut Tab| tab
|
||||
.toggle_active_pane_fullscreen(client_id));
|
||||
@ -1186,6 +1223,10 @@ pub(crate) fn screen_thread_main(
|
||||
screen.update_active_tab_name(c, client_id);
|
||||
screen.render();
|
||||
},
|
||||
ScreenInstruction::UndoRenameTab(client_id) => {
|
||||
screen.undo_active_rename_tab(client_id);
|
||||
screen.render();
|
||||
},
|
||||
ScreenInstruction::TerminalResize(new_size) => {
|
||||
screen.resize_to_screen(new_size);
|
||||
screen.render();
|
||||
|
@ -70,6 +70,7 @@ pub(crate) struct Tab {
|
||||
pub index: usize,
|
||||
pub position: usize,
|
||||
pub name: String,
|
||||
pub prev_name: String,
|
||||
tiled_panes: TiledPanes,
|
||||
floating_panes: FloatingPanes,
|
||||
suppressed_panes: HashMap<PaneId, Box<dyn Pane>>,
|
||||
@ -267,6 +268,8 @@ pub trait Pane {
|
||||
|| position_on_screen.column() == self.x()
|
||||
|| position_on_screen.column() == (self.x() + self.cols()).saturating_sub(1)
|
||||
}
|
||||
fn store_pane_name(&mut self);
|
||||
fn load_pane_name(&mut self);
|
||||
fn set_borderless(&mut self, borderless: bool);
|
||||
fn borderless(&self) -> bool;
|
||||
fn handle_right_click(&mut self, _to: &Position, _client_id: ClientId) {}
|
||||
@ -346,7 +349,8 @@ impl Tab {
|
||||
tiled_panes,
|
||||
floating_panes,
|
||||
suppressed_panes: HashMap::new(),
|
||||
name,
|
||||
name: name.clone(),
|
||||
prev_name: name,
|
||||
max_panes,
|
||||
viewport,
|
||||
display_area,
|
||||
@ -1932,6 +1936,21 @@ impl Tab {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn undo_active_rename_pane(&mut self, client_id: ClientId) {
|
||||
if let Some(active_terminal_id) = self.get_active_terminal_id(client_id) {
|
||||
let active_terminal = if self.are_floating_panes_visible() {
|
||||
self.floating_panes
|
||||
.get_pane_mut(PaneId::Terminal(active_terminal_id))
|
||||
} else {
|
||||
self.tiled_panes
|
||||
.get_pane_mut(PaneId::Terminal(active_terminal_id))
|
||||
}
|
||||
.unwrap();
|
||||
|
||||
active_terminal.load_pane_name();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_position_inside_viewport(&self, point: &Position) -> bool {
|
||||
let Position {
|
||||
line: Line(line),
|
||||
|
@ -327,7 +327,7 @@ keybinds:
|
||||
renametab:
|
||||
- action: [SwitchToMode: Normal,]
|
||||
key: [Char: "\n", Ctrl: 'c', Esc]
|
||||
- action: [TabNameInput: [27] , SwitchToMode: Tab,]
|
||||
- action: [UndoRenameTab , SwitchToMode: Tab,]
|
||||
key: [Esc,]
|
||||
- action: [NewPane: ,]
|
||||
key: [ Alt: 'n',]
|
||||
@ -348,7 +348,7 @@ keybinds:
|
||||
renamepane:
|
||||
- action: [SwitchToMode: Normal,]
|
||||
key: [Char: "\n", Ctrl: 'c', Esc]
|
||||
- action: [PaneNameInput: [27] , SwitchToMode: Pane,]
|
||||
- action: [UndoRenamePane , SwitchToMode: Pane,]
|
||||
key: [Esc,]
|
||||
- action: [NewPane: ,]
|
||||
key: [ Alt: 'n',]
|
||||
|
@ -265,12 +265,14 @@ pub enum ScreenContext {
|
||||
SetFixedWidth,
|
||||
ClosePane,
|
||||
UpdatePaneName,
|
||||
UndoRenamePane,
|
||||
NewTab,
|
||||
SwitchTabNext,
|
||||
SwitchTabPrev,
|
||||
CloseTab,
|
||||
GoToTab,
|
||||
UpdateTabName,
|
||||
UndoRenameTab,
|
||||
TerminalResize,
|
||||
TerminalPixelDimensions,
|
||||
TerminalBackgroundColor,
|
||||
|
@ -91,6 +91,7 @@ pub enum Action {
|
||||
/// Close the focus pane.
|
||||
CloseFocus,
|
||||
PaneNameInput(Vec<u8>),
|
||||
UndoRenamePane,
|
||||
/// Create a new tab, optionally with a specified tab layout.
|
||||
NewTab(Option<TabLayout>),
|
||||
/// Do nothing.
|
||||
@ -104,6 +105,7 @@ pub enum Action {
|
||||
GoToTab(u32),
|
||||
ToggleTab,
|
||||
TabNameInput(Vec<u8>),
|
||||
UndoRenameTab,
|
||||
/// Run specified command in new pane.
|
||||
Run(RunCommandAction),
|
||||
/// Detach session and exit
|
||||
|
Loading…
Reference in New Issue
Block a user