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

mux: more robust handling of pane killing

Work harder to notice and handle the PaneRemoved notification
more centrally, which allows removing some earlier workarounds.

Now when we receive PaneRemoved, we take the opportunity to handle
missing mapping or stale mapping between local and remote ids and
perform a resync before continuing to handle the PaneRemoved message.

Doing it this way means that we don't need to second guess the timing
of notification or the resync, so we end up with the correct sequence
of notifications, and the result is the correct size of the splits
because the local and remote aren't independently managing the
the pane removal with conflicting ideas of the new size.

refs: https://github.com/wez/wezterm/issues/3386
This commit is contained in:
Wez Furlong 2023-03-28 08:47:28 -07:00
parent 05919acb29
commit 07e1c5834b
No known key found for this signature in database
GPG Key ID: 7A7F66A31EC9B387
3 changed files with 20 additions and 33 deletions

View File

@ -27,6 +27,7 @@ As features stabilize some brief notes about them will accumulate here.
#### Fixed #### Fixed
* mux: Stale remote window mapping could prevent spawning new tabs in remote domain. #2759 * mux: Stale remote window mapping could prevent spawning new tabs in remote domain. #2759
* mux: Splitting then killing a pane could result in incorrect pane sizes. #3386
### 20230326-111934-3666303c ### 20230326-111934-3666303c

View File

@ -142,6 +142,7 @@ async fn process_unilateral_inner_async(
let local_pane_id = match client_domain.remote_to_local_pane_id(pane_id) { let local_pane_id = match client_domain.remote_to_local_pane_id(pane_id) {
Some(p) => p, Some(p) => p,
None => { None => {
log::debug!("got {decoded:?}, pane not found locally, resync");
client_domain.resync().await?; client_domain.resync().await?;
client_domain client_domain
.remote_to_local_pane_id(pane_id) .remote_to_local_pane_id(pane_id)
@ -151,9 +152,23 @@ async fn process_unilateral_inner_async(
} }
}; };
let pane = mux let pane = match mux.get_pane(local_pane_id) {
.get_pane(local_pane_id) Some(p) => p,
.ok_or_else(|| anyhow!("no such pane {}", local_pane_id))?; None => {
log::debug!("got {decoded:?}, but local pane {local_pane_id} no longer exists; resync");
client_domain.resync().await?;
let local_pane_id =
client_domain
.remote_to_local_pane_id(pane_id)
.ok_or_else(|| {
anyhow!("remote pane id {} does not have a local pane id", pane_id)
})?;
mux.get_pane(local_pane_id)
.ok_or_else(|| anyhow!("local pane {local_pane_id} not found"))?
}
};
let client_pane = pane.downcast_ref::<ClientPane>().ok_or_else(|| { let client_pane = pane.downcast_ref::<ClientPane>().ok_or_else(|| {
log::error!( log::error!(
"received unilateral PDU for pane {} which is \ "received unilateral PDU for pane {} which is \

View File

@ -466,39 +466,10 @@ impl Pane for ClientPane {
.kill_pane(KillPane { .kill_pane(KillPane {
pane_id: remote_pane_id, pane_id: remote_pane_id,
}) })
.await?; .await
// Arrange to resync the layout, to avoid artifacts
// <https://github.com/wez/wezterm/issues/1277>.
// We need a short delay to avoid racing with the observable
// effects of killing the pane.
// <https://github.com/wez/wezterm/issues/1752#issuecomment-1088269363>
smol::Timer::after(std::time::Duration::from_millis(200)).await;
let mux = Mux::get();
let client_domain = mux
.get_domain(local_domain_id)
.ok_or_else(|| anyhow::anyhow!("no such domain {}", local_domain_id))?;
let client_domain =
client_domain
.downcast_ref::<ClientDomain>()
.ok_or_else(|| {
anyhow::anyhow!(
"domain {} is not a ClientDomain instance",
local_domain_id
)
})?;
client_domain.resync().await?;
anyhow::Result::<()>::Ok(())
}) })
.detach(); .detach();
} }
// Explicitly mark ourselves as dead.
// Ideally we'd discover this later when polling the
// status, but killing the pane prevents the server
// side from sending us further data.
// <https://github.com/wez/wezterm/issues/1752>
self.renderable.lock().inner.borrow_mut().dead = true;
} }
fn mouse_event(&self, event: MouseEvent) -> anyhow::Result<()> { fn mouse_event(&self, event: MouseEvent) -> anyhow::Result<()> {