From 416dd946706a53d07ac833b721bf6ac36b513cad Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Tue, 4 Nov 2025 08:02:05 -0800 Subject: [PATCH] feat(wm): promote containers by swapping indices This commit adds a new SocketMessage variant PromoteSwap and corresponding komorebic promote-swap command. PromoteSwap will also promote the focused window container to the largest tile in the layout, but instead of removing the focused container x from the Ring and inserting it into position 0, possibly changing the positions of other windows between 0 and x, the indices x and 0 in the Ring will be swapped directly. --- docs/cli/promote-swap.md | 12 ++++++++++++ docs/cli/promote.md | 2 +- komorebi/src/core/mod.rs | 1 + komorebi/src/process_command.rs | 1 + komorebi/src/window_manager.rs | 25 +++++++++++++++++++++++++ komorebic/src/main.rs | 7 ++++++- mkdocs.yml | 1 + 7 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 docs/cli/promote-swap.md diff --git a/docs/cli/promote-swap.md b/docs/cli/promote-swap.md new file mode 100644 index 00000000..45df1d6a --- /dev/null +++ b/docs/cli/promote-swap.md @@ -0,0 +1,12 @@ +# promote-swap + +``` +Promote the focused window to the largest tile by swapping container indices with the largest tile + +Usage: komorebic.exe promote-swap + +Options: + -h, --help + Print help + +``` diff --git a/docs/cli/promote.md b/docs/cli/promote.md index b40d299c..f8d77f9f 100644 --- a/docs/cli/promote.md +++ b/docs/cli/promote.md @@ -1,7 +1,7 @@ # promote ``` -Promote the focused window to the top of the tree +Promote the focused window to the largest tile via container removal and re-insertion Usage: komorebic.exe promote diff --git a/komorebi/src/core/mod.rs b/komorebi/src/core/mod.rs index ff6eddf4..ffe841db 100644 --- a/komorebi/src/core/mod.rs +++ b/komorebi/src/core/mod.rs @@ -89,6 +89,7 @@ pub enum SocketMessage { Close, Minimize, Promote, + PromoteSwap, PromoteFocus, PromoteWindow(OperationDirection), EagerFocus(String), diff --git a/komorebi/src/process_command.rs b/komorebi/src/process_command.rs index b68eac28..ddd0962f 100644 --- a/komorebi/src/process_command.rs +++ b/komorebi/src/process_command.rs @@ -213,6 +213,7 @@ impl WindowManager { let mut force_update_borders = false; match message { SocketMessage::Promote => self.promote_container_to_front()?, + SocketMessage::PromoteSwap => self.promote_container_swap()?, SocketMessage::PromoteFocus => self.promote_focus_to_front()?, SocketMessage::PromoteWindow(direction) => { self.focus_container_in_direction(direction)?; diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index 295294eb..50749139 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -2892,6 +2892,31 @@ impl WindowManager { self.update_focused_workspace(self.mouse_follows_focus, true) } + #[tracing::instrument(skip(self))] + pub fn promote_container_swap(&mut self) -> eyre::Result<()> { + self.handle_unmanaged_window_behaviour()?; + + let workspace = self.focused_workspace_mut()?; + let focused_container_idx = workspace.focused_container_idx(); + let primary_idx = match &workspace.layout { + Layout::Default(_) => 0, + Layout::Custom(layout) => layout.first_container_idx( + layout + .primary_idx() + .ok_or_eyre("this custom layout does not have a primary column")?, + ), + }; + + if matches!(workspace.layout, Layout::Default(DefaultLayout::Grid)) { + tracing::debug!("ignoring promote-swap command for grid layout"); + return Ok(()); + } + + workspace.swap_containers(focused_container_idx, primary_idx); + + self.update_focused_workspace(self.mouse_follows_focus, true) + } + #[tracing::instrument(skip(self))] pub fn promote_focus_to_front(&mut self) -> eyre::Result<()> { self.handle_unmanaged_window_behaviour()?; diff --git a/komorebic/src/main.rs b/komorebic/src/main.rs index f8ec7ca9..6e8480a4 100644 --- a/komorebic/src/main.rs +++ b/komorebic/src/main.rs @@ -1267,8 +1267,10 @@ enum SubCommand { /// Flip the layout on the focused workspace #[clap(arg_required_else_help = true)] FlipLayout(FlipLayout), - /// Promote the focused window to the top of the tree + /// Promote the focused window to the largest tile via container removal and re-insertion Promote, + /// Promote the focused window to the largest tile by swapping container indices with the largest tile + PromoteSwap, /// Promote the user focus to the top of the tree PromoteFocus, /// Promote the window in the specified direction @@ -2029,6 +2031,9 @@ fn main() -> eyre::Result<()> { SubCommand::Promote => { send_message(&SocketMessage::Promote)?; } + SubCommand::PromoteSwap => { + send_message(&SocketMessage::PromoteSwap)?; + } SubCommand::PromoteFocus => { send_message(&SocketMessage::PromoteFocus)?; } diff --git a/mkdocs.yml b/mkdocs.yml index 8aaf7b1a..35fe0052 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -172,6 +172,7 @@ nav: - cli/scrolling-layout-columns.md - cli/flip-layout.md - cli/promote.md + - cli/promote-swap.md - cli/promote-focus.md - cli/promote-window.md - cli/retile.md