1
1
mirror of https://github.com/wez/wezterm.git synced 2024-11-23 15:04:36 +03:00

wezterm: tidy up pane/tab/window killing, resize boundaries

This should make closing panes more consistent and reliable;
there were some cases where we wouldn't always terminate the
associated process and this improves that.

There are also some resize boundary check improvements.

refs: https://github.com/wez/wezterm/issues/157#issuecomment-700408882
refs: https://github.com/wez/wezterm/issues/157#issuecomment-700335114
This commit is contained in:
Wez Furlong 2020-09-28 23:02:50 -07:00
parent 3a47d76094
commit 53c63267e8
4 changed files with 88 additions and 55 deletions

View File

@ -2038,10 +2038,12 @@ impl TermWindow {
(size, dims)
} else {
// Resize of the window dimensions may result in changed terminal dimensions
let avail_width = dimensions.pixel_width
- (config.window_padding.left + self.effective_right_padding(&config)) as usize;
let avail_height = dimensions.pixel_height
- (config.window_padding.top + config.window_padding.bottom) as usize;
let avail_width = dimensions.pixel_width.saturating_sub(
(config.window_padding.left + self.effective_right_padding(&config)) as usize,
);
let avail_height = dimensions.pixel_height.saturating_sub(
(config.window_padding.top + config.window_padding.bottom) as usize,
);
let rows = (avail_height / self.render_metrics.cell_size.height as usize)
.saturating_sub(if self.show_tab_bar { 1 } else { 0 });

View File

@ -5,7 +5,7 @@ use crate::ratelim::RateLimiter;
use crate::server::pollable::{pollable_channel, PollableReceiver, PollableSender};
use anyhow::{anyhow, Error};
use domain::{Domain, DomainId};
use log::{debug, error};
use log::error;
use portable_pty::ExitStatus;
use std::cell::{Ref, RefCell, RefMut};
use std::collections::HashMap;
@ -223,16 +223,16 @@ impl Mux {
self.add_pane(&pane)
}
pub fn remove_pane(&self, pane_id: PaneId) {
debug!("removing pane {}", pane_id);
fn remove_pane_internal(&self, pane_id: PaneId) {
log::debug!("removing pane {}", pane_id);
if let Some(pane) = self.panes.borrow_mut().remove(&pane_id) {
log::debug!("killing pane {}", pane_id);
pane.kill();
}
self.prune_dead_windows();
}
pub fn remove_tab(&self, tab_id: TabId) {
debug!("removing tab {}", tab_id);
fn remove_tab_internal(&self, tab_id: TabId) {
log::debug!("remove_tab_internal tab {}", tab_id);
let mut pane_ids = vec![];
if let Some(tab) = self.tabs.borrow_mut().remove(&tab_id) {
for pos in tab.iter_panes() {
@ -240,61 +240,65 @@ impl Mux {
}
}
for pane_id in pane_ids {
self.remove_pane(pane_id);
self.remove_pane_internal(pane_id);
}
}
fn remove_window_internal(&self, window_id: WindowId) {
log::debug!("remove_window_internal {}", window_id);
let window = self.windows.borrow_mut().remove(&window_id);
if let Some(window) = window {
for tab in window.iter() {
self.remove_tab_internal(tab.tab_id());
}
}
}
pub fn remove_pane(&self, pane_id: PaneId) {
self.remove_pane_internal(pane_id);
self.prune_dead_windows();
}
pub fn remove_tab(&self, tab_id: TabId) {
self.remove_tab_internal(tab_id);
self.prune_dead_windows();
}
pub fn prune_dead_windows(&self) {
let live_tab_ids: Vec<TabId> = self.tabs.borrow().keys().cloned().collect();
let mut windows = self.windows.borrow_mut();
let mut dead_windows = vec![];
for (window_id, win) in windows.iter_mut() {
win.prune_dead_tabs(&live_tab_ids);
if win.is_empty() {
log::error!("prune_dead_windows: window is now empty");
dead_windows.push(*window_id);
}
}
let dead_tab_ids: Vec<TabId>;
let dead_tab_ids: Vec<TabId> = self
.tabs
.borrow()
.iter()
.filter_map(|(&id, tab)| if tab.is_dead() { Some(id) } else { None })
.collect();
{
let mut windows = self.windows.borrow_mut();
for (window_id, win) in windows.iter_mut() {
win.prune_dead_tabs(&live_tab_ids);
if win.is_empty() {
log::debug!("prune_dead_windows: window is now empty");
dead_windows.push(*window_id);
}
}
dead_tab_ids = self
.tabs
.borrow()
.iter()
.filter_map(|(&id, tab)| if tab.is_dead() { Some(id) } else { None })
.collect();
}
for tab_id in dead_tab_ids {
log::error!("tab {} is dead", tab_id);
self.tabs.borrow_mut().remove(&tab_id);
self.remove_tab_internal(tab_id);
}
/*
let dead_pane_ids: Vec<TabId> = self
.panes
.borrow()
.iter()
.filter_map(|(&id, pane)| if pane.is_dead() { Some(id) } else { None })
.collect();
for pane_id in dead_pane_ids {
self.panes.borrow_mut().remove(&pane_id);
}
*/
for window_id in dead_windows {
error!("removing window {}", window_id);
windows.remove(&window_id);
self.remove_window_internal(window_id);
}
}
pub fn kill_window(&self, window_id: WindowId) {
let mut windows = self.windows.borrow_mut();
if let Some(window) = windows.remove(&window_id) {
for tab in window.iter() {
self.tabs.borrow_mut().remove(&tab.tab_id());
}
}
self.remove_window_internal(window_id);
}
pub fn get_window(&self, window_id: WindowId) -> Option<Ref<Window>> {
@ -382,12 +386,28 @@ impl Mux {
}
pub fn domain_was_detached(&self, domain: DomainId) {
self.panes
.borrow_mut()
.retain(|_pane_id, pane| pane.domain_id() != domain);
// Ideally we'd do this here, but that seems to cause problems
// at the moment:
// self.prune_dead_windows();
let mut dead_panes = vec![];
for pane in self.panes.borrow().values() {
if pane.domain_id() == domain {
dead_panes.push(pane.pane_id());
}
}
{
let mut windows = self.windows.borrow_mut();
for (_, win) in windows.iter_mut() {
for tab in win.iter() {
tab.kill_panes_in_domain(domain);
}
}
}
log::error!("domain detached panes: {:?}", dead_panes);
for pane_id in dead_panes {
self.remove_pane_internal(pane_id);
}
self.prune_dead_windows();
}
}

View File

@ -762,6 +762,11 @@ impl Tab {
/// first. For large resizes this tends to proportionally adjust
/// the relative sizes of the elements in a split.
pub fn resize(&self, size: PtySize) {
if size.rows == 0 || size.cols == 0 {
// Ignore "impossible" resize requests
return;
}
// Un-zoom first, so that the layout can be reasoned about
// more easily.
let was_zoomed = self.zoomed.borrow().is_some();
@ -1150,7 +1155,13 @@ impl Tab {
pub fn kill_active_pane(&self) -> bool {
let active_idx = *self.active.borrow();
self.remove_pane_if(|idx, _| idx == active_idx)
let killed = self.remove_pane_if(|idx, _| idx == active_idx);
log::debug!("kill_active_pane: killed={}", killed);
killed
}
pub fn kill_panes_in_domain(&self, domain: DomainId) -> bool {
self.remove_pane_if(|_, pane| pane.domain_id() == domain)
}
fn remove_pane_if<F>(&self, f: F) -> bool
@ -1197,6 +1208,7 @@ impl Tab {
// We might be the root, for example
if c.is_top() && c.is_leaf() {
root.replace(Tree::Empty);
dead_panes.push(pane.pane_id());
} else {
root.replace(c.tree());
}

View File

@ -252,7 +252,6 @@ fn client_thread(
for (_, mut promise) in promises.into_iter() {
promise.result(Err(anyhow!("{}", reason)));
}
// FIXME: detach the domain here
return Err(err).context("Error while decoding response pdu");
}
}