diff --git a/README.md b/README.md index 6535a12..adb5e7b 100644 --- a/README.md +++ b/README.md @@ -1,63 +1,397 @@ -# SWAY Workspace manipulation helper -in progress / unstable +# SWAY workspace manipulation helper +Less confusing rename, switch, or reorder workspaces.\ +switch: This program tries very hard to keep all workspace operations on the focused monitor.\ +reorder: Move workspaces left/right like container tabs in Sway.\ +rename: Renaming remembers the workspace number.\ +Also, it serves as a binary for selecting or renaming workspaces in rofi. -#### motivation: -i was unhappy how sway handles user interaction with workspaces especially when you have additional monitors connected. -This program tries very hard to keep all workspace operations on the output where the the currently focused container resides. -Also it seconds as a replacement for a bash script to integrate workspaces in rofi. +##### e.g. Next workspace while multiple monitors are connected +``` +~/.cargo/bin/swaymsg_workspace next +``` +```mermaid +block-beta + columns 2 + block:a1["Monitor 1"]:1 + columns 3 + A1["6 work"] + B1["8 messages"] + space:6 + end + block:a2["Monitor 2"]:1 + columns 3 + A2["7 music"] + space:6 + end + space:2 + block:b1["Monitor 1"]:1 + columns 3 + C1["6 work"] + D1["8 messages"] + space:6 + end + block:b2["Monitor 2"]:1 + columns 3 + B2["7 music"] + space:6 + end + a1 -- "next" --> b1 + style A1 fill:#ccc,stroke:#333,stroke-width:4px + style D1 fill:#ccc,stroke:#333,stroke-width:4px +``` + +##### Sway stock behaviour: + +Given the workspaces: +| Monitor1 | Monitor1 |Monitor2| +| --- | --- | --- | +| ▫ 6 work | ▪ 8 messages|▫ 7 music + + +with ```▪ 8 messages``` *Monitor 1* being focused + +calling Sway's "workspace next" would switch focus to -## Features: +```▪ 6 work``` *Monitor 1*      "workspace next"     ```▪ 7 music``` *Monitor 2*      "workspace next"     ```▪ 8 messages``` *Monitor 1* -- \/\ command stays on the active output -- reorder workspace by increasing/decreasing workspace Number -- swap current workspace with previous / next workspace on the currently active output -- rename workspace without changing the workspace Number +## Features +- [next/prev command to select adjacent Workspaces on the same monitor, (unlike sway's 'workspace next' command) ](#select-workspace) +- [swap current workspace with previous / next workspace on the currently active monitor](#select-workspace) +- [reorder workspaces by increasing/decreasing workspace Number](#index-workspace) +- [rename a workspace without changing the workspace Number](#rename-workspace) - rename/select workspace via rofi -- move container to workspace on same output -- select workspace by number on same output - -``` -> cat ~/.config/sway/config |grep swaymsg_workspace - -bindsym Mod1+Ctrl+Shift+n exec /usr/bin/swaymsg_workspace swap_with_next -bindsym Mod1+Ctrl+Shift+p exec /usr/bin/swaymsg_workspace swap_with_prev -bindsym Mod1+Ctrl+f exec /usr/bin/swaymsg_workspace decrease -bindsym Mod1+Ctrl+g exec /usr/bin/swaymsg_workspace increase -bindsym Mod1+Ctrl+n exec /usr/bin/swaymsg_workspace next -bindsym Mod1+Ctrl+p exec /usr/bin/swaymsg_workspace prev - -bindsym --release Mod1+Ctrl+r exec /usr/bin/swaymsg_workspace rename_to $(rofi -dmenu -l 0 -P "rename workspace $(/usr/bin/swaymsg_workspace print_focused_name) to") - -bindsym Mod1+Ctrl+0 exec /usr/bin/swaymsg_workspace number 10 -bindsym Mod1+Ctrl+1 exec /usr/bin/swaymsg_workspace number 1 -bindsym Mod1+Ctrl+2 exec /usr/bin/swaymsg_workspace number 2 -bindsym Mod1+Ctrl+3 exec /usr/bin/swaymsg_workspace number 3 -bindsym Mod1+Ctrl+4 exec /usr/bin/swaymsg_workspace number 4 -bindsym Mod1+Ctrl+5 exec /usr/bin/swaymsg_workspace number 5 -bindsym Mod1+Ctrl+6 exec /usr/bin/swaymsg_workspace number 6 -bindsym Mod1+Ctrl+7 exec /usr/bin/swaymsg_workspace number 7 -bindsym Mod1+Ctrl+8 exec /usr/bin/swaymsg_workspace number 8 -bindsym Mod1+Ctrl+9 exec /usr/bin/swaymsg_workspace number 9 -bindsym Mod1+Ctrl+Shift+0 exec /usr/bin/swaymsg_workspace move_container_to_workspace_number 10 -bindsym Mod1+Ctrl+Shift+1 exec /usr/bin/swaymsg_workspace move_container_to_workspace_number 1 -bindsym Mod1+Ctrl+Shift+2 exec /usr/bin/swaymsg_workspace move_container_to_workspace_number 2 -bindsym Mod1+Ctrl+Shift+3 exec /usr/bin/swaymsg_workspace move_container_to_workspace_number 3 -bindsym Mod1+Ctrl+Shift+4 exec /usr/bin/swaymsg_workspace move_container_to_workspace_number 4 -bindsym Mod1+Ctrl+Shift+5 exec /usr/bin/swaymsg_workspace move_container_to_workspace_number 5 -bindsym Mod1+Ctrl+Shift+6 exec /usr/bin/swaymsg_workspace move_container_to_workspace_number 6 -bindsym Mod1+Ctrl+Shift+7 exec /usr/bin/swaymsg_workspace move_container_to_workspace_number 7 -bindsym Mod1+Ctrl+Shift+8 exec /usr/bin/swaymsg_workspace move_container_to_workspace_number 8 -bindsym Mod1+Ctrl+Shift+9 exec /usr/bin/swaymsg_workspace move_container_to_workspace_number 9 - -``` - -``` -> cat ~/.config/rofi/config.rasi +- [select workspace by number on same output](#select-workspace-while-multiple-monitors-are-connected) +- [move window to workspace on same output](#move-window-to-workspace-number-while-multiple-monitors-are-connected) + + +##### Select workspace +``` +~/.cargo/bin/swaymsg_workspace next +``` +```mermaid +block-beta + columns 3 + block:a:3 + A["5 music"] + B["6 work"] + C["8 messages"] + end + space:3 + block:b:3 + D["5 music"] + E["6 work"] + F["8 messages"] + end + space:3 + block:c:3 + G["5 music"] + H["6 work"] + I["8 messages"] + end + a -- "next" --> b + b -- "next" --> c + style B fill:#ccc,stroke:#333,stroke-width:4px + style F fill:#ccc,stroke:#333,stroke-width:4px + style G fill:#ccc,stroke:#333,stroke-width:4px +``` +``` +~/.cargo/bin/swaymsg_workspace prev +``` +```mermaid +block-beta + columns 3 + block:a:3 + A["5 music"] + B["6 work"] + C["8 messages"] + end + space:3 + block:b:3 + D["5 music"] + E["6 work"] + F["8 messages"] + end + a -- "prev" --> b + style B fill:#ccc,stroke:#333,stroke-width:4px + style D fill:#ccc,stroke:#333,stroke-width:4px + +``` +##### Swap workspace +``` +~/.cargo/bin/swaymsg_workspace swap_with_next +``` +```mermaid +block-beta + columns 3 + block:a:3 + A["5 music"] + B["6 work"] + C["8 messages"] + end + space:3 + block:b:3 + D["5 music"] + E["6 messages"] + F["8 work"] + end + space:3 + block:c:3 + G["5 work"] + H["6 messages"] + I["8 music"] + end + a -- "swap_with_next"--> b + b -- "swap_with_next"--> c + style B fill:#ccc,stroke:#333,stroke-width:4px + style F fill:#ccc,stroke:#333,stroke-width:4px + style G fill:#ccc,stroke:#333,stroke-width:4px +``` +``` +~/.cargo/bin/swaymsg_workspace swap_with_prev +``` +```mermaid +block-beta + columns 3 + block:a:3 + A["5 music"] + B["6 work"] + C["8 messages"] + end + space:3 + block:b:3 + D["5 work"] + E["6 music"] + F["8 messages"] + end + a -- "swap_with_prev" --> b + style B fill:#ccc,stroke:#333,stroke-width:4px + style D fill:#ccc,stroke:#333,stroke-width:4px +``` +##### Index workspace +``` +~/.cargo/bin/swaymsg_workspace increase +``` +```mermaid +block-beta + columns 3 + block:a:3 + A["5 music"] + B["6 work"] + C["8 messages"] + end + space:3 + block:b:3 + D["5 music"] + E["7 work"] + F["8 messages"] + end + space:3 + block:c:3 + G["5 music"] + H["7 messages"] + I["8 work"] + end + a -- "increase"--> b + b -- "increase"--> c + style B fill:#ccc,stroke:#333,stroke-width:4px + style E fill:#ccc,stroke:#333,stroke-width:4px + style I fill:#ccc,stroke:#333,stroke-width:4px +``` +``` +~/.cargo/bin/swaymsg_workspace decrease +``` +```mermaid +block-beta + columns 3 + block:a:3 + A["5 music"] + B["7 work"] + C["8 messages"] + end + space:3 + block:b:3 + D["5 music"] + E["6 work"] + F["8 messages"] + end + a -- "decrease"--> b + style B fill:#ccc,stroke:#333,stroke-width:4px + style E fill:#ccc,stroke:#333,stroke-width:4px + +``` +##### Rename workspace +``` +~/.cargo/bin/swaymsg_workspace rename_to movies +``` +```mermaid +block-beta + columns 3 + block:a:3 + A["5 music"] + B["6 work"] + C["8 messages"] + end + space:3 + block:b:3 + D["5 movies"] + E["6 work"] + F["8 messages"] + end + a -- "rename_to movies"--> b + style A fill:#ccc,stroke:#333,stroke-width:4px + style D fill:#ccc,stroke:#333,stroke-width:4px +``` +##### Select workspace while multiple monitors are connected +``` +~/.cargo/bin/swaymsg_workspace number 5 +``` +```mermaid +block-beta + columns 2 + block:a1["Monitor 1"]:1 + columns 3 + A1["6 work"] + B1["8 messages"] + space:6 + end + block:a2["Monitor 2"]:1 + columns 3 + A2["5"] + space:6 + end + space:2 + block:b1["Monitor 1"]:1 + columns 3 + C1["5"] + D1["6 work"] + E1["8 messages"] + space:6 + end + block:b2["Monitor 2"]:1 + columns 3 + B2["5"] + space:6 + end + a1 -- "number 5" --> b1 + style B1 fill:#ccc,stroke:#333,stroke-width:4px + style C1 fill:#ccc,stroke:#333,stroke-width:4px +``` +##### Move window to workspace number while multiple monitors are connected +``` +~/.cargo/bin/swaymsg_workspace move_container_to_workspace_number 5 +``` +```mermaid +block-beta + columns 2 + block:a1["Monitor 1"]:1 + columns 3 + A1["6 work"] + B1["8 messages"] + space:6 + end + block:a2["Monitor 2"]:1 + columns 3 + A2["5"] + space:6 + end + space:2 + block:b1["Monitor 1"]:1 + columns 3 + C1["5"] + D1["6 work"] + E1["8 messages"] + space:6 + end + block:b2["Monitor 2"]:1 + columns 3 + B2["5"] + space:6 + end + a1 -- "move_container_to_workspace_number 5" --> b1 + style B1 fill:#ccc,stroke:#333,stroke-width:4px + style E1 fill:#ccc,stroke:#333,stroke-width:4px +``` + +___ +## Demo +https://github.com/user-attachments/assets/7169c4ec-6c15-4ab4-a7ec-35b221379996 + +## Installation + +1. #### install Rust + https://www.rust-lang.org/tools/install + + The Rust installer comes with 'rustup' and 'cargo'. + +2. #### switch to rust nightly channel + ``` + rustup override set nightly + ``` + +3. #### Build and install binary + ``` + cargo install --git https://github.com/berezowski/swaymsg_workspace + ``` + The compiled binary should be in + ```~/.cargo/bin/swaymsg_workspace``` + + +4. #### edit sway config + ```> grep swaymsg_workspace ~/.config/sway/config``` + ``` + ### swaymsg_workspace select previous / next + bindsym Mod1+Ctrl+n exec ~/.cargo/bin/swaymsg_workspace next + bindsym Mod1+Ctrl+p exec ~/.cargo/bin/swaymsg_workspace prev + + ### swaymsg_workspace move workspace left / right + bindsym Mod1+Ctrl+Shift+n exec ~/.cargo/bin/swaymsg_workspace swap_with_next + bindsym Mod1+Ctrl+Shift+p exec ~/.cargo/bin/swaymsg_workspace swap_with_prev + + ### swaymsg_workspace increase / decrease number + bindsym Mod1+Ctrl+f exec ~/.cargo/bin/swaymsg_workspace decrease + bindsym Mod1+Ctrl+g exec ~/.cargo/bin/swaymsg_workspace increase + + ### swaymsg_workspace select by number + bindsym Mod1+Ctrl+0 exec ~/.cargo/bin/swaymsg_workspace number 10 + bindsym Mod1+Ctrl+1 exec ~/.cargo/bin/swaymsg_workspace number 1 + bindsym Mod1+Ctrl+2 exec ~/.cargo/bin/swaymsg_workspace number 2 + bindsym Mod1+Ctrl+3 exec ~/.cargo/bin/swaymsg_workspace number 3 + bindsym Mod1+Ctrl+4 exec ~/.cargo/bin/swaymsg_workspace number 4 + bindsym Mod1+Ctrl+5 exec ~/.cargo/bin/swaymsg_workspace number 5 + bindsym Mod1+Ctrl+6 exec ~/.cargo/bin/swaymsg_workspace number 6 + bindsym Mod1+Ctrl+7 exec ~/.cargo/bin/swaymsg_workspace number 7 + bindsym Mod1+Ctrl+8 exec ~/.cargo/bin/swaymsg_workspace number 8 + bindsym Mod1+Ctrl+9 exec ~/.cargo/bin/swaymsg_workspace number 9 + + ### swaymsg_workspace move container to workspace number + bindsym Mod1+Ctrl+Shift+0 exec ~/.cargo/bin/swaymsg_workspace move_container_to_workspace_number 10 + bindsym Mod1+Ctrl+Shift+1 exec ~/.cargo/bin/swaymsg_workspace move_container_to_workspace_number 1 + bindsym Mod1+Ctrl+Shift+2 exec ~/.cargo/bin/swaymsg_workspace move_container_to_workspace_number 2 + bindsym Mod1+Ctrl+Shift+3 exec ~/.cargo/bin/swaymsg_workspace move_container_to_workspace_number 3 + bindsym Mod1+Ctrl+Shift+4 exec ~/.cargo/bin/swaymsg_workspace move_container_to_workspace_number 4 + bindsym Mod1+Ctrl+Shift+5 exec ~/.cargo/bin/swaymsg_workspace move_container_to_workspace_number 5 + bindsym Mod1+Ctrl+Shift+6 exec ~/.cargo/bin/swaymsg_workspace move_container_to_workspace_number 6 + bindsym Mod1+Ctrl+Shift+7 exec ~/.cargo/bin/swaymsg_workspace move_container_to_workspace_number 7 + bindsym Mod1+Ctrl+Shift+8 exec ~/.cargo/bin/swaymsg_workspace move_container_to_workspace_number 8 + bindsym Mod1+Ctrl+Shift+9 exec ~/.cargo/bin/swaymsg_workspace move_container_to_workspace_number 9 + + ``` + +#### rofi config +```> grep rofi ~/.config/sway/config``` +``` +bindsym --release Mod1+Ctrl+space exec /usr/bin/rofi -show combi +bindsym Mod1+Ctrl+r exec ~/.cargo/bin/swaymsg_workspace rename_to $(rofi -dmenu -l 0 -P "rename workspace $(~/.cargo/bin/swaymsg_workspace print_focused_name) to") +``` + + +```> cat ~/.config/rofi/config.rasi``` +``` configuration { - modi: "combi,move to workspace:/usr/bin/swaymsg_workspace rofi_move_window"; + modi: "combi,move to workspace:~/.cargo/bin/swaymsg_workspace rofi_move_window"; font: "M+CodeLat60 Nerd Font Mono 12"; - combi-modi: "workspaces:/usr/bin/swaymsg_workspace rofi_select_workspace,window,drun,ssh"; + combi-modi: "workspaces:~/.cargo/bin/swaymsg_workspace rofi_select_workspace,window,drun,ssh"; kb-mode-next: "Control+Alt+space"; } diff --git a/src/main.rs b/src/main.rs index c715895..f427a36 100644 --- a/src/main.rs +++ b/src/main.rs @@ -185,11 +185,15 @@ fn execute_userinput(argument: String, argument_parameter: Option) -> Re Ok(()) } -fn swap_workspace(wss: &Workspaces, prev: Option<&Workspace>, next: Option<&Workspace>) { +fn swap_workspace(workspaces: &Workspaces, prev: Option<&Workspace>, next: Option<&Workspace>) { match (prev, next) { - (Some(prev), Some(next)) => wss.swap(prev, next), - (Some(prev), None) => swap_workspace(wss, Some(prev), wss.on_same_screen().first()), - (None, Some(next)) => swap_workspace(wss, wss.on_same_screen().last(), Some(next)), + (Some(prev), Some(next)) => workspaces.swap(prev, next), + (Some(prev), None) => { + swap_workspace(workspaces, Some(prev), workspaces.on_same_screen().first()) + } + (None, Some(next)) => { + swap_workspace(workspaces, workspaces.on_same_screen().last(), Some(next)) + } (None, None) => {} } } diff --git a/src/workspaces.rs b/src/workspaces.rs index 8aaceef..fe1b377 100644 --- a/src/workspaces.rs +++ b/src/workspaces.rs @@ -354,6 +354,9 @@ impl Workspaces { .collect() } pub fn swap(&self, ws1: &Workspace, ws2: &Workspace) { + if ws1.basename == ws2.basename { + return; + } if ws1.get_number() == ws2.get_number() { self.increase_number(ws1); } else {