From 67e8d54771fbc805f244a42f91902678ee39dbbb Mon Sep 17 00:00:00 2001 From: Quan Tong Date: Sun, 27 Aug 2023 17:12:25 +0700 Subject: [PATCH 1/3] add zoom-pane subcommand --- mux/src/tab.rs | 8 ++ wezterm-mux-server-impl/src/sessionhandler.rs | 9 +- wezterm/src/cli/mod.rs | 6 + wezterm/src/cli/zoom_pane.rs | 109 ++++++++++++++++++ 4 files changed, 129 insertions(+), 3 deletions(-) create mode 100644 wezterm/src/cli/zoom_pane.rs diff --git a/mux/src/tab.rs b/mux/src/tab.rs index 1b46ff170bb..f7c178b64ae 100644 --- a/mux/src/tab.rs +++ b/mux/src/tab.rs @@ -745,6 +745,10 @@ impl Tab { .lock() .split_and_insert(pane_index, request, pane) } + + pub fn get_zoomed_pane(&self) -> Option> { + self.inner.lock().get_zoomed_pane() + } } impl TabInner { @@ -2051,6 +2055,10 @@ impl TabInner { pane_index }) } + + fn get_zoomed_pane(&self) -> Option> { + self.zoomed.clone() + } } /// This type is used directly by the codec, take care to bump diff --git a/wezterm-mux-server-impl/src/sessionhandler.rs b/wezterm-mux-server-impl/src/sessionhandler.rs index 31df12dad8c..977c6a7b7fa 100644 --- a/wezterm-mux-server-impl/src/sessionhandler.rs +++ b/wezterm-mux-server-impl/src/sessionhandler.rs @@ -532,8 +532,11 @@ impl SessionHandler { let tab = mux .get_tab(containing_tab_id) .ok_or_else(|| anyhow!("no such tab {}", containing_tab_id))?; - tab.set_active_pane(&pane); - tab.set_zoomed(zoomed); + tab.set_zoomed(false); + if zoomed { + tab.set_active_pane(&pane); + tab.set_zoomed(zoomed); + } Ok(Pdu::UnitResponse(UnitResponse {})) }, send_response, @@ -1021,7 +1024,7 @@ async fn split_pane(split: SplitPane, client_id: Option>) -> anyho Ok::(Pdu::SpawnResponse(SpawnResponse { pane_id: pane.pane_id(), - tab_id: tab_id, + tab_id, window_id, size, })) diff --git a/wezterm/src/cli/mod.rs b/wezterm/src/cli/mod.rs index 0dbd5bd09cf..95e90bf89cb 100644 --- a/wezterm/src/cli/mod.rs +++ b/wezterm/src/cli/mod.rs @@ -22,6 +22,7 @@ mod set_window_title; mod spawn_command; mod split_pane; mod tls_creds; +mod zoom_pane; #[derive(Debug, Parser, Clone, Copy)] enum CliOutputFormatKind { @@ -159,6 +160,10 @@ Outputs the pane-id for the newly created pane on success" /// Rename a workspace #[command(name = "rename-workspace", rename_all = "kebab")] RenameWorkspace(rename_workspace::RenameWorkspace), + + /// Zoom, unzoom, or toggle zoom state + #[command(name = "zoom-pane", rename_all = "kebab")] + ZoomPane(zoom_pane::ZoomPane), } async fn run_cli_async(opts: &crate::Opt, cli: CliCommand) -> anyhow::Result<()> { @@ -194,6 +199,7 @@ async fn run_cli_async(opts: &crate::Opt, cli: CliCommand) -> anyhow::Result<()> CliSubCommand::SetTabTitle(cmd) => cmd.run(client).await, CliSubCommand::SetWindowTitle(cmd) => cmd.run(client).await, CliSubCommand::RenameWorkspace(cmd) => cmd.run(client).await, + CliSubCommand::ZoomPane(cmd) => cmd.run(client).await, } } diff --git a/wezterm/src/cli/zoom_pane.rs b/wezterm/src/cli/zoom_pane.rs new file mode 100644 index 00000000000..5cd3cadfb65 --- /dev/null +++ b/wezterm/src/cli/zoom_pane.rs @@ -0,0 +1,109 @@ +use crate::cli::resolve_pane_id; +use anyhow::{anyhow, Result}; +use clap::Parser; +use codec::SetPaneZoomed; +use mux::pane::PaneId; +use std::collections::HashMap; +use wezterm_client::client::Client; + +#[derive(Debug, Parser, Clone)] +pub struct ZoomPane { + /// Specify the target pane. + /// The default is to use the current pane based on the + /// environment variable WEZTERM_PANE. + #[arg(long)] + pane_id: Option, + + /// Zooms the pane if it wasn't already zoomed + #[arg(long, default_value = "true", conflicts_with_all=&["unzoom", "toggle"])] + zoom: bool, + + /// Unzooms the pane if it was zoomed + #[arg(long, conflicts_with_all=&["zoom", "toggle"])] + unzoom: bool, + + /// Toggles the zoom state of the pane + #[arg(long, conflicts_with_all=&["zoom", "unzoom"])] + toggle: bool, +} + +impl ZoomPane { + pub async fn run(&self, client: Client) -> Result<()> { + let panes = client.list_panes().await?; + + let mut pane_id_to_tab_id = HashMap::new(); + let mut tab_id_to_active_zoomed_pane_id = HashMap::new(); + + for tabroot in panes.tabs { + let mut cursor = tabroot.into_tree().cursor(); + + loop { + if let Some(entry) = cursor.leaf_mut() { + pane_id_to_tab_id.insert(entry.pane_id, entry.tab_id); + if entry.is_active_pane && entry.is_zoomed_pane { + tab_id_to_active_zoomed_pane_id.insert(entry.tab_id, entry.pane_id); + } + } + match cursor.preorder_next() { + Ok(c) => cursor = c, + Err(_) => break, + } + } + } + + let pane_id = resolve_pane_id(&client, self.pane_id).await?; + let containing_tab_id = pane_id_to_tab_id + .get(&pane_id) + .copied() + .ok_or_else(|| anyhow!("unable to resolve current tab"))?; + + if self.zoom { + client + .set_zoomed(SetPaneZoomed { + containing_tab_id, + pane_id, + zoomed: true, + }) + .await?; + } + + if self.unzoom { + client + .set_zoomed(SetPaneZoomed { + containing_tab_id, + pane_id, + zoomed: false, + }) + .await?; + } + + if self.toggle { + if tab_id_to_active_zoomed_pane_id.contains_key(&containing_tab_id) { + let target_pane = tab_id_to_active_zoomed_pane_id + .get(&containing_tab_id) + .copied() + .ok_or_else(|| { + anyhow!("could not determine which pane should be active for tab {containing_tab_id}") + })?; + if target_pane == pane_id { + client + .set_zoomed(SetPaneZoomed { + containing_tab_id, + pane_id, + zoomed: false, + }) + .await?; + } + } else { + client + .set_zoomed(SetPaneZoomed { + containing_tab_id, + pane_id, + zoomed: true, + }) + .await?; + } + } + Ok(()) + } +} From 336ebbfb2aa2e2a552b2890e98b906e00adc8297 Mon Sep 17 00:00:00 2001 From: Quan Tong Date: Tue, 29 Aug 2023 10:09:33 +0700 Subject: [PATCH 2/3] simplify --- wezterm/src/cli/zoom_pane.rs | 46 ++++++++++-------------------------- 1 file changed, 13 insertions(+), 33 deletions(-) diff --git a/wezterm/src/cli/zoom_pane.rs b/wezterm/src/cli/zoom_pane.rs index 5cd3cadfb65..f3af33e72be 100644 --- a/wezterm/src/cli/zoom_pane.rs +++ b/wezterm/src/cli/zoom_pane.rs @@ -15,7 +15,10 @@ pub struct ZoomPane { pane_id: Option, /// Zooms the pane if it wasn't already zoomed - #[arg(long, default_value = "true", conflicts_with_all=&["unzoom", "toggle"])] + #[arg(long, default_value = "true", default_value_ifs([ + ("unzoom", "true", "false"), + ("toggle", "true", "false"), + ]), conflicts_with_all=&["unzoom", "toggle"])] zoom: bool, /// Unzooms the pane if it was zoomed @@ -57,53 +60,30 @@ impl ZoomPane { .copied() .ok_or_else(|| anyhow!("unable to resolve current tab"))?; - if self.zoom { + if self.zoom || self.unzoom { client .set_zoomed(SetPaneZoomed { containing_tab_id, pane_id, - zoomed: true, + zoomed: self.zoom, }) .await?; } - if self.unzoom { + if self.toggle { + let is_zoomed = tab_id_to_active_zoomed_pane_id + .get(&containing_tab_id) + .copied() + == Some(pane_id); + client .set_zoomed(SetPaneZoomed { containing_tab_id, pane_id, - zoomed: false, + zoomed: !is_zoomed, }) .await?; } - - if self.toggle { - if tab_id_to_active_zoomed_pane_id.contains_key(&containing_tab_id) { - let target_pane = tab_id_to_active_zoomed_pane_id - .get(&containing_tab_id) - .copied() - .ok_or_else(|| { - anyhow!("could not determine which pane should be active for tab {containing_tab_id}") - })?; - if target_pane == pane_id { - client - .set_zoomed(SetPaneZoomed { - containing_tab_id, - pane_id, - zoomed: false, - }) - .await?; - } - } else { - client - .set_zoomed(SetPaneZoomed { - containing_tab_id, - pane_id, - zoomed: true, - }) - .await?; - } - } Ok(()) } } From 1819a7dc6f6b26cc248af5271159ed2ec982fb1a Mon Sep 17 00:00:00 2001 From: Quan Tong Date: Tue, 29 Aug 2023 10:10:38 +0700 Subject: [PATCH 3/3] check the zoom state before unzooming --- wezterm-mux-server-impl/src/sessionhandler.rs | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/wezterm-mux-server-impl/src/sessionhandler.rs b/wezterm-mux-server-impl/src/sessionhandler.rs index 977c6a7b7fa..b9dcc7e1cfb 100644 --- a/wezterm-mux-server-impl/src/sessionhandler.rs +++ b/wezterm-mux-server-impl/src/sessionhandler.rs @@ -532,10 +532,23 @@ impl SessionHandler { let tab = mux .get_tab(containing_tab_id) .ok_or_else(|| anyhow!("no such tab {}", containing_tab_id))?; - tab.set_zoomed(false); - if zoomed { - tab.set_active_pane(&pane); - tab.set_zoomed(zoomed); + match tab.get_zoomed_pane() { + Some(p) => { + let is_zoomed = p.pane_id() == pane_id; + if is_zoomed != zoomed { + tab.set_zoomed(false); + if zoomed { + tab.set_active_pane(&pane); + tab.set_zoomed(zoomed); + } + } + } + None => { + if zoomed { + tab.set_active_pane(&pane); + tab.set_zoomed(zoomed); + } + } } Ok(Pdu::UnitResponse(UnitResponse {})) },