diff --git a/modules/home/programs/ghostty/default.nix b/modules/home/programs/ghostty/default.nix index 365b8115..3dc3e646 100644 --- a/modules/home/programs/ghostty/default.nix +++ b/modules/home/programs/ghostty/default.nix @@ -28,7 +28,7 @@ in enableFishIntegration = config.programs.fish.enable; enableZshIntegration = config.programs.zsh.enable; settings = { - theme = "GruvboxDarkHard"; + theme = "Gruvbox Dark Hard"; focus-follows-mouse = true; resize-overlay = "never"; background-opacity = 0.95; diff --git a/scripts/bin/ghostty-spawn.sh b/scripts/bin/ghostty-spawn.sh new file mode 100644 index 00000000..fdf682c8 --- /dev/null +++ b/scripts/bin/ghostty-spawn.sh @@ -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 diff --git a/scripts/bin/spawn.sh b/scripts/bin/spawn.sh new file mode 100644 index 00000000..596273e8 --- /dev/null +++ b/scripts/bin/spawn.sh @@ -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_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 diff --git a/scripts/bin/tuirun-debug.sh b/scripts/bin/tuirun-debug.sh deleted file mode 100755 index d8013040..00000000 --- a/scripts/bin/tuirun-debug.sh +++ /dev/null @@ -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)" diff --git a/scripts/bin/tuirun-toggle.sh b/scripts/bin/tuirun-toggle.sh deleted file mode 100755 index fe8825fa..00000000 --- a/scripts/bin/tuirun-toggle.sh +++ /dev/null @@ -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 diff --git a/scripts/bin/tuirun-toggle.shbak b/scripts/bin/tuirun-toggle.shbak deleted file mode 100755 index 55b0f1cf..00000000 --- a/scripts/bin/tuirun-toggle.shbak +++ /dev/null @@ -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 diff --git a/scripts/default.nix b/scripts/default.nix index e2e2acb4..4c44dcaa 100644 --- a/scripts/default.nix +++ b/scripts/default.nix @@ -12,8 +12,17 @@ in { home = { sessionPath = [ "${config.home.homeDirectory}/.local/bin" ]; - 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" = { source = getExe ( 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" = { source = getExe ( pkgs.writeShellApplication {