Feature: Move panes directionally (#762)
* Feature: Move panes directionally * change keybinds * Fix active pane after move * Add a separate 'Move' mode * Add tests * Add more tests * Send resize message to pty * wrap set_terminal_size_using_fd() in macro * change keybind for Move mode * cargo fmt * fix test * move render functions from tab.rs to screen.rs * undo wrong keybinds
This commit is contained in:
parent
76a96b538b
commit
d90e3d4cac
11 changed files with 546 additions and 12 deletions
|
|
@ -23,6 +23,7 @@ enum CtrlKeyAction {
|
||||||
Scroll,
|
Scroll,
|
||||||
Quit,
|
Quit,
|
||||||
Session,
|
Session,
|
||||||
|
Move,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum CtrlKeyMode {
|
enum CtrlKeyMode {
|
||||||
|
|
@ -41,6 +42,7 @@ impl CtrlKeyShortcut {
|
||||||
CtrlKeyAction::Scroll => String::from("SCROLL"),
|
CtrlKeyAction::Scroll => String::from("SCROLL"),
|
||||||
CtrlKeyAction::Quit => String::from("QUIT"),
|
CtrlKeyAction::Quit => String::from("QUIT"),
|
||||||
CtrlKeyAction::Session => String::from("SESSION"),
|
CtrlKeyAction::Session => String::from("SESSION"),
|
||||||
|
CtrlKeyAction::Move => String::from("MOVE"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn letter_shortcut(&self) -> char {
|
pub fn letter_shortcut(&self) -> char {
|
||||||
|
|
@ -52,6 +54,7 @@ impl CtrlKeyShortcut {
|
||||||
CtrlKeyAction::Scroll => 's',
|
CtrlKeyAction::Scroll => 's',
|
||||||
CtrlKeyAction::Quit => 'q',
|
CtrlKeyAction::Quit => 'q',
|
||||||
CtrlKeyAction::Session => 'o',
|
CtrlKeyAction::Session => 'o',
|
||||||
|
CtrlKeyAction::Move => 'h',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -253,6 +256,7 @@ pub fn ctrl_keys(help: &ModeInfo, max_len: usize, separator: &str) -> LinePart {
|
||||||
CtrlKeyShortcut::new(CtrlKeyMode::Disabled, CtrlKeyAction::Pane),
|
CtrlKeyShortcut::new(CtrlKeyMode::Disabled, CtrlKeyAction::Pane),
|
||||||
CtrlKeyShortcut::new(CtrlKeyMode::Disabled, CtrlKeyAction::Tab),
|
CtrlKeyShortcut::new(CtrlKeyMode::Disabled, CtrlKeyAction::Tab),
|
||||||
CtrlKeyShortcut::new(CtrlKeyMode::Disabled, CtrlKeyAction::Resize),
|
CtrlKeyShortcut::new(CtrlKeyMode::Disabled, CtrlKeyAction::Resize),
|
||||||
|
CtrlKeyShortcut::new(CtrlKeyMode::Disabled, CtrlKeyAction::Move),
|
||||||
CtrlKeyShortcut::new(CtrlKeyMode::Disabled, CtrlKeyAction::Scroll),
|
CtrlKeyShortcut::new(CtrlKeyMode::Disabled, CtrlKeyAction::Scroll),
|
||||||
CtrlKeyShortcut::new(CtrlKeyMode::Disabled, CtrlKeyAction::Session),
|
CtrlKeyShortcut::new(CtrlKeyMode::Disabled, CtrlKeyAction::Session),
|
||||||
CtrlKeyShortcut::new(CtrlKeyMode::Disabled, CtrlKeyAction::Quit),
|
CtrlKeyShortcut::new(CtrlKeyMode::Disabled, CtrlKeyAction::Quit),
|
||||||
|
|
@ -267,6 +271,7 @@ pub fn ctrl_keys(help: &ModeInfo, max_len: usize, separator: &str) -> LinePart {
|
||||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Pane),
|
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Pane),
|
||||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Tab),
|
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Tab),
|
||||||
CtrlKeyShortcut::new(CtrlKeyMode::Selected, CtrlKeyAction::Resize),
|
CtrlKeyShortcut::new(CtrlKeyMode::Selected, CtrlKeyAction::Resize),
|
||||||
|
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Move),
|
||||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Scroll),
|
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Scroll),
|
||||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Session),
|
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Session),
|
||||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Quit),
|
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Quit),
|
||||||
|
|
@ -281,6 +286,7 @@ pub fn ctrl_keys(help: &ModeInfo, max_len: usize, separator: &str) -> LinePart {
|
||||||
CtrlKeyShortcut::new(CtrlKeyMode::Selected, CtrlKeyAction::Pane),
|
CtrlKeyShortcut::new(CtrlKeyMode::Selected, CtrlKeyAction::Pane),
|
||||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Tab),
|
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Tab),
|
||||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Resize),
|
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Resize),
|
||||||
|
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Move),
|
||||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Scroll),
|
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Scroll),
|
||||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Session),
|
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Session),
|
||||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Quit),
|
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Quit),
|
||||||
|
|
@ -295,6 +301,7 @@ pub fn ctrl_keys(help: &ModeInfo, max_len: usize, separator: &str) -> LinePart {
|
||||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Pane),
|
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Pane),
|
||||||
CtrlKeyShortcut::new(CtrlKeyMode::Selected, CtrlKeyAction::Tab),
|
CtrlKeyShortcut::new(CtrlKeyMode::Selected, CtrlKeyAction::Tab),
|
||||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Resize),
|
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Resize),
|
||||||
|
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Move),
|
||||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Scroll),
|
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Scroll),
|
||||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Session),
|
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Session),
|
||||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Quit),
|
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Quit),
|
||||||
|
|
@ -309,6 +316,7 @@ pub fn ctrl_keys(help: &ModeInfo, max_len: usize, separator: &str) -> LinePart {
|
||||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Pane),
|
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Pane),
|
||||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Tab),
|
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Tab),
|
||||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Resize),
|
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Resize),
|
||||||
|
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Move),
|
||||||
CtrlKeyShortcut::new(CtrlKeyMode::Selected, CtrlKeyAction::Scroll),
|
CtrlKeyShortcut::new(CtrlKeyMode::Selected, CtrlKeyAction::Scroll),
|
||||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Session),
|
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Session),
|
||||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Quit),
|
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Quit),
|
||||||
|
|
@ -316,6 +324,21 @@ pub fn ctrl_keys(help: &ModeInfo, max_len: usize, separator: &str) -> LinePart {
|
||||||
colored_elements,
|
colored_elements,
|
||||||
separator,
|
separator,
|
||||||
),
|
),
|
||||||
|
InputMode::Move => key_indicators(
|
||||||
|
max_len,
|
||||||
|
&[
|
||||||
|
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Lock),
|
||||||
|
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Pane),
|
||||||
|
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Tab),
|
||||||
|
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Resize),
|
||||||
|
CtrlKeyShortcut::new(CtrlKeyMode::Selected, CtrlKeyAction::Move),
|
||||||
|
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Scroll),
|
||||||
|
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Session),
|
||||||
|
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Quit),
|
||||||
|
],
|
||||||
|
colored_elements,
|
||||||
|
separator,
|
||||||
|
),
|
||||||
InputMode::Normal => key_indicators(
|
InputMode::Normal => key_indicators(
|
||||||
max_len,
|
max_len,
|
||||||
&[
|
&[
|
||||||
|
|
@ -323,6 +346,7 @@ pub fn ctrl_keys(help: &ModeInfo, max_len: usize, separator: &str) -> LinePart {
|
||||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Pane),
|
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Pane),
|
||||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Tab),
|
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Tab),
|
||||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Resize),
|
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Resize),
|
||||||
|
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Move),
|
||||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Scroll),
|
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Scroll),
|
||||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Session),
|
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Session),
|
||||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Quit),
|
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Quit),
|
||||||
|
|
@ -337,6 +361,7 @@ pub fn ctrl_keys(help: &ModeInfo, max_len: usize, separator: &str) -> LinePart {
|
||||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Pane),
|
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Pane),
|
||||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Tab),
|
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Tab),
|
||||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Resize),
|
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Resize),
|
||||||
|
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Move),
|
||||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Scroll),
|
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Scroll),
|
||||||
CtrlKeyShortcut::new(CtrlKeyMode::Selected, CtrlKeyAction::Session),
|
CtrlKeyShortcut::new(CtrlKeyMode::Selected, CtrlKeyAction::Session),
|
||||||
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Quit),
|
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Quit),
|
||||||
|
|
|
||||||
|
|
@ -116,6 +116,15 @@ fn route_action(
|
||||||
};
|
};
|
||||||
session.senders.send_to_screen(screen_instr).unwrap();
|
session.senders.send_to_screen(screen_instr).unwrap();
|
||||||
}
|
}
|
||||||
|
Action::MovePane(direction) => {
|
||||||
|
let screen_instr = match direction {
|
||||||
|
Direction::Left => ScreenInstruction::MovePaneLeft,
|
||||||
|
Direction::Right => ScreenInstruction::MovePaneRight,
|
||||||
|
Direction::Up => ScreenInstruction::MovePaneUp,
|
||||||
|
Direction::Down => ScreenInstruction::MovePaneDown,
|
||||||
|
};
|
||||||
|
session.senders.send_to_screen(screen_instr).unwrap();
|
||||||
|
}
|
||||||
Action::ScrollUp => {
|
Action::ScrollUp => {
|
||||||
session
|
session
|
||||||
.senders
|
.senders
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,10 @@ pub(crate) enum ScreenInstruction {
|
||||||
MoveFocusUp,
|
MoveFocusUp,
|
||||||
MoveFocusRight,
|
MoveFocusRight,
|
||||||
MoveFocusRightOrNextTab,
|
MoveFocusRightOrNextTab,
|
||||||
|
MovePaneUp,
|
||||||
|
MovePaneDown,
|
||||||
|
MovePaneRight,
|
||||||
|
MovePaneLeft,
|
||||||
Exit,
|
Exit,
|
||||||
ScrollUp,
|
ScrollUp,
|
||||||
ScrollUpAt(Position),
|
ScrollUpAt(Position),
|
||||||
|
|
@ -100,6 +104,10 @@ impl From<&ScreenInstruction> for ScreenContext {
|
||||||
ScreenInstruction::MoveFocusUp => ScreenContext::MoveFocusUp,
|
ScreenInstruction::MoveFocusUp => ScreenContext::MoveFocusUp,
|
||||||
ScreenInstruction::MoveFocusRight => ScreenContext::MoveFocusRight,
|
ScreenInstruction::MoveFocusRight => ScreenContext::MoveFocusRight,
|
||||||
ScreenInstruction::MoveFocusRightOrNextTab => ScreenContext::MoveFocusRightOrNextTab,
|
ScreenInstruction::MoveFocusRightOrNextTab => ScreenContext::MoveFocusRightOrNextTab,
|
||||||
|
ScreenInstruction::MovePaneDown => ScreenContext::MovePaneDown,
|
||||||
|
ScreenInstruction::MovePaneUp => ScreenContext::MovePaneUp,
|
||||||
|
ScreenInstruction::MovePaneRight => ScreenContext::MovePaneRight,
|
||||||
|
ScreenInstruction::MovePaneLeft => ScreenContext::MovePaneLeft,
|
||||||
ScreenInstruction::Exit => ScreenContext::Exit,
|
ScreenInstruction::Exit => ScreenContext::Exit,
|
||||||
ScreenInstruction::ScrollUp => ScreenContext::ScrollUp,
|
ScreenInstruction::ScrollUp => ScreenContext::ScrollUp,
|
||||||
ScreenInstruction::ScrollDown => ScreenContext::ScrollDown,
|
ScreenInstruction::ScrollDown => ScreenContext::ScrollDown,
|
||||||
|
|
@ -637,6 +645,29 @@ pub(crate) fn screen_thread_main(
|
||||||
|
|
||||||
screen.render();
|
screen.render();
|
||||||
}
|
}
|
||||||
|
ScreenInstruction::MovePaneDown => {
|
||||||
|
screen.get_active_tab_mut().unwrap().move_active_pane_down();
|
||||||
|
|
||||||
|
screen.render();
|
||||||
|
}
|
||||||
|
ScreenInstruction::MovePaneUp => {
|
||||||
|
screen.get_active_tab_mut().unwrap().move_active_pane_up();
|
||||||
|
|
||||||
|
screen.render();
|
||||||
|
}
|
||||||
|
ScreenInstruction::MovePaneRight => {
|
||||||
|
screen
|
||||||
|
.get_active_tab_mut()
|
||||||
|
.unwrap()
|
||||||
|
.move_active_pane_right();
|
||||||
|
|
||||||
|
screen.render();
|
||||||
|
}
|
||||||
|
ScreenInstruction::MovePaneLeft => {
|
||||||
|
screen.get_active_tab_mut().unwrap().move_active_pane_left();
|
||||||
|
|
||||||
|
screen.render();
|
||||||
|
}
|
||||||
ScreenInstruction::ScrollUp => {
|
ScreenInstruction::ScrollUp => {
|
||||||
screen
|
screen
|
||||||
.get_active_tab_mut()
|
.get_active_tab_mut()
|
||||||
|
|
|
||||||
|
|
@ -275,6 +275,20 @@ pub trait Pane {
|
||||||
fn borderless(&self) -> bool;
|
fn borderless(&self) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! resize_pty {
|
||||||
|
($pane:expr, $os_input:expr) => {
|
||||||
|
if let PaneId::Terminal(ref pid) = $pane.pid() {
|
||||||
|
// FIXME: This `set_terminal_size_using_fd` call would be best in
|
||||||
|
// `TerminalPane::reflow_lines`
|
||||||
|
$os_input.set_terminal_size_using_fd(
|
||||||
|
*pid,
|
||||||
|
$pane.get_content_columns() as u16,
|
||||||
|
$pane.get_content_rows() as u16,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
impl Tab {
|
impl Tab {
|
||||||
// FIXME: Still too many arguments for clippy to be happy...
|
// FIXME: Still too many arguments for clippy to be happy...
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
|
@ -756,7 +770,7 @@ impl Tab {
|
||||||
self.draw_pane_frames = draw_pane_frames;
|
self.draw_pane_frames = draw_pane_frames;
|
||||||
self.should_clear_display_before_rendering = true;
|
self.should_clear_display_before_rendering = true;
|
||||||
let viewport = self.viewport;
|
let viewport = self.viewport;
|
||||||
for (pane_id, pane) in self.panes.iter_mut() {
|
for pane in self.panes.values_mut() {
|
||||||
if !pane.borderless() {
|
if !pane.borderless() {
|
||||||
pane.set_frame(draw_pane_frames);
|
pane.set_frame(draw_pane_frames);
|
||||||
}
|
}
|
||||||
|
|
@ -783,15 +797,7 @@ impl Tab {
|
||||||
pane.set_content_offset(Offset::shift(pane_rows_offset, pane_columns_offset));
|
pane.set_content_offset(Offset::shift(pane_rows_offset, pane_columns_offset));
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: This, and all other `set_terminal_size_using_fd` calls, would be best in
|
resize_pty!(pane, self.os_api);
|
||||||
// `TerminalPane::reflow_lines`
|
|
||||||
if let PaneId::Terminal(pid) = pane_id {
|
|
||||||
self.os_api.set_terminal_size_using_fd(
|
|
||||||
*pid,
|
|
||||||
pane.get_content_columns() as u16,
|
|
||||||
pane.get_content_rows() as u16,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn render(&mut self) -> Option<Output> {
|
pub fn render(&mut self) -> Option<Output> {
|
||||||
|
|
@ -2031,6 +2037,170 @@ impl Tab {
|
||||||
self.active_terminal = updated_active_terminal;
|
self.active_terminal = updated_active_terminal;
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
pub fn move_active_pane_down(&mut self) {
|
||||||
|
if !self.has_selectable_panes() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if self.fullscreen_is_active {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if let Some(active) = self.get_active_pane() {
|
||||||
|
let terminals = self.get_selectable_panes();
|
||||||
|
let next_index = terminals
|
||||||
|
.enumerate()
|
||||||
|
.filter(|(_, (_, c))| {
|
||||||
|
c.is_directly_below(active) && c.vertically_overlaps_with(active)
|
||||||
|
})
|
||||||
|
.max_by_key(|(_, (_, c))| c.active_at())
|
||||||
|
.map(|(_, (pid, _))| pid);
|
||||||
|
if let Some(&p) = next_index {
|
||||||
|
let current_position = self.panes.get(&self.active_terminal.unwrap()).unwrap();
|
||||||
|
let prev_geom = current_position.position_and_size();
|
||||||
|
let prev_geom_override = current_position.geom_override();
|
||||||
|
|
||||||
|
let new_position = self.panes.get_mut(&p).unwrap();
|
||||||
|
let next_geom = new_position.position_and_size();
|
||||||
|
let next_geom_override = new_position.geom_override();
|
||||||
|
new_position.set_geom(prev_geom);
|
||||||
|
if let Some(geom) = prev_geom_override {
|
||||||
|
new_position.get_geom_override(geom);
|
||||||
|
}
|
||||||
|
resize_pty!(new_position, self.os_api);
|
||||||
|
new_position.set_should_render(true);
|
||||||
|
|
||||||
|
let current_position = self.panes.get_mut(&self.active_terminal.unwrap()).unwrap();
|
||||||
|
current_position.set_geom(next_geom);
|
||||||
|
if let Some(geom) = next_geom_override {
|
||||||
|
current_position.get_geom_override(geom);
|
||||||
|
}
|
||||||
|
resize_pty!(current_position, self.os_api);
|
||||||
|
current_position.set_should_render(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn move_active_pane_up(&mut self) {
|
||||||
|
if !self.has_selectable_panes() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if self.fullscreen_is_active {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if let Some(active) = self.get_active_pane() {
|
||||||
|
let terminals = self.get_selectable_panes();
|
||||||
|
let next_index = terminals
|
||||||
|
.enumerate()
|
||||||
|
.filter(|(_, (_, c))| {
|
||||||
|
c.is_directly_above(active) && c.vertically_overlaps_with(active)
|
||||||
|
})
|
||||||
|
.max_by_key(|(_, (_, c))| c.active_at())
|
||||||
|
.map(|(_, (pid, _))| pid);
|
||||||
|
if let Some(&p) = next_index {
|
||||||
|
let current_position = self.panes.get(&self.active_terminal.unwrap()).unwrap();
|
||||||
|
let prev_geom = current_position.position_and_size();
|
||||||
|
let prev_geom_override = current_position.geom_override();
|
||||||
|
|
||||||
|
let new_position = self.panes.get_mut(&p).unwrap();
|
||||||
|
let next_geom = new_position.position_and_size();
|
||||||
|
let next_geom_override = new_position.geom_override();
|
||||||
|
new_position.set_geom(prev_geom);
|
||||||
|
if let Some(geom) = prev_geom_override {
|
||||||
|
new_position.get_geom_override(geom);
|
||||||
|
}
|
||||||
|
resize_pty!(new_position, self.os_api);
|
||||||
|
new_position.set_should_render(true);
|
||||||
|
|
||||||
|
let current_position = self.panes.get_mut(&self.active_terminal.unwrap()).unwrap();
|
||||||
|
current_position.set_geom(next_geom);
|
||||||
|
if let Some(geom) = next_geom_override {
|
||||||
|
current_position.get_geom_override(geom);
|
||||||
|
}
|
||||||
|
resize_pty!(current_position, self.os_api);
|
||||||
|
current_position.set_should_render(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn move_active_pane_right(&mut self) {
|
||||||
|
if !self.has_selectable_panes() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if self.fullscreen_is_active {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if let Some(active) = self.get_active_pane() {
|
||||||
|
let terminals = self.get_selectable_panes();
|
||||||
|
let next_index = terminals
|
||||||
|
.enumerate()
|
||||||
|
.filter(|(_, (_, c))| {
|
||||||
|
c.is_directly_right_of(active) && c.horizontally_overlaps_with(active)
|
||||||
|
})
|
||||||
|
.max_by_key(|(_, (_, c))| c.active_at())
|
||||||
|
.map(|(_, (pid, _))| pid);
|
||||||
|
if let Some(&p) = next_index {
|
||||||
|
let current_position = self.panes.get(&self.active_terminal.unwrap()).unwrap();
|
||||||
|
let prev_geom = current_position.position_and_size();
|
||||||
|
let prev_geom_override = current_position.geom_override();
|
||||||
|
|
||||||
|
let new_position = self.panes.get_mut(&p).unwrap();
|
||||||
|
let next_geom = new_position.position_and_size();
|
||||||
|
let next_geom_override = new_position.geom_override();
|
||||||
|
new_position.set_geom(prev_geom);
|
||||||
|
if let Some(geom) = prev_geom_override {
|
||||||
|
new_position.get_geom_override(geom);
|
||||||
|
}
|
||||||
|
resize_pty!(new_position, self.os_api);
|
||||||
|
new_position.set_should_render(true);
|
||||||
|
|
||||||
|
let current_position = self.panes.get_mut(&self.active_terminal.unwrap()).unwrap();
|
||||||
|
current_position.set_geom(next_geom);
|
||||||
|
if let Some(geom) = next_geom_override {
|
||||||
|
current_position.get_geom_override(geom);
|
||||||
|
}
|
||||||
|
resize_pty!(current_position, self.os_api);
|
||||||
|
current_position.set_should_render(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn move_active_pane_left(&mut self) {
|
||||||
|
if !self.has_selectable_panes() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if self.fullscreen_is_active {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if let Some(active) = self.get_active_pane() {
|
||||||
|
let terminals = self.get_selectable_panes();
|
||||||
|
let next_index = terminals
|
||||||
|
.enumerate()
|
||||||
|
.filter(|(_, (_, c))| {
|
||||||
|
c.is_directly_left_of(active) && c.horizontally_overlaps_with(active)
|
||||||
|
})
|
||||||
|
.max_by_key(|(_, (_, c))| c.active_at())
|
||||||
|
.map(|(_, (pid, _))| pid);
|
||||||
|
if let Some(&p) = next_index {
|
||||||
|
let current_position = self.panes.get(&self.active_terminal.unwrap()).unwrap();
|
||||||
|
let prev_geom = current_position.position_and_size();
|
||||||
|
let prev_geom_override = current_position.geom_override();
|
||||||
|
|
||||||
|
let new_position = self.panes.get_mut(&p).unwrap();
|
||||||
|
let next_geom = new_position.position_and_size();
|
||||||
|
let next_geom_override = new_position.geom_override();
|
||||||
|
new_position.set_geom(prev_geom);
|
||||||
|
if let Some(geom) = prev_geom_override {
|
||||||
|
new_position.get_geom_override(geom);
|
||||||
|
}
|
||||||
|
resize_pty!(new_position, self.os_api);
|
||||||
|
new_position.set_should_render(true);
|
||||||
|
|
||||||
|
let current_position = self.panes.get_mut(&self.active_terminal.unwrap()).unwrap();
|
||||||
|
current_position.set_geom(next_geom);
|
||||||
|
if let Some(geom) = next_geom_override {
|
||||||
|
current_position.get_geom_override(geom);
|
||||||
|
}
|
||||||
|
resize_pty!(current_position, self.os_api);
|
||||||
|
current_position.set_should_render(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
fn horizontal_borders(&self, terminals: &[PaneId]) -> HashSet<usize> {
|
fn horizontal_borders(&self, terminals: &[PaneId]) -> HashSet<usize> {
|
||||||
terminals.iter().fold(HashSet::new(), |mut borders, t| {
|
terminals.iter().fold(HashSet::new(), |mut borders, t| {
|
||||||
let terminal = self.panes.get(t).unwrap();
|
let terminal = self.panes.get(t).unwrap();
|
||||||
|
|
|
||||||
|
|
@ -2525,6 +2525,244 @@ pub fn move_focus_right_to_the_most_recently_used_pane() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn move_active_pane_down() {
|
||||||
|
let size = Size {
|
||||||
|
cols: 121,
|
||||||
|
rows: 20,
|
||||||
|
};
|
||||||
|
let mut tab = create_new_tab(size);
|
||||||
|
let new_pane_id = PaneId::Terminal(2);
|
||||||
|
|
||||||
|
tab.horizontal_split(new_pane_id);
|
||||||
|
tab.move_focus_up();
|
||||||
|
tab.move_active_pane_down();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
tab.get_active_pane().unwrap().y(),
|
||||||
|
10,
|
||||||
|
"Active pane is the bottom one"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
tab.get_active_pane().unwrap().pid(),
|
||||||
|
PaneId::Terminal(1),
|
||||||
|
"Active pane is the bottom one"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn move_active_pane_down_to_the_most_recently_used_position() {
|
||||||
|
let size = Size {
|
||||||
|
cols: 121,
|
||||||
|
rows: 20,
|
||||||
|
};
|
||||||
|
let mut tab = create_new_tab(size);
|
||||||
|
let new_pane_id_1 = PaneId::Terminal(2);
|
||||||
|
let new_pane_id_2 = PaneId::Terminal(3);
|
||||||
|
let new_pane_id_3 = PaneId::Terminal(4);
|
||||||
|
|
||||||
|
tab.horizontal_split(new_pane_id_1);
|
||||||
|
tab.vertical_split(new_pane_id_2);
|
||||||
|
tab.vertical_split(new_pane_id_3);
|
||||||
|
tab.move_focus_up();
|
||||||
|
tab.move_active_pane_down();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
tab.get_active_pane().unwrap().y(),
|
||||||
|
10,
|
||||||
|
"Active pane y position"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
tab.get_active_pane().unwrap().x(),
|
||||||
|
91,
|
||||||
|
"Active pane x position"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
tab.get_active_pane().unwrap().pid(),
|
||||||
|
PaneId::Terminal(1),
|
||||||
|
"Active pane PaneId"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn move_active_pane_up() {
|
||||||
|
let size = Size {
|
||||||
|
cols: 121,
|
||||||
|
rows: 20,
|
||||||
|
};
|
||||||
|
let mut tab = create_new_tab(size);
|
||||||
|
let new_pane_id = PaneId::Terminal(2);
|
||||||
|
|
||||||
|
tab.horizontal_split(new_pane_id);
|
||||||
|
tab.move_active_pane_up();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
tab.get_active_pane().unwrap().y(),
|
||||||
|
0,
|
||||||
|
"Active pane is the top one"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
tab.get_active_pane().unwrap().pid(),
|
||||||
|
PaneId::Terminal(2),
|
||||||
|
"Active pane is the top one"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn move_active_pane_up_to_the_most_recently_used_position() {
|
||||||
|
let size = Size {
|
||||||
|
cols: 121,
|
||||||
|
rows: 20,
|
||||||
|
};
|
||||||
|
let mut tab = create_new_tab(size);
|
||||||
|
let new_pane_id_1 = PaneId::Terminal(2);
|
||||||
|
let new_pane_id_2 = PaneId::Terminal(3);
|
||||||
|
let new_pane_id_3 = PaneId::Terminal(4);
|
||||||
|
|
||||||
|
tab.horizontal_split(new_pane_id_1);
|
||||||
|
tab.move_focus_up();
|
||||||
|
tab.vertical_split(new_pane_id_2);
|
||||||
|
tab.vertical_split(new_pane_id_3);
|
||||||
|
tab.move_focus_down();
|
||||||
|
tab.move_active_pane_up();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
tab.get_active_pane().unwrap().y(),
|
||||||
|
0,
|
||||||
|
"Active pane y position"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
tab.get_active_pane().unwrap().x(),
|
||||||
|
91,
|
||||||
|
"Active pane x position"
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
tab.get_active_pane().unwrap().pid(),
|
||||||
|
PaneId::Terminal(2),
|
||||||
|
"Active pane PaneId"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn move_active_pane_left() {
|
||||||
|
let size = Size {
|
||||||
|
cols: 121,
|
||||||
|
rows: 20,
|
||||||
|
};
|
||||||
|
let mut tab = create_new_tab(size);
|
||||||
|
let new_pane_id = PaneId::Terminal(2);
|
||||||
|
|
||||||
|
tab.vertical_split(new_pane_id);
|
||||||
|
tab.move_active_pane_left();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
tab.get_active_pane().unwrap().x(),
|
||||||
|
0,
|
||||||
|
"Active pane is the left one"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
tab.get_active_pane().unwrap().pid(),
|
||||||
|
PaneId::Terminal(2),
|
||||||
|
"Active pane is the left one"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn move_active_pane_left_to_the_most_recently_used_position() {
|
||||||
|
let size = Size {
|
||||||
|
cols: 121,
|
||||||
|
rows: 20,
|
||||||
|
};
|
||||||
|
let mut tab = create_new_tab(size);
|
||||||
|
let new_pane_id_1 = PaneId::Terminal(2);
|
||||||
|
let new_pane_id_2 = PaneId::Terminal(3);
|
||||||
|
let new_pane_id_3 = PaneId::Terminal(4);
|
||||||
|
|
||||||
|
tab.vertical_split(new_pane_id_1);
|
||||||
|
tab.move_focus_left();
|
||||||
|
tab.horizontal_split(new_pane_id_2);
|
||||||
|
tab.horizontal_split(new_pane_id_3);
|
||||||
|
tab.move_focus_right();
|
||||||
|
tab.move_active_pane_left();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
tab.get_active_pane().unwrap().y(),
|
||||||
|
15,
|
||||||
|
"Active pane y position"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
tab.get_active_pane().unwrap().x(),
|
||||||
|
0,
|
||||||
|
"Active pane x position"
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
tab.get_active_pane().unwrap().pid(),
|
||||||
|
PaneId::Terminal(2),
|
||||||
|
"Active pane PaneId"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn move_active_pane_right() {
|
||||||
|
let size = Size {
|
||||||
|
cols: 121,
|
||||||
|
rows: 20,
|
||||||
|
};
|
||||||
|
let mut tab = create_new_tab(size);
|
||||||
|
let new_pane_id = PaneId::Terminal(2);
|
||||||
|
|
||||||
|
tab.vertical_split(new_pane_id);
|
||||||
|
tab.move_focus_left();
|
||||||
|
tab.move_active_pane_right();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
tab.get_active_pane().unwrap().x(),
|
||||||
|
61,
|
||||||
|
"Active pane is the right one"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
tab.get_active_pane().unwrap().pid(),
|
||||||
|
PaneId::Terminal(1),
|
||||||
|
"Active pane is the right one"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn move_active_pane_right_to_the_most_recently_used_position() {
|
||||||
|
let size = Size {
|
||||||
|
cols: 121,
|
||||||
|
rows: 20,
|
||||||
|
};
|
||||||
|
let mut tab = create_new_tab(size);
|
||||||
|
let new_pane_id_1 = PaneId::Terminal(2);
|
||||||
|
let new_pane_id_2 = PaneId::Terminal(3);
|
||||||
|
let new_pane_id_3 = PaneId::Terminal(4);
|
||||||
|
|
||||||
|
tab.vertical_split(new_pane_id_1);
|
||||||
|
tab.horizontal_split(new_pane_id_2);
|
||||||
|
tab.horizontal_split(new_pane_id_3);
|
||||||
|
tab.move_focus_left();
|
||||||
|
tab.move_active_pane_right();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
tab.get_active_pane().unwrap().y(),
|
||||||
|
15,
|
||||||
|
"Active pane y position"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
tab.get_active_pane().unwrap().x(),
|
||||||
|
61,
|
||||||
|
"Active pane x position"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
tab.get_active_pane().unwrap().pid(),
|
||||||
|
PaneId::Terminal(1),
|
||||||
|
"Active pane Paneid"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn resize_down_with_pane_above() {
|
pub fn resize_down_with_pane_above() {
|
||||||
// ┌───────────┐ ┌───────────┐
|
// ┌───────────┐ ┌───────────┐
|
||||||
|
|
|
||||||
|
|
@ -81,6 +81,9 @@ pub enum InputMode {
|
||||||
/// `Session` mode allows detaching sessions
|
/// `Session` mode allows detaching sessions
|
||||||
#[serde(alias = "session")]
|
#[serde(alias = "session")]
|
||||||
Session,
|
Session,
|
||||||
|
/// `Move` mode allows moving the different existing panes within a tab
|
||||||
|
#[serde(alias = "move")]
|
||||||
|
Move,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for InputMode {
|
impl Default for InputMode {
|
||||||
|
|
@ -124,6 +127,7 @@ impl FromStr for InputMode {
|
||||||
"scroll" => Ok(InputMode::Scroll),
|
"scroll" => Ok(InputMode::Scroll),
|
||||||
"renametab" => Ok(InputMode::RenameTab),
|
"renametab" => Ok(InputMode::RenameTab),
|
||||||
"session" => Ok(InputMode::Session),
|
"session" => Ok(InputMode::Session),
|
||||||
|
"move" => Ok(InputMode::Move),
|
||||||
e => Err(e.to_string().into()),
|
e => Err(e.to_string().into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,8 @@ keybinds:
|
||||||
key: [Ctrl: 's',]
|
key: [Ctrl: 's',]
|
||||||
- action: [SwitchToMode: Session,]
|
- action: [SwitchToMode: Session,]
|
||||||
key: [Ctrl: 'o',]
|
key: [Ctrl: 'o',]
|
||||||
|
- action: [SwitchToMode: Move,]
|
||||||
|
key: [Ctrl: 'h',]
|
||||||
- action: [Quit,]
|
- action: [Quit,]
|
||||||
key: [Ctrl: 'q',]
|
key: [Ctrl: 'q',]
|
||||||
- action: [NewPane: ]
|
- action: [NewPane: ]
|
||||||
|
|
@ -52,6 +54,8 @@ keybinds:
|
||||||
key: [Ctrl: 's']
|
key: [Ctrl: 's']
|
||||||
- action: [SwitchToMode: Session,]
|
- action: [SwitchToMode: Session,]
|
||||||
key: [Ctrl: 'o',]
|
key: [Ctrl: 'o',]
|
||||||
|
- action: [SwitchToMode: Move,]
|
||||||
|
key: [Ctrl: 'h',]
|
||||||
- action: [Quit]
|
- action: [Quit]
|
||||||
key: [Ctrl: 'q']
|
key: [Ctrl: 'q']
|
||||||
- action: [Resize: Left,]
|
- action: [Resize: Left,]
|
||||||
|
|
@ -89,6 +93,8 @@ keybinds:
|
||||||
key: [Ctrl: 's']
|
key: [Ctrl: 's']
|
||||||
- action: [SwitchToMode: Session,]
|
- action: [SwitchToMode: Session,]
|
||||||
key: [Ctrl: 'o',]
|
key: [Ctrl: 'o',]
|
||||||
|
- action: [SwitchToMode: Move,]
|
||||||
|
key: [Ctrl: 'h',]
|
||||||
- action: [Quit,]
|
- action: [Quit,]
|
||||||
key: [Ctrl: 'q',]
|
key: [Ctrl: 'q',]
|
||||||
- action: [MoveFocus: Left,]
|
- action: [MoveFocus: Left,]
|
||||||
|
|
@ -117,6 +123,45 @@ keybinds:
|
||||||
key: [ Alt: '[',]
|
key: [ Alt: '[',]
|
||||||
- action: [FocusNextPane,]
|
- action: [FocusNextPane,]
|
||||||
key: [ Alt: ']',]
|
key: [ Alt: ']',]
|
||||||
|
move:
|
||||||
|
- action: [SwitchToMode: Locked,]
|
||||||
|
key: [Ctrl: 'g']
|
||||||
|
- action: [SwitchToMode: Pane,]
|
||||||
|
key: [Ctrl: 'p',]
|
||||||
|
- action: [SwitchToMode: Tab,]
|
||||||
|
key: [Ctrl: 't',]
|
||||||
|
- action: [SwitchToMode: Resize,]
|
||||||
|
key: [Ctrl: 'n',]
|
||||||
|
- action: [SwitchToMode: Normal,]
|
||||||
|
key: [Ctrl: 'h', Char: "\n", Char: ' ',]
|
||||||
|
- action: [SwitchToMode: Scroll,]
|
||||||
|
key: [Ctrl: 's']
|
||||||
|
- action: [SwitchToMode: Session,]
|
||||||
|
key: [Ctrl: 'o',]
|
||||||
|
- action: [Quit]
|
||||||
|
key: [Ctrl: 'q']
|
||||||
|
- action: [MovePane: Left,]
|
||||||
|
key: [Char: 'h', Left,]
|
||||||
|
- action: [MovePane: Down,]
|
||||||
|
key: [Char: 'j', Down,]
|
||||||
|
- action: [MovePane: Up,]
|
||||||
|
key: [Char: 'k', Up, ]
|
||||||
|
- action: [MovePane: Right,]
|
||||||
|
key: [Char: 'l', Right,]
|
||||||
|
- action: [NewPane: ,]
|
||||||
|
key: [ Alt: 'n',]
|
||||||
|
- action: [MoveFocus: Left,]
|
||||||
|
key: [ Alt: 'h',]
|
||||||
|
- action: [MoveFocus: Right,]
|
||||||
|
key: [ Alt: 'l',]
|
||||||
|
- action: [MoveFocus: Down,]
|
||||||
|
key: [ Alt: 'j',]
|
||||||
|
- action: [MoveFocus: Up,]
|
||||||
|
key: [ Alt: 'k',]
|
||||||
|
- action: [FocusPreviousPane,]
|
||||||
|
key: [ Alt: '[',]
|
||||||
|
- action: [FocusNextPane,]
|
||||||
|
key: [ Alt: ']',]
|
||||||
tab:
|
tab:
|
||||||
- action: [SwitchToMode: Locked,]
|
- action: [SwitchToMode: Locked,]
|
||||||
key: [Ctrl: 'g']
|
key: [Ctrl: 'g']
|
||||||
|
|
@ -128,6 +173,8 @@ keybinds:
|
||||||
key: [Ctrl: 't', Char: "\n", Char: ' ',]
|
key: [Ctrl: 't', Char: "\n", Char: ' ',]
|
||||||
- action: [SwitchToMode: Scroll,]
|
- action: [SwitchToMode: Scroll,]
|
||||||
key: [Ctrl: 's']
|
key: [Ctrl: 's']
|
||||||
|
- action: [SwitchToMode: Move,]
|
||||||
|
key: [Ctrl: 'h',]
|
||||||
- action: [SwitchToMode: Session,]
|
- action: [SwitchToMode: Session,]
|
||||||
key: [Ctrl: 'o',]
|
key: [Ctrl: 'o',]
|
||||||
- action: [SwitchToMode: RenameTab, TabNameInput: [0],]
|
- action: [SwitchToMode: RenameTab, TabNameInput: [0],]
|
||||||
|
|
@ -186,6 +233,8 @@ keybinds:
|
||||||
key: [Ctrl: 'g',]
|
key: [Ctrl: 'g',]
|
||||||
- action: [SwitchToMode: Pane,]
|
- action: [SwitchToMode: Pane,]
|
||||||
key: [Ctrl: 'p',]
|
key: [Ctrl: 'p',]
|
||||||
|
- action: [SwitchToMode: Move,]
|
||||||
|
key: [Ctrl: 'h',]
|
||||||
- action: [SwitchToMode: Session,]
|
- action: [SwitchToMode: Session,]
|
||||||
key: [Ctrl: 'o',]
|
key: [Ctrl: 'o',]
|
||||||
- action: [SwitchToMode: Resize,]
|
- action: [SwitchToMode: Resize,]
|
||||||
|
|
@ -244,6 +293,8 @@ keybinds:
|
||||||
key: [Ctrl: 'n',]
|
key: [Ctrl: 'n',]
|
||||||
- action: [SwitchToMode: Pane,]
|
- action: [SwitchToMode: Pane,]
|
||||||
key: [Ctrl: 'p',]
|
key: [Ctrl: 'p',]
|
||||||
|
- action: [SwitchToMode: Move,]
|
||||||
|
key: [Ctrl: 'h',]
|
||||||
- action: [SwitchToMode: Tab,]
|
- action: [SwitchToMode: Tab,]
|
||||||
key: [Ctrl: 't',]
|
key: [Ctrl: 't',]
|
||||||
- action: [SwitchToMode: Normal,]
|
- action: [SwitchToMode: Normal,]
|
||||||
|
|
|
||||||
|
|
@ -226,6 +226,10 @@ pub enum ScreenContext {
|
||||||
MoveFocusUp,
|
MoveFocusUp,
|
||||||
MoveFocusRight,
|
MoveFocusRight,
|
||||||
MoveFocusRightOrNextTab,
|
MoveFocusRightOrNextTab,
|
||||||
|
MovePaneDown,
|
||||||
|
MovePaneUp,
|
||||||
|
MovePaneRight,
|
||||||
|
MovePaneLeft,
|
||||||
Exit,
|
Exit,
|
||||||
ScrollUp,
|
ScrollUp,
|
||||||
ScrollUpAt,
|
ScrollUpAt,
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@ pub enum Action {
|
||||||
/// Tries to move the focus pane in specified direction.
|
/// Tries to move the focus pane in specified direction.
|
||||||
/// If there is no pane in the direction, move to previous/next Tab.
|
/// If there is no pane in the direction, move to previous/next Tab.
|
||||||
MoveFocusOrTab(Direction),
|
MoveFocusOrTab(Direction),
|
||||||
|
MovePane(Direction),
|
||||||
/// Scroll up in focus pane.
|
/// Scroll up in focus pane.
|
||||||
ScrollUp,
|
ScrollUp,
|
||||||
/// Scroll up at point
|
/// Scroll up at point
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ pub fn get_mode_info(
|
||||||
let keybinds = match mode {
|
let keybinds = match mode {
|
||||||
InputMode::Normal | InputMode::Locked => Vec::new(),
|
InputMode::Normal | InputMode::Locked => Vec::new(),
|
||||||
InputMode::Resize => vec![("←↓↑→".to_string(), "Resize".to_string())],
|
InputMode::Resize => vec![("←↓↑→".to_string(), "Resize".to_string())],
|
||||||
|
InputMode::Move => vec![("←↓↑→".to_string(), "Move".to_string())],
|
||||||
InputMode::Pane => vec![
|
InputMode::Pane => vec![
|
||||||
("←↓↑→".to_string(), "Move focus".to_string()),
|
("←↓↑→".to_string(), "Move focus".to_string()),
|
||||||
("p".to_string(), "Next".to_string()),
|
("p".to_string(), "Next".to_string()),
|
||||||
|
|
|
||||||
|
|
@ -378,7 +378,7 @@ fn unbind_multiple_keybinds_all_modes() {
|
||||||
let result_normal_2 = mode_keybinds_normal
|
let result_normal_2 = mode_keybinds_normal
|
||||||
.expect("ModeKeybinds shouldn't be empty")
|
.expect("ModeKeybinds shouldn't be empty")
|
||||||
.0
|
.0
|
||||||
.get(&Key::Ctrl('h'));
|
.get(&Key::Ctrl('f'));
|
||||||
let result_resize_1 = mode_keybinds_resize
|
let result_resize_1 = mode_keybinds_resize
|
||||||
.expect("ModeKeybinds shouldn't be empty")
|
.expect("ModeKeybinds shouldn't be empty")
|
||||||
.0
|
.0
|
||||||
|
|
@ -386,7 +386,7 @@ fn unbind_multiple_keybinds_all_modes() {
|
||||||
let result_resize_2 = mode_keybinds_resize
|
let result_resize_2 = mode_keybinds_resize
|
||||||
.expect("ModeKeybinds shouldn't be empty")
|
.expect("ModeKeybinds shouldn't be empty")
|
||||||
.0
|
.0
|
||||||
.get(&Key::Ctrl('h'));
|
.get(&Key::Ctrl('f'));
|
||||||
assert!(result_normal_1.is_none());
|
assert!(result_normal_1.is_none());
|
||||||
assert!(result_resize_1.is_none());
|
assert!(result_resize_1.is_none());
|
||||||
assert!(result_normal_2.is_none());
|
assert!(result_normal_2.is_none());
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue