feat(sh): niri spawning script for stacking two windows of same app vertically
This commit is contained in:
@@ -28,7 +28,7 @@ in
|
|||||||
enableFishIntegration = config.programs.fish.enable;
|
enableFishIntegration = config.programs.fish.enable;
|
||||||
enableZshIntegration = config.programs.zsh.enable;
|
enableZshIntegration = config.programs.zsh.enable;
|
||||||
settings = {
|
settings = {
|
||||||
theme = "GruvboxDarkHard";
|
theme = "Gruvbox Dark Hard";
|
||||||
focus-follows-mouse = true;
|
focus-follows-mouse = true;
|
||||||
resize-overlay = "never";
|
resize-overlay = "never";
|
||||||
background-opacity = 0.95;
|
background-opacity = 0.95;
|
||||||
|
|||||||
77
scripts/bin/ghostty-spawn.sh
Normal file
77
scripts/bin/ghostty-spawn.sh
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
# Ghostty spawn-or-focus logic for Niri:
|
||||||
|
# If no Ghostty windows exist, spawn one.
|
||||||
|
# If focused window is not Ghostty, focus the first Ghostty instance.
|
||||||
|
# If Ghostty is focused and only one instance exists, spawn + consume into stack.
|
||||||
|
# If Ghostty is focused and two instances already exist, spawn a new separate one.
|
||||||
|
# Cycle repeats: focus first > allow stack of 2 > reset on 3rd.
|
||||||
|
|
||||||
|
APP_ID="com.mitchellh.ghostty"
|
||||||
|
APP_CMD="ghostty"
|
||||||
|
|
||||||
|
WINDOW_DATA=$(niri msg -j windows)
|
||||||
|
|
||||||
|
readarray -t GHOSTTY_IDS < <(
|
||||||
|
echo "$WINDOW_DATA" | jq -r --arg app_id "$APP_ID" '
|
||||||
|
[ .[] | select(.app_id == $app_id) ]
|
||||||
|
| sort_by(.layout.pos_in_scrolling_layout // [0,0])
|
||||||
|
| .[].id
|
||||||
|
'
|
||||||
|
)
|
||||||
|
|
||||||
|
COUNT=${#GHOSTTY_IDS[@]}
|
||||||
|
|
||||||
|
FOCUSED_IS_GHOSTTY=$(
|
||||||
|
echo "$WINDOW_DATA" | jq -r --arg app_id "$APP_ID" '
|
||||||
|
any(.[]; .app_id == $app_id and .is_focused)
|
||||||
|
'
|
||||||
|
)
|
||||||
|
|
||||||
|
spawn_normal() {
|
||||||
|
"$APP_CMD" &
|
||||||
|
}
|
||||||
|
|
||||||
|
spawn_and_consume() {
|
||||||
|
local initial_ids=("$@")
|
||||||
|
"$APP_CMD" &
|
||||||
|
local pid=$!
|
||||||
|
|
||||||
|
for _ in {1..50}; do
|
||||||
|
readarray -t after_ids < <(
|
||||||
|
niri msg -j windows | jq -r --arg app_id "$APP_ID" '
|
||||||
|
[ .[] | select(.app_id == $app_id) ]
|
||||||
|
| sort_by(.layout.pos_in_scrolling_layout // [0,0])
|
||||||
|
| .[].id
|
||||||
|
'
|
||||||
|
)
|
||||||
|
|
||||||
|
NEW_ID=""
|
||||||
|
for id in "${after_ids[@]}"; do
|
||||||
|
[[ " ${initial_ids[*]} " == *" $id "* ]] || NEW_ID="$id"
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ -n "$NEW_ID" ]; then
|
||||||
|
niri msg action focus-window --id "${initial_ids[$((${#initial_ids[@]} - 1))]}"
|
||||||
|
niri msg action consume-window-into-column
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
sleep 0.05
|
||||||
|
done
|
||||||
|
|
||||||
|
wait "$pid" 2>/dev/null || true
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((COUNT == 0)); then
|
||||||
|
spawn_normal
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$FOCUSED_IS_GHOSTTY" != "true" ]; then
|
||||||
|
niri msg action focus-window --id "${GHOSTTY_IDS[0]}"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ((COUNT % 2 == 0)); then
|
||||||
|
spawn_normal
|
||||||
|
else
|
||||||
|
spawn_and_consume "${GHOSTTY_IDS[@]}"
|
||||||
|
fi
|
||||||
82
scripts/bin/spawn.sh
Normal file
82
scripts/bin/spawn.sh
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
# Spawn-or-focus logic for Niri:
|
||||||
|
# If no "app" windows exist, spawn one.
|
||||||
|
# If focused window is not "app", focus the first "app" instance.
|
||||||
|
# If "app" is focused and only one instance exists, spawn + consume into stack.
|
||||||
|
# If "app" is focused and two instances already exist, spawn a new separate one.
|
||||||
|
# Cycle repeats: focus first > allow stack of 2 > reset on 3rd.
|
||||||
|
|
||||||
|
if [ $# -lt 1 ]; then
|
||||||
|
echo "Usage: $0 <APP_ID> [APP_CMD]" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
APP_ID="$1"
|
||||||
|
APP_CMD="${2:-$1}"
|
||||||
|
|
||||||
|
WINDOW_DATA=$(niri msg -j windows)
|
||||||
|
|
||||||
|
readarray -t APP_IDS < <(
|
||||||
|
echo "$WINDOW_DATA" | jq -r --arg app_id "$APP_ID" '
|
||||||
|
[ .[] | select(.app_id == $app_id) ]
|
||||||
|
| sort_by(.layout.pos_in_scrolling_layout // [0,0])
|
||||||
|
| .[].id
|
||||||
|
'
|
||||||
|
)
|
||||||
|
|
||||||
|
COUNT=${#APP_IDS[@]}
|
||||||
|
|
||||||
|
FOCUSED_IS_APP=$(
|
||||||
|
echo "$WINDOW_DATA" | jq -r --arg app_id "$APP_ID" '
|
||||||
|
any(.[]; .app_id == $app_id and .is_focused)
|
||||||
|
'
|
||||||
|
)
|
||||||
|
|
||||||
|
spawn_normal() {
|
||||||
|
"$APP_CMD" &
|
||||||
|
}
|
||||||
|
|
||||||
|
spawn_and_consume() {
|
||||||
|
local initial_ids=("$@")
|
||||||
|
"$APP_CMD" &
|
||||||
|
local pid=$!
|
||||||
|
|
||||||
|
for _ in {1..50}; do
|
||||||
|
readarray -t after_ids < <(
|
||||||
|
niri msg -j windows | jq -r --arg app_id "$APP_ID" '
|
||||||
|
[ .[] | select(.app_id == $app_id) ]
|
||||||
|
| sort_by(.layout.pos_in_scrolling_layout // [0,0])
|
||||||
|
| .[].id
|
||||||
|
'
|
||||||
|
)
|
||||||
|
|
||||||
|
NEW_ID=""
|
||||||
|
for id in "${after_ids[@]}"; do
|
||||||
|
[[ " ${initial_ids[*]} " == *" $id "* ]] || NEW_ID="$id"
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ -n "$NEW_ID" ]; then
|
||||||
|
niri msg action focus-window --id "${initial_ids[$((${#initial_ids[@]} - 1))]}"
|
||||||
|
niri msg action consume-window-into-column
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
sleep 0.05
|
||||||
|
done
|
||||||
|
|
||||||
|
wait "$pid" 2>/dev/null || true
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((COUNT == 0)); then
|
||||||
|
spawn_normal
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$FOCUSED_IS_APP" != "true" ]; then
|
||||||
|
niri msg action focus-window --id "${APP_IDS[0]}"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ((COUNT % 2 == 0)); then
|
||||||
|
spawn_normal
|
||||||
|
else
|
||||||
|
spawn_and_consume "${APP_IDS[@]}"
|
||||||
|
fi
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
# Log file location
|
|
||||||
LOGFILE="/home/$USER/.cache/tuirun/tuirun-toggle.log"
|
|
||||||
# Redirect all output and errors to the log file
|
|
||||||
exec >>"$LOGFILE" 2>&1
|
|
||||||
# Enable command tracing
|
|
||||||
set -x
|
|
||||||
|
|
||||||
echo "Script started at $(date)"
|
|
||||||
|
|
||||||
# Log the environment variables
|
|
||||||
echo "Environment variables:"
|
|
||||||
env
|
|
||||||
|
|
||||||
# Define TERMINAL if not set
|
|
||||||
TERMINAL="${TERMINAL:-foot}"
|
|
||||||
echo "TERMINAL is set to: $TERMINAL"
|
|
||||||
|
|
||||||
# Ensure USER is set
|
|
||||||
USER="${USER:-$(whoami)}"
|
|
||||||
echo "USER is set to: $USER"
|
|
||||||
|
|
||||||
# Path to the tuirun executable
|
|
||||||
TUIRUN_PATH="/etc/profiles/per-user/$USER/bin/tuirun"
|
|
||||||
echo "TUIRUN_PATH is set to: $TUIRUN_PATH"
|
|
||||||
|
|
||||||
# Use absolute paths for commands
|
|
||||||
PGREP="/run/current-system/sw/bin/pgrep"
|
|
||||||
PKILL="/run/current-system/sw/bin/pkill"
|
|
||||||
HYPRCTL="/etc/profiles/per-user/$USER/bin/hyprctl"
|
|
||||||
|
|
||||||
echo "Checking if tuirun is already running..."
|
|
||||||
|
|
||||||
if "$PGREP" -f "$TERMINAL --title tuirun" >/dev/null; then
|
|
||||||
echo "Found existing tuirun process. Terminating..."
|
|
||||||
"$PKILL" -f "$TERMINAL --title tuirun"
|
|
||||||
else
|
|
||||||
echo "No existing tuirun process. Starting a new one..."
|
|
||||||
"$HYPRCTL" dispatch exec "$TERMINAL --title tuirun -e $TUIRUN_PATH"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Script finished at $(date)"
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
# Define TERMINAL if not set
|
|
||||||
TERMINAL="${TERMINAL:-foot}"
|
|
||||||
|
|
||||||
# Use absolute paths for commands
|
|
||||||
PGREP="/run/current-system/sw/bin/pgrep"
|
|
||||||
PKILL="/run/current-system/sw/bin/pkill"
|
|
||||||
UWSM="/run/current-system/sw/bin/uwsm"
|
|
||||||
TUIRUN_PATH="/etc/profiles/per-user/$USER/bin/tuirun"
|
|
||||||
|
|
||||||
# Determine OPTIONS based on TERMINAL
|
|
||||||
if [ "$TERMINAL" = "foot" ]; then
|
|
||||||
OPTIONS="--override=main.pad=0x0"
|
|
||||||
elif [ "$TERMINAL" = "alacritty" ]; then
|
|
||||||
OPTIONS="--option window.padding.x=0 --option window.padding.y=0"
|
|
||||||
else
|
|
||||||
OPTIONS=""
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Matching pattern for the process
|
|
||||||
MATCH_PATTERN="$TERMINAL --title tuirun"
|
|
||||||
if "$PGREP" -f "$MATCH_PATTERN" >/dev/null; then
|
|
||||||
echo "$(date): Killing existing process"
|
|
||||||
"$PKILL" -f "$MATCH_PATTERN"
|
|
||||||
else
|
|
||||||
# Log the environment for debugging
|
|
||||||
env >/tmp/script_env.txt
|
|
||||||
# Construct the command as an array for proper argument handling
|
|
||||||
CMD=("$TERMINAL" "--title" "tuirun")
|
|
||||||
if [ -n "$OPTIONS" ]; then
|
|
||||||
CMD+=("$OPTIONS")
|
|
||||||
fi
|
|
||||||
CMD+=("-e" "$TUIRUN_PATH")
|
|
||||||
|
|
||||||
echo "$(date): Executing command: ${CMD[*]}"
|
|
||||||
# Use eval to expand the command or pass the arguments directly
|
|
||||||
"$UWSM" app -- "${CMD[@]}"
|
|
||||||
fi
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
# Define TERMINAL if not set
|
|
||||||
TERMINAL="${TERMINAL:-foot}"
|
|
||||||
|
|
||||||
# Use absolute paths for commands
|
|
||||||
PGREP="/run/current-system/sw/bin/pgrep"
|
|
||||||
PKILL="/run/current-system/sw/bin/pkill"
|
|
||||||
HYPRCTL="/etc/profiles/per-user/$USER/bin/hyprctl"
|
|
||||||
TUIRUN_PATH="/etc/profiles/per-user/$USER/bin/tuirun"
|
|
||||||
|
|
||||||
# Determine OPTIONS based on TERMINAL
|
|
||||||
if [ "$TERMINAL" = "foot" ]; then
|
|
||||||
OPTIONS="--override=main.pad=0x0"
|
|
||||||
elif [ "$TERMINAL" = "alacritty" ]; then
|
|
||||||
OPTIONS="--option window.padding.x=0 --option window.padding.y=0"
|
|
||||||
else
|
|
||||||
OPTIONS=""
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Matching pattern for the process
|
|
||||||
MATCH_PATTERN="$TERMINAL --title tuirun"
|
|
||||||
if "$PGREP" -f "$MATCH_PATTERN" >/dev/null; then
|
|
||||||
"$PKILL" -f "$MATCH_PATTERN"
|
|
||||||
else
|
|
||||||
# Construct the command
|
|
||||||
CMD="$TERMINAL --title tuirun"
|
|
||||||
if [ -n "$OPTIONS" ]; then
|
|
||||||
CMD="$CMD $OPTIONS"
|
|
||||||
fi
|
|
||||||
# Use login shell to ensure proper environment
|
|
||||||
CMD="$CMD -e $SHELL -l -c '$TUIRUN_PATH'"
|
|
||||||
# Launch the terminal with OPTIONS
|
|
||||||
"$HYPRCTL" dispatch exec "$CMD"
|
|
||||||
fi
|
|
||||||
@@ -12,8 +12,17 @@ in
|
|||||||
{
|
{
|
||||||
home = {
|
home = {
|
||||||
sessionPath = [ "${config.home.homeDirectory}/.local/bin" ];
|
sessionPath = [ "${config.home.homeDirectory}/.local/bin" ];
|
||||||
|
|
||||||
file = {
|
file = {
|
||||||
|
".local/bin/spawn.sh" = {
|
||||||
|
source = getExe (
|
||||||
|
pkgs.writeShellApplication {
|
||||||
|
name = "spawn";
|
||||||
|
runtimeInputs = with pkgs; [ niri ];
|
||||||
|
text = readFile ./bin/spawn.sh;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
".local/bin/spawn-or-focus.sh" = {
|
".local/bin/spawn-or-focus.sh" = {
|
||||||
source = getExe (
|
source = getExe (
|
||||||
pkgs.writeShellApplication {
|
pkgs.writeShellApplication {
|
||||||
@@ -34,34 +43,6 @@ in
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
".local/bin/tuirun-toggle.sh" = {
|
|
||||||
source = getExe (
|
|
||||||
pkgs.writeShellApplication {
|
|
||||||
name = "tuirun-toggle";
|
|
||||||
runtimeInputs = with pkgs; [
|
|
||||||
hyprland
|
|
||||||
uwsm
|
|
||||||
];
|
|
||||||
text = readFile ./bin/tuirun-toggle.sh;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
".local/bin/tuirun-debugger.sh" = {
|
|
||||||
source = getExe (
|
|
||||||
pkgs.writeShellApplication {
|
|
||||||
name = "tuirun-debugger";
|
|
||||||
runtimeInputs = with pkgs; [ hyprland ];
|
|
||||||
text = ''
|
|
||||||
# Save environment to file
|
|
||||||
env > /tmp/tuirun-env.txt
|
|
||||||
# Run tuirun
|
|
||||||
/etc/profiles/per-user/cnst/bin/tuirun
|
|
||||||
'';
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
".local/bin/calcurse-toggle.sh" = {
|
".local/bin/calcurse-toggle.sh" = {
|
||||||
source = getExe (
|
source = getExe (
|
||||||
pkgs.writeShellApplication {
|
pkgs.writeShellApplication {
|
||||||
|
|||||||
Reference in New Issue
Block a user