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

paneselect: add mode parameter and a mode for swapping panes

Extends the pane selector to allow:

```
wezterm --config 'keys={{key="p", mods="CTRL", action=wezterm.action{PaneSelect={mode="SwapWithActive"}}}}'
```

to swap the active pane with the selected pane.
Similar to https://wezfurlong.org/wezterm/config/lua/keyassignment/RotatePanes.html
except that only the active and the selected panes have their positions
adjusted.

refs: https://github.com/wez/wezterm/issues/1842
refs: https://github.com/wez/wezterm/issues/1975
This commit is contained in:
Wez Furlong 2022-05-24 22:48:34 -07:00
parent e114534bee
commit 2725559fc0
3 changed files with 103 additions and 17 deletions

View File

@ -264,11 +264,26 @@ impl Default for ClipboardPasteSource {
} }
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq, FromDynamic, ToDynamic)]
pub enum PaneSelectMode {
Activate,
SwapWithActive,
}
impl Default for PaneSelectMode {
fn default() -> Self {
Self::Activate
}
}
#[derive(Default, Debug, Clone, PartialEq, Eq, FromDynamic, ToDynamic)] #[derive(Default, Debug, Clone, PartialEq, Eq, FromDynamic, ToDynamic)]
pub struct PaneSelectArguments { pub struct PaneSelectArguments {
/// Overrides the main quick_select_alphabet config /// Overrides the main quick_select_alphabet config
#[dynamic(default)] #[dynamic(default)]
pub alphabet: String, pub alphabet: String,
#[dynamic(default)]
pub mode: PaneSelectMode,
} }
#[derive(Default, Debug, Clone, PartialEq, Eq, FromDynamic, ToDynamic)] #[derive(Default, Debug, Clone, PartialEq, Eq, FromDynamic, ToDynamic)]

View File

@ -1470,6 +1470,58 @@ impl Tab {
cell_dimensions(&*self.size.borrow()) cell_dimensions(&*self.size.borrow())
} }
/// Swap the active pane with the specified pane_index
pub fn swap_active_with_index(&self, pane_index: usize) -> Option<()> {
let active_idx = self.get_active_idx();
let mut pane = self.get_active_pane()?;
log::trace!(
"swap_active_with_index: pane_index {} active {}",
pane_index,
active_idx
);
{
let mut root = self.pane.borrow_mut();
let mut cursor = root.take().unwrap().cursor();
// locate the requested index
match cursor.go_to_nth_leaf(pane_index) {
Ok(c) => cursor = c,
Err(c) => {
log::trace!("didn't find pane {pane_index}");
root.replace(c.tree());
return None;
}
};
std::mem::swap(&mut pane, cursor.leaf_mut().unwrap());
// re-position to the root
cursor = cursor.tree().cursor();
// and now go and update the active idx
match cursor.go_to_nth_leaf(active_idx) {
Ok(c) => cursor = c,
Err(c) => {
root.replace(c.tree());
log::trace!("didn't find active {active_idx}");
return None;
}
};
std::mem::swap(&mut pane, cursor.leaf_mut().unwrap());
root.replace(cursor.tree());
// Advise the panes of their new sizes
let size = *self.size.borrow();
apply_sizes_from_splits(root.as_mut().unwrap(), &size);
}
// And update focus
self.advise_focus_change(Some(pane));
None
}
/// Computes the size of the pane that would result if the specified /// Computes the size of the pane that would result if the specified
/// pane was split in a particular direction. /// pane was split in a particular direction.
/// The intent is to call this prior to spawning the new pane so that /// The intent is to call this prior to spawning the new pane so that

View File

@ -7,7 +7,7 @@ use crate::termwindow::render::{
use crate::termwindow::DimensionContext; use crate::termwindow::DimensionContext;
use crate::utilsprites::RenderMetrics; use crate::utilsprites::RenderMetrics;
use crate::TermWindow; use crate::TermWindow;
use config::keyassignment::{KeyAssignment, PaneSelectArguments}; use config::keyassignment::{KeyAssignment, PaneSelectArguments, PaneSelectMode};
use config::{Dimension, TabBarColors}; use config::{Dimension, TabBarColors};
use mux::Mux; use mux::Mux;
use std::cell::{Ref, RefCell}; use std::cell::{Ref, RefCell};
@ -18,6 +18,7 @@ pub struct PaneSelector {
labels: RefCell<Vec<String>>, labels: RefCell<Vec<String>>,
selection: RefCell<String>, selection: RefCell<String>,
alphabet: String, alphabet: String,
mode: PaneSelectMode,
} }
impl PaneSelector { impl PaneSelector {
@ -32,6 +33,7 @@ impl PaneSelector {
labels: RefCell::new(vec![]), labels: RefCell::new(vec![]),
selection: RefCell::new(String::new()), selection: RefCell::new(String::new()),
alphabet, alphabet,
mode: args.mode,
} }
} }
@ -143,6 +145,38 @@ impl PaneSelector {
Ok((elements, labels)) Ok((elements, labels))
} }
fn perform_selection(
&self,
pane_index: usize,
term_window: &mut TermWindow,
) -> anyhow::Result<()> {
let mux = Mux::get().unwrap();
let tab = match mux.get_active_tab_for_window(term_window.mux_window_id) {
Some(tab) => tab,
None => return Ok(()),
};
let tab_id = tab.tab_id();
if term_window.tab_state(tab_id).overlay.is_none() {
let panes = tab.iter_panes();
match self.mode {
PaneSelectMode::Activate => {
if panes.iter().position(|p| p.index == pane_index).is_some() {
tab.set_active_idx(pane_index);
}
}
PaneSelectMode::SwapWithActive => {
tab.swap_active_with_index(pane_index);
}
}
}
term_window.cancel_modal();
Ok(())
}
} }
impl Modal for PaneSelector { impl Modal for PaneSelector {
@ -176,22 +210,7 @@ impl Modal for PaneSelector {
// and if we have a complete match, activate that pane // and if we have a complete match, activate that pane
if let Some(pane_index) = self.labels.borrow().iter().position(|s| s == &*selection) if let Some(pane_index) = self.labels.borrow().iter().position(|s| s == &*selection)
{ {
let mux = Mux::get().unwrap(); return self.perform_selection(pane_index, term_window);
let tab = match mux.get_active_tab_for_window(term_window.mux_window_id) {
Some(tab) => tab,
None => return Ok(()),
};
let tab_id = tab.tab_id();
if term_window.tab_state(tab_id).overlay.is_none() {
let panes = tab.iter_panes();
if panes.iter().position(|p| p.index == pane_index).is_some() {
tab.set_active_idx(pane_index);
}
}
term_window.cancel_modal();
} }
} }
(KeyCode::Backspace, KeyModifiers::NONE) => { (KeyCode::Backspace, KeyModifiers::NONE) => {