Files
pi3-smart-workspace/README.md
Asger Weirsøe 0d8f843814
All checks were successful
CI / test (push) Successful in 40s
Fixed some bugs, updated how packages are handeled. Prepared on AUR publishing
2026-05-19 15:59:28 +02:00

195 lines
6.0 KiB
Markdown

# pi3-smart-workspace
A small CLI helper for the [i3 window manager](https://i3wm.org/). Bound to
`$mod+<n>` keys, it switches (or moves a container to) the **N-th workspace
declared for the output your mouse cursor is currently on**, rather than
i3's default behaviour of jumping to a globally-numbered workspace.
This makes multi-monitor i3 setups feel a lot more seamless: pressing
`$mod+1` always lands you on the first workspace of whichever screen you're
pointing at.
## Usage
```
usage: pi3-smart-workspace [-h] [-d] -i INDEX [-s] [-k]
Switch (or shift) to the N-th workspace on the output your cursor is on.
options:
-h, --help show this help message and exit
-d, --debug Print parsed state and re-raise exceptions.
Required:
-i INDEX, --index INDEX
The 1-based index into the workspaces declared for
the cursor's output.
Shift:
manipulate the active window
-s, --shift Move the focused container to the indexed workspace.
-k, --keep-with-it With --shift, also follow the container to the new
workspace.
```
## Installation
Install from PyPI:
```sh
pip install pi3-smart-workspace
```
For local development, clone the repo and install in editable mode with the
dev extras:
```sh
pip install -e ".[dev]"
pytest
```
Requires Python 3.14+ and a running i3 session.
## i3 configuration
`pi3-smart-workspace` parses your live i3 config and looks for three
specific patterns:
1. `set $<var> <output-name>` — output aliases
2. `set $<var> <digit…>` — workspace-name aliases (quoted or unquoted)
3. `workspace $<var> output $<var>` — bindings of workspaces to outputs
The order in which `workspace … output …` lines appear in your config
determines the N-th workspace for that output.
### Bootstrap with `init` (recommended)
Instead of writing the config by hand, run:
```sh
pi3-smart-workspace init
```
This detects every active monitor via i3 and writes:
```
~/.config/i3/pi3-smart-workspace/
├── bindings.conf # $mod+N, $mod+Shift+N, $mod+Ctrl+N bindings
├── eDP-1/
│ └── workspaces.conf # workspaces 1..8 bound to eDP-1
├── HDMI-A-0/
│ └── workspaces.conf # workspaces 9..16 bound to HDMI-A-0
└── DP-1/
└── workspaces.conf # workspaces 17..24 bound to DP-1
```
Each output gets a contiguous range of global workspace numbers; the
local index (the number after the colon, e.g. `9:1`) tells you "first
workspace on this monitor". Then add the include lines `init` prints to
your main i3 config and reload (`$mod+Shift+r`):
```i3config
include ~/.config/i3/pi3-smart-workspace/bindings.conf
include ~/.config/i3/pi3-smart-workspace/*/workspaces.conf
```
i3's `include` directive needs i3 ≥ 4.20.
Useful flags:
| Flag | Default | Effect |
| --- | --- | --- |
| `-n N` / `--count N` | 8 | Workspaces per output |
| `--config-dir PATH` | `~/.config/i3/pi3-smart-workspace` | Where to write |
| `--dry-run` | off | Print to stdout, don't touch the filesystem |
| `--force` | off | Overwrite existing files |
Re-run `init --force` after plugging or unplugging a monitor to
regenerate the per-output folders.
### Example config (manual)
```i3config
# Displays
set $primary eDP
set $top HDMI-A-0
set $bottom HDMI2
# Workspaces
set $ws1 1:1
# ... and so on
set $ws{n} {n}:{n}
set $TopWs1 {n+1}:1
# ... and so on
set $TopWs{k} {n+1+k}:{k}
set $BottomWs1 {k+1}:1
# ... and so on
set $BottomWs{q} {k+1+q}:{q}
workspace $ws1 output $primary
# ... and so on
workspace $ws{n} output $primary
workspace $TopWs1 output $top
# ... and so on
workspace $TopWs{k} output $top
workspace $BottomWs1 output $bottom
# ... and so on
workspace $BottomWs{q} output $bottom
# Switch to workspace
bindsym $mod+1 exec --no-startup-id pi3-smart-workspace -i 1
bindsym $mod+2 exec --no-startup-id pi3-smart-workspace -i 2
bindsym $mod+3 exec --no-startup-id pi3-smart-workspace -i 3
bindsym $mod+4 exec --no-startup-id pi3-smart-workspace -i 4
bindsym $mod+5 exec --no-startup-id pi3-smart-workspace -i 5
bindsym $mod+6 exec --no-startup-id pi3-smart-workspace -i 6
bindsym $mod+7 exec --no-startup-id pi3-smart-workspace -i 7
bindsym $mod+8 exec --no-startup-id pi3-smart-workspace -i 8
# Move focused container to workspace
bindsym $mod+Shift+1 exec --no-startup-id pi3-smart-workspace -i 1 -s
bindsym $mod+Shift+2 exec --no-startup-id pi3-smart-workspace -i 2 -s
bindsym $mod+Shift+3 exec --no-startup-id pi3-smart-workspace -i 3 -s
bindsym $mod+Shift+4 exec --no-startup-id pi3-smart-workspace -i 4 -s
bindsym $mod+Shift+5 exec --no-startup-id pi3-smart-workspace -i 5 -s
bindsym $mod+Shift+6 exec --no-startup-id pi3-smart-workspace -i 6 -s
bindsym $mod+Shift+7 exec --no-startup-id pi3-smart-workspace -i 7 -s
bindsym $mod+Shift+8 exec --no-startup-id pi3-smart-workspace -i 8 -s
# Move to workspace with focused container
bindsym $mod+Ctrl+1 exec --no-startup-id pi3-smart-workspace -i 1 -sk
bindsym $mod+Ctrl+2 exec --no-startup-id pi3-smart-workspace -i 2 -sk
bindsym $mod+Ctrl+3 exec --no-startup-id pi3-smart-workspace -i 3 -sk
bindsym $mod+Ctrl+4 exec --no-startup-id pi3-smart-workspace -i 4 -sk
bindsym $mod+Ctrl+5 exec --no-startup-id pi3-smart-workspace -i 5 -sk
bindsym $mod+Ctrl+6 exec --no-startup-id pi3-smart-workspace -i 6 -sk
bindsym $mod+Ctrl+7 exec --no-startup-id pi3-smart-workspace -i 7 -sk
bindsym $mod+Ctrl+8 exec --no-startup-id pi3-smart-workspace -i 8 -sk
```
## Development
```sh
pip install -e ".[dev]"
pytest # run the unit tests
python -m build # build sdist + wheel into dist/
twine check dist/* # validate the distributions
```
The unit tests cover the two pure functions (`parse_workspaces_per_output`
and `find_output_at_cursor`) and run without an X display, so they work in
CI. The i3-dispatch path needs a real multi-monitor session and is only
exercised manually.
## Credits
Thanks to Michał Wieluński for the inspiration
([pi3-switch](https://github.com/landmaj/pi3-switch)) and Tony Crisci for
the easy-to-use i3 Python library
([i3ipc-python](https://github.com/acrisci/i3ipc-python)).