1
1
mirror of https://github.com/wez/wezterm.git synced 2024-12-24 13:52:55 +03:00

wezterm: add confirm parameter to CloseCurrentPane

When confirmation is enabled, a really basic overlay is
rendered over the top of the pane to request confirmation.

```lua
 action=wezterm.action{CloseCurrentPane={confirm=true}}

 action=wezterm.action{CloseCurrentPane={confirm=false}}
```

refs: https://github.com/wez/wezterm/issues/157
refs: https://github.com/wez/wezterm/issues/280
This commit is contained in:
Wez Furlong 2020-10-01 21:45:39 -07:00
parent f3bccc7d08
commit 1b9d561e56
5 changed files with 114 additions and 12 deletions

View File

@ -0,0 +1,60 @@
use crate::mux::tab::PaneId;
use crate::mux::window::WindowId;
use crate::mux::Mux;
use crate::termwiztermtab::TermWizTerminal;
use termwiz::color::ColorAttribute;
use termwiz::input::{InputEvent, KeyCode, KeyEvent};
use termwiz::surface::{Change, Position};
use termwiz::terminal::Terminal;
pub fn confirm_close_pane(
pane_id: PaneId,
mut term: TermWizTerminal,
mux_window_id: WindowId,
) -> anyhow::Result<()> {
term.set_raw_mode()?;
let changes = vec![
Change::ClearScreen(ColorAttribute::Default),
Change::CursorPosition {
x: Position::Absolute(0),
y: Position::Absolute(0),
},
Change::Text("Really kill this pane? [y/n]\r\n".to_string()),
];
term.render(&changes)?;
term.flush()?;
while let Ok(Some(event)) = term.poll_input(None) {
match event {
InputEvent::Key(KeyEvent {
key: KeyCode::Char('y'),
..
}) => {
promise::spawn::spawn_into_main_thread(async move {
let mux = Mux::get().unwrap();
let tab = match mux.get_active_tab_for_window(mux_window_id) {
Some(tab) => tab,
None => return,
};
tab.kill_pane(pane_id);
});
break;
}
InputEvent::Key(KeyEvent {
key: KeyCode::Char('n'),
..
})
| InputEvent::Key(KeyEvent {
key: KeyCode::Escape,
..
}) => {
break;
}
_ => {}
}
}
Ok(())
}

View File

@ -1,14 +1,16 @@
use crate::frontend::gui::termwindow::TermWindow;
use crate::mux::tab::{Pane, Tab, TabId};
use crate::mux::tab::{Pane, PaneId, Tab, TabId};
use crate::termwiztermtab::{allocate, TermWizTerminal};
use std::pin::Pin;
use std::rc::Rc;
mod confirm_close_pane;
mod copy;
mod launcher;
mod search;
mod tabnavigator;
pub use confirm_close_pane::confirm_close_pane;
pub use copy::CopyOverlay;
pub use launcher::launcher;
pub use search::SearchOverlay;
@ -40,3 +42,30 @@ where
(tw_tab, Box::pin(future))
}
pub fn start_overlay_pane<T, F>(
term_window: &TermWindow,
pane: &Rc<dyn Pane>,
func: F,
) -> (
Rc<dyn Pane>,
Pin<Box<dyn std::future::Future<Output = Option<anyhow::Result<T>>>>>,
)
where
T: Send + 'static,
F: Send + 'static + FnOnce(PaneId, TermWizTerminal) -> anyhow::Result<T>,
{
let pane_id = pane.pane_id();
let dims = pane.renderer().get_dimensions();
let (tw_term, tw_tab) = allocate(dims.cols.into(), dims.viewport_rows.into());
let window = term_window.window.clone().unwrap();
let future = promise::spawn::spawn_into_new_thread(move || {
let res = func(pane_id, tw_term);
TermWindow::schedule_cancel_overlay_for_pane(window, pane_id);
res
});
(tw_tab, Box::pin(future))
}

View File

@ -9,7 +9,8 @@ use crate::font::FontConfiguration;
use crate::frontend::activity::Activity;
use crate::frontend::front_end;
use crate::frontend::gui::overlay::{
launcher, start_overlay, tab_navigator, CopyOverlay, SearchOverlay,
confirm_close_pane, launcher, start_overlay, start_overlay_pane, tab_navigator, CopyOverlay,
SearchOverlay,
};
use crate::frontend::gui::scrollbar::*;
use crate::frontend::gui::selection::*;
@ -1855,7 +1856,7 @@ impl TermWindow {
}
}
CloseCurrentTab => self.close_current_tab(),
CloseCurrentPane => self.close_active_pane(),
CloseCurrentPane { confirm } => self.close_current_pane(*confirm),
Nop | DisableDefaultAssignment => {}
ReloadConfiguration => crate::config::reload(),
MoveTab(n) => self.move_tab(*n)?,
@ -2128,13 +2129,28 @@ impl TermWindow {
self.scaling_changed(self.dimensions, 1.);
}
fn close_active_pane(&mut self) {
fn close_current_pane(&mut self, confirm: bool) {
let mux_window_id = self.mux_window_id;
let mux = Mux::get().unwrap();
let tab = match mux.get_active_tab_for_window(self.mux_window_id) {
let tab = match mux.get_active_tab_for_window(mux_window_id) {
Some(tab) => tab,
None => return,
};
tab.kill_active_pane();
let pane = match tab.get_active_pane() {
Some(p) => p,
None => return,
};
let pane_id = pane.pane_id();
if confirm {
let (overlay, future) = start_overlay_pane(self, &pane, move |pane_id, term| {
confirm_close_pane(pane_id, term, mux_window_id)
});
self.assign_overlay_for_pane(pane_id, overlay);
promise::spawn::spawn(future);
} else {
tab.kill_pane(pane_id);
}
}
fn close_current_tab(&mut self) {

View File

@ -123,7 +123,7 @@ pub enum KeyAssignment {
AdjustPaneSize(PaneDirection, usize),
ActivatePaneDirection(PaneDirection),
TogglePaneZoomState,
CloseCurrentPane,
CloseCurrentPane { confirm: bool },
}
impl_lua_conversion!(KeyAssignment);

View File

@ -1156,11 +1156,8 @@ impl Tab {
self.remove_pane_if(|_, pane| pane.is_dead())
}
pub fn kill_active_pane(&self) -> bool {
let active_idx = *self.active.borrow();
let killed = self.remove_pane_if(|idx, _| idx == active_idx);
log::debug!("kill_active_pane: killed={}", killed);
killed
pub fn kill_pane(&self, pane_id: PaneId) -> bool {
self.remove_pane_if(|_, pane| pane.pane_id() == pane_id)
}
pub fn kill_panes_in_domain(&self, domain: DomainId) -> bool {