Skip to content

Commit

Permalink
Add support for pane swapping in Key Assignment and Lua API.
Browse files Browse the repository at this point in the history
Adds a couple of variants:
- SwapActivePaneDirection / tab:swap_active_pane_direction
  analogous to ActivatePaneDirection.
- SwapActivePaneByIndex / tab:swap_active_pane_by_index
  analogous to ActivatePaneByIndex.
  • Loading branch information
bogdan2412 committed Aug 19, 2024
1 parent 986eac2 commit 7384a83
Show file tree
Hide file tree
Showing 8 changed files with 390 additions and 5 deletions.
16 changes: 16 additions & 0 deletions config/src/keyassignment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,20 @@ impl PaneDirection {
}
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, FromDynamic, ToDynamic)]
pub struct SwapActivePaneDirectionArguments {
pub direction: PaneDirection,
pub keep_focus: bool,
}
impl_lua_conversion_dynamic!(SwapActivePaneDirectionArguments);

#[derive(Debug, Clone, Copy, PartialEq, Eq, FromDynamic, ToDynamic)]
pub struct SwapActivePaneWithIndexArguments {
pub pane_index: usize,
pub keep_focus: bool,
}
impl_lua_conversion_dynamic!(SwapActivePaneWithIndexArguments);

#[derive(Debug, Copy, Clone, PartialEq, Eq, FromDynamic, ToDynamic, Serialize, Deserialize)]
pub enum ScrollbackEraseMode {
ScrollbackOnly,
Expand Down Expand Up @@ -566,6 +580,8 @@ pub enum KeyAssignment {
AdjustPaneSize(PaneDirection, usize),
ActivatePaneDirection(PaneDirection),
ActivatePaneByIndex(usize),
SwapActivePaneDirection(SwapActivePaneDirectionArguments),
SwapActivePaneWithIndex(SwapActivePaneWithIndexArguments),
TogglePaneZoomState,
SetPaneZoomState(bool),
CloseCurrentPane {
Expand Down
52 changes: 52 additions & 0 deletions docs/config/lua/MuxTab/swap_active_pane_direction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# `tab:swap_active_pane_direction{ direction, keep_focus }`

{{since('nightly')}}

Swaps the active pane with the pane adjacent to it in the direction *direction*.
If *keep_focus* is true, focus is retained on the currently active pane but in its
new position.

Valid values for *direction* are:

* `"Left"`
* `"Right"`
* `"Up"`
* `"Down"`
* `"Prev"`
* `"Next"`

An example of usage is below:

```lua
local wezterm = require 'wezterm'
local config = {}

local function swap_active_pane_action(direction)
return wezterm.action_callback(function(_window, pane)
local tab = pane:tab()
if tab ~= nil then
tab:swap_active_pane_direction {
direction = direction,
keep_focus = true,
}
end
end)
end

config.keys = {
{
key = 'LeftArrow',
mods = 'CTRL|ALT',
action = swap_active_pane_action 'Prev',
},
{
key = 'RightArrow',
mods = 'CTRL|ALT',
action = swap_active_pane_action 'Next',
},
}
return config
```

See [ActivatePaneDirection](../keyassignment/ActivatePaneDirection.md) for more information
about how panes are selected given a direction.
10 changes: 10 additions & 0 deletions docs/config/lua/MuxTab/swap_active_pane_with_index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# `tab:swap_active_pane_with_index{ pane_index, keep_focus }`

{{since('nightly')}}

Swaps the active pane with the pane corresponding to *pane_index*.
If *keep_focus* is true, focus is retained on the currently active pane but in
its new position.

See [tab:panes_with_info](panes_with_info.md) for more information about how to
obtain pane indexes.
45 changes: 45 additions & 0 deletions docs/config/lua/keyassignment/SwapActivePaneDirection.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# `SwapActivePaneDirection`

{{since('nightly')}}

`SwapActivePaneDirection` swaps the active pane with the pane adjacent to it in
a specific direction.

See [ActivatePaneDirection](../keyassignment/ActivatePaneDirection.md) for more information
about how panes are selected given a direction.

The action requires two named arguments, *direction* and *keep_focus*.

If *keep_focus* is true, focus is retained on the currently active pane but in its
new position.

Valid values for *direction* are:

* `"Left"`
* `"Right"`
* `"Up"`
* `"Down"`
* `"Prev"`
* `"Next"`

An example of usage is below:

```lua
local wezterm = require 'wezterm'
local act = wezterm.action
local config = {}

config.keys = {
{
key = 'LeftArrow',
mods = 'CTRL|ALT',
action = act.SwapActivePaneDirection { direction = 'Prev', keep_focus = true },
},
{
key = 'RightArrow',
mods = 'CTRL|ALT',
action = act.SwapActivePaneDirection { direction = 'Next', keep_focus = true },
},
}
return config
```
35 changes: 35 additions & 0 deletions docs/config/lua/keyassignment/SwapActivePaneWithIndex.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# `SwapActivePaneWithIndex`

{{since('20220319-142410-0fcdea07')}}

`SwapActivePaneWithIndex` swaps the active pane with the pane with the specified
index within the current tab. Invalid indices are ignored.

This example causes CTRL-ALT-a, CTRL-ALT-b, CTRL-ALT-c to swap the current pane
with the 0th, 1st and 2nd panes, respectively:

```lua
local wezterm = require 'wezterm'
local act = wezterm.action
local config = {}

config.keys = {
{
key = 'a',
mods = 'CTRL|ALT',
action = act.SwapActivePaneWithIndex { pane_index = 0, keep_focus = true },
},
{
key = 'b',
mods = 'CTRL|ALT',
action = act.SwapActivePaneWithIndex { pane_index = 1, keep_focus = true },
},
{
key = 'c',
mods = 'CTRL|ALT',
action = act.SwapActivePaneWithIndex { pane_index = 2, keep_focus = true },
},
}

return config
```
58 changes: 57 additions & 1 deletion lua-api-crates/mux/src/tab.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use config::keyassignment::{PaneDirection, RotationDirection};
use config::keyassignment::{
PaneDirection, RotationDirection, SwapActivePaneDirectionArguments,
SwapActivePaneWithIndexArguments,
};

use super::*;
use luahelper::mlua::Value;
Expand Down Expand Up @@ -175,5 +178,58 @@ impl UserData for MuxTab {
}
Ok(())
});

methods.add_method("swap_active_pane_direction", |_, this, args: Value| {
let mux = get_mux()?;
let tab = this.resolve(&mux)?;

let SwapActivePaneDirectionArguments {
direction,
keep_focus,
} = from_lua(args)?;

if let (Some(active_pane), Some(with_pane_index)) = (
tab.get_active_pane(),
tab.get_pane_direction(direction, true),
) {
let active_pane_id = active_pane.pane_id();
promise::spawn::spawn(async move {
let mux = Mux::get();
if let Err(err) = mux
.swap_active_pane_with_index(active_pane_id, with_pane_index, keep_focus)
.await
{
log::error!("Unable to swap active pane in direction: {:#}", err);
}
})
.detach();
}
Ok(())
});

methods.add_method("swap_active_pane_with_index", |_, this, args: Value| {
let mux = get_mux()?;
let tab = this.resolve(&mux)?;

let SwapActivePaneWithIndexArguments {
pane_index,
keep_focus,
} = from_lua(args)?;

if let Some(active_pane) = tab.get_active_pane() {
let active_pane_id = active_pane.pane_id();
promise::spawn::spawn(async move {
let mux = Mux::get();
if let Err(err) = mux
.swap_active_pane_with_index(active_pane_id, pane_index, keep_focus)
.await
{
log::error!("Unable to swap active pane in direction: {:#}", err);
}
})
.detach();
}
Ok(())
});
}
}
112 changes: 109 additions & 3 deletions wezterm-gui/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1015,19 +1015,34 @@ pub fn derive_command_from_key_assignment(action: &KeyAssignment) -> Option<Comm
menubar: &["Window", "Select Tab"],
icon: None,
}
}
},
ActivatePaneByIndex(n) => {
let n = *n;
let ordinal = english_ordinal(n as isize);
CommandDef {
brief: format!("Activate {ordinal} Pane").into(),
doc: format!("Activates the {ordinal} Pane").into(),
keys: vec![],
args: &[ArgType::ActiveWindow],
args: &[ArgType::ActiveTab],
menubar: &[],
icon: None,
}
}
},
SwapActivePaneWithIndex(SwapActivePaneWithIndexArguments {
pane_index,
keep_focus
}) => {
let ordinal = english_ordinal(*pane_index as isize);
let with_focus = if *keep_focus { ", keeping focus" } else { "" };
CommandDef {
brief: format!("Swap active pane with {ordinal} pane{with_focus}").into(),
doc: format!("Swaps thhe active pane with the {ordinal} pane").into(),
keys: vec![],
args: &[ArgType::ActiveTab],
menubar: &[],
icon: None,
}
},
SetPaneZoomState(true) => CommandDef {
brief: format!("Zooms the current Pane").into(),
doc: format!(
Expand Down Expand Up @@ -1587,6 +1602,65 @@ pub fn derive_command_from_key_assignment(action: &KeyAssignment) -> Option<Comm
menubar: &["Window", "Select Pane"],
icon: Some("fa_long_arrow_down"),
},
SwapActivePaneDirection(SwapActivePaneDirectionArguments {
direction : PaneDirection::Next | PaneDirection::Prev, keep_focus : _
}) => return None,
SwapActivePaneDirection(SwapActivePaneDirectionArguments {
direction : PaneDirection::Left, keep_focus
}) => CommandDef {
brief: if *keep_focus {
"Swap active pane with left one".into()
} else {
"Swap active pane with left one, keeping focus".into()
},
doc: "Swaps the current pane with the pane to the left of it".into(),
keys: vec![],
args: &[ArgType::ActivePane],
menubar: &["Window", "Swap Pane"],
icon: None,
},
SwapActivePaneDirection(SwapActivePaneDirectionArguments {
direction : PaneDirection::Right, keep_focus
}) => CommandDef {
brief: if *keep_focus {
"Swap active pane with right one".into()
} else {
"Swap active pane with right one, keeping focus".into()
},
doc: "Swaps the current pane with the pane to the right of it".into(),
keys: vec![],
args: &[ArgType::ActivePane],
menubar: &["Window", "Swap Pane"],
icon: None,
},
SwapActivePaneDirection(SwapActivePaneDirectionArguments {
direction : PaneDirection::Up, keep_focus
}) => CommandDef {
brief: if *keep_focus {
"Swap active pane with upwards one".into()
} else {
"Swap active pane with upwards one, keeping focus".into()
},
doc: "Swaps the current pane with the pane to the top of it".into(),
keys: vec![],
args: &[ArgType::ActivePane],
menubar: &["Window", "Swap Pane"],
icon: None,
},
SwapActivePaneDirection(SwapActivePaneDirectionArguments {
direction : PaneDirection::Down, keep_focus
}) => CommandDef {
brief: if *keep_focus {
"Swap active pane with downwards one".into()
} else {
"Swap active pane with downwards one, keeping focus".into()
},
doc: "Swaps the current pane with the pane to the bottom of it".into(),
keys: vec![],
args: &[ArgType::ActivePane],
menubar: &["Window", "Swap Pane"],
icon: None,
},
TogglePaneZoomState => CommandDef {
brief: "Toggle Pane Zoom".into(),
doc: "Toggles the zoom state for the current pane".into(),
Expand Down Expand Up @@ -2129,6 +2203,38 @@ fn compute_default_actions() -> Vec<KeyAssignment> {
ActivatePaneDirection(PaneDirection::Right),
ActivatePaneDirection(PaneDirection::Up),
ActivatePaneDirection(PaneDirection::Down),
SwapActivePaneDirection(SwapActivePaneDirectionArguments {
direction: PaneDirection::Left,
keep_focus: false,
}),
SwapActivePaneDirection(SwapActivePaneDirectionArguments {
direction: PaneDirection::Right,
keep_focus: false,
}),
SwapActivePaneDirection(SwapActivePaneDirectionArguments {
direction: PaneDirection::Up,
keep_focus: false,
}),
SwapActivePaneDirection(SwapActivePaneDirectionArguments {
direction: PaneDirection::Down,
keep_focus: false,
}),
SwapActivePaneDirection(SwapActivePaneDirectionArguments {
direction: PaneDirection::Left,
keep_focus: true,
}),
SwapActivePaneDirection(SwapActivePaneDirectionArguments {
direction: PaneDirection::Right,
keep_focus: true,
}),
SwapActivePaneDirection(SwapActivePaneDirectionArguments {
direction: PaneDirection::Up,
keep_focus: true,
}),
SwapActivePaneDirection(SwapActivePaneDirectionArguments {
direction: PaneDirection::Down,
keep_focus: true,
}),
TogglePaneZoomState,
ActivateLastTab,
ShowLauncher,
Expand Down
Loading

0 comments on commit 7384a83

Please sign in to comment.