1
1
mirror of https://github.com/wez/wezterm.git synced 2024-12-23 13:21:38 +03:00

Add RotatePanes key assignment

This commit is contained in:
Wez Furlong 2022-05-21 17:08:49 -07:00
parent da7da888cd
commit d2d4257f79
6 changed files with 168 additions and 1 deletions

View File

@ -459,6 +459,40 @@ impl<L, N> Cursor<L, N> {
}
}
/// Move the current position to the next in a postorder traversal.
/// Returns the modified cursor position.
///
/// In the case where there are no more nodes in the postorder traversal,
/// yields `Err` with the newly adjusted cursor; calling `postorder_next`
/// after it has yielded `Err` can potentially yield `Ok` with previously
/// visited nodes, so the caller must take care to stop iterating when
/// `Err` is received!
pub fn postorder_next(mut self) -> Result<Self, Self> {
// Since we are a "proper" binary tree, we know we cannot have
// difficult cases such as a left without a right or vice versa.
if self.is_leaf() {
if self.is_right() {
return self.go_up()?.go_left();
}
// while (We were on the left)
loop {
self = self.go_up()?;
if self.is_top() {
return Err(self);
}
if self.is_right() {
return self.go_up()?.go_left();
}
}
} else {
self.go_right()
}
}
/// Move to the nth (preorder) leaf from the current position.
pub fn go_to_nth_leaf(mut self, n: usize) -> Result<Self, Self> {
let mut next = 0;

View File

@ -370,9 +370,16 @@ pub enum KeyAssignment {
AttachDomain(String),
CopyMode(CopyModeAssignment),
RotatePanes(RotationDirection),
}
impl_lua_conversion_dynamic!(KeyAssignment);
#[derive(Debug, Clone, PartialEq, Eq, FromDynamic, ToDynamic)]
pub enum RotationDirection {
Clockwise,
CounterClockwise,
}
#[derive(Debug, Clone, PartialEq, Eq, FromDynamic, ToDynamic)]
pub enum CopyModeAssignment {
MoveToViewportBottom,

View File

@ -34,6 +34,7 @@ As features stabilize some brief notes about them will accumulate here.
* In the Launcher Menu, you may now use `CTRL-G` to cancel/exit the launcher [#1977](https://github.com/wez/wezterm/issues/1977)
* [cell_width](config/lua/config/cell_width.md) option to adjust the horizontal spacing when the availble font stretches are insufficient. [#1979](https://github.com/wez/wezterm/issues/1979)
* [min_scroll_bar_height](config/lua/config/min_scroll_bar_height.md) to control the minimum size of the scroll bar thumb [#1936](https://github.com/wez/wezterm/issues/1936)
* [RotatePanes](config/lua/keyassignment/RotatePanes.md) key assignment for re-arranging the panes in a tab
#### Updated

View File

@ -0,0 +1,50 @@
# RotatePanes
*Since: nightly builds only*
Rotates the sequence of panes within the active tab, preserving the sizes based on the tab positions.
Panes within a tab have an ordering that follows the creation order of the splits.
As an example, if you have three panes created in sequence using horizontal
splits, their indices from left to right are `0, 1, 2`:
```
|--------|----|----|
| 0 | 1 | 2 |
|--------|----|----|
```
If you perform a clockwise rotation on that tab, the indices are rearranged
so that the panes are now `2, 0, 1`.
```
|--------|----|----|
| 2 | 0 | 1 |
|--------|----|----|
```
If you instead perform a counter-clockwise rotation then the indices are rearranged
so that the panes are now `1, 2, 0`
```
|--------|----|----|
| 1 | 2 | 0 |
|--------|----|----|
```
The sizes of original positions are preserved; as you can see from the examples
above, the left-most pane is still the largest of the panes despite rotating
the panes withing those placements.
```lua
local wezterm = require 'wezterm'
return {
keys = {
{key="b", mods="CTRL", action=wezterm.action{RotatePanes="CounterClockwise"}},
{key="n", mods="CTRL", action=wezterm.action{RotatePanes="Clockwise"}},
},
}
```

View File

@ -594,6 +594,70 @@ impl Tab {
self.iter_panes_impl(false)
}
pub fn rotate_counter_clockwise(&self) {
let panes = self.iter_panes_ignoring_zoom();
if panes.is_empty() {
// Shouldn't happen, but we check for this here so that the
// expect below cannot trigger a panic
return;
}
let mut pane_to_swap = panes
.first()
.map(|p| p.pane.clone())
.expect("at least one pane");
let mut root = self.pane.borrow_mut();
let mut cursor = root.take().unwrap().cursor();
loop {
if cursor.is_leaf() {
std::mem::swap(&mut pane_to_swap, cursor.leaf_mut().unwrap());
}
match cursor.postorder_next() {
Ok(c) => cursor = c,
Err(c) => {
root.replace(c.tree());
let size = *self.size.borrow();
apply_sizes_from_splits(root.as_mut().unwrap(), &size);
break;
}
}
}
}
pub fn rotate_clockwise(&self) {
let panes = self.iter_panes_ignoring_zoom();
if panes.is_empty() {
// Shouldn't happen, but we check for this here so that the
// expect below cannot trigger a panic
return;
}
let mut pane_to_swap = panes
.last()
.map(|p| p.pane.clone())
.expect("at least one pane");
let mut root = self.pane.borrow_mut();
let mut cursor = root.take().unwrap().cursor();
loop {
if cursor.is_leaf() {
std::mem::swap(&mut pane_to_swap, cursor.leaf_mut().unwrap());
}
match cursor.preorder_next() {
Ok(c) => cursor = c,
Err(c) => {
root.replace(c.tree());
let size = *self.size.borrow();
apply_sizes_from_splits(root.as_mut().unwrap(), &size);
break;
}
}
}
}
fn iter_panes_impl(&self, respect_zoom_state: bool) -> Vec<PositionedPane> {
let mut panes = vec![];

View File

@ -23,7 +23,7 @@ use ::window::*;
use anyhow::{anyhow, ensure, Context};
use config::keyassignment::{
ClipboardCopyDestination, ClipboardPasteSource, KeyAssignment, Pattern, QuickSelectArguments,
SpawnCommand,
RotationDirection, SpawnCommand,
};
use config::{
configuration, AudibleBell, ConfigHandle, Dimension, DimensionContext, GradientOrientation,
@ -2477,6 +2477,17 @@ impl TermWindow {
CopyMode(_) => {
// NOP here; handled by the overlay directly
}
RotatePanes(direction) => {
let mux = Mux::get().unwrap();
let tab = match mux.get_active_tab_for_window(self.mux_window_id) {
Some(tab) => tab,
None => return Ok(()),
};
match direction {
RotationDirection::Clockwise => tab.rotate_clockwise(),
RotationDirection::CounterClockwise => tab.rotate_counter_clockwise(),
}
}
};
Ok(())
}