131 lines
3.4 KiB
Bash
131 lines
3.4 KiB
Bash
#!/usr/bin/env bash
|
|
# ~/.config/hypr/2d-nav.sh
|
|
# 2D workspace navigation for Hyprland
|
|
# Workspaces are named "X" (base row) or "X-Y" (sub-row, Y >= 1)
|
|
# Usage: 2d-nav.sh [left|right|up|down|move-left|move-right|move-up|move-down]
|
|
|
|
set -euo pipefail
|
|
|
|
ACTION="${1:-}"
|
|
|
|
# --- Parse current workspace ---
|
|
# Returns e.g. "3" or "3-2"
|
|
get_current_ws() {
|
|
hyprctl activeworkspace -j | jq -r '.name'
|
|
}
|
|
|
|
# Split "X-Y" into X and Y parts
|
|
parse_ws() {
|
|
local name="$1"
|
|
if [[ "$name" =~ ^([0-9]+)-([0-9]+)$ ]]; then
|
|
echo "${BASH_REMATCH[1]} ${BASH_REMATCH[2]}"
|
|
elif [[ "$name" =~ ^([0-9]+)$ ]]; then
|
|
echo "${BASH_REMATCH[1]} 0"
|
|
else
|
|
# Named/special workspace we don't manage — bail
|
|
echo "0 0"
|
|
fi
|
|
}
|
|
|
|
make_ws_name() {
|
|
local x="$1" y="$2"
|
|
if [[ "$y" -eq 0 ]]; then
|
|
echo "$x"
|
|
else
|
|
echo "${x}-${y}"
|
|
fi
|
|
}
|
|
|
|
# Check if a named workspace currently exists (has at least one window OR is active)
|
|
ws_exists() {
|
|
local name="$1"
|
|
hyprctl workspaces -j | jq -e --arg n "$name" '.[] | select(.name == $n)' > /dev/null 2>&1
|
|
}
|
|
|
|
# Navigate to workspace (creates it on demand if going up; smart-back if going down)
|
|
go_to_ws() {
|
|
local name="$1"
|
|
hyprctl dispatch workspace "name:${name}"
|
|
}
|
|
|
|
move_window_to_ws() {
|
|
local name="$1"
|
|
hyprctl dispatch movetoworkspace "name:${name}"
|
|
}
|
|
|
|
# --- Main logic ---
|
|
current=$(get_current_ws)
|
|
read -r cx cy <<< "$(parse_ws "$current")"
|
|
|
|
# Min/max for X axis (your config has 1-5 on DP-2, 6-10 on HDMI-A-1)
|
|
# But for 2D nav we treat X as free-range 1..10
|
|
X_MIN=1
|
|
X_MAX=10
|
|
Y_MIN=0
|
|
Y_MAX=9 # Reasonable cap for sub-workspaces
|
|
|
|
case "$ACTION" in
|
|
right)
|
|
nx=$(( cx < X_MAX ? cx + 1 : cx ))
|
|
# When moving right, land on base row of target X (Y=0)
|
|
target=$(make_ws_name "$nx" 0)
|
|
go_to_ws "$target"
|
|
;;
|
|
left)
|
|
nx=$(( cx > X_MIN ? cx - 1 : cx ))
|
|
target=$(make_ws_name "$nx" 0)
|
|
go_to_ws "$target"
|
|
;;
|
|
up)
|
|
ny=$(( cy < Y_MAX ? cy + 1 : cy ))
|
|
target=$(make_ws_name "$cx" "$ny")
|
|
go_to_ws "$target"
|
|
;;
|
|
down)
|
|
if [[ "$cy" -gt 0 ]]; then
|
|
ny=$(( cy - 1 ))
|
|
# If the workspace below doesn't exist, fall back to base (Y=0), not Y=(cy-1)
|
|
target=$(make_ws_name "$cx" "$ny")
|
|
if [[ "$ny" -gt 0 ]] && ! ws_exists "$target"; then
|
|
target=$(make_ws_name "$cx" 0)
|
|
fi
|
|
else
|
|
target=$(make_ws_name "$cx" 0)
|
|
fi
|
|
go_to_ws "$target"
|
|
;;
|
|
|
|
# --- Move window variants ---
|
|
move-right)
|
|
nx=$(( cx < X_MAX ? cx + 1 : cx ))
|
|
target=$(make_ws_name "$nx" 0)
|
|
move_window_to_ws "$target"
|
|
;;
|
|
move-left)
|
|
nx=$(( cx > X_MIN ? cx - 1 : cx ))
|
|
target=$(make_ws_name "$nx" 0)
|
|
move_window_to_ws "$target"
|
|
;;
|
|
move-up)
|
|
ny=$(( cy < Y_MAX ? cy + 1 : cy ))
|
|
target=$(make_ws_name "$cx" "$ny")
|
|
move_window_to_ws "$target"
|
|
;;
|
|
move-down)
|
|
if [[ "$cy" -gt 0 ]]; then
|
|
ny=$(( cy - 1 ))
|
|
target=$(make_ws_name "$cx" "$ny")
|
|
if [[ "$ny" -gt 0 ]] && ! ws_exists "$target"; then
|
|
target=$(make_ws_name "$cx" 0)
|
|
fi
|
|
else
|
|
target=$(make_ws_name "$cx" 0)
|
|
fi
|
|
move_window_to_ws "$target"
|
|
;;
|
|
|
|
*)
|
|
echo "Usage: $0 [left|right|up|down|move-left|move-right|move-up|move-down]" >&2
|
|
exit 1
|
|
;;
|
|
esac |