#!/usr/bin/env bash set -e set -o nounset set -o pipefail SCRIPTS=${SCRIPTS:-$HOME/.local/scripts} THIS_FILE=${BASH_SOURCE[0]} LOG_LABEL=$(basename "$THIS_FILE") LOG_FILE=${LOG_FILE:-"$LOG_LABEL.log"} THIS=${THIS:-$LOG_LABEL} FZF_DEFAULT_OPTS=${FZF_DEFAULT_OPTS:-""} usage() { cat <
FLAGS: -a | --active: Uses the active window to perform the selected action. --show-back: Shows a back option in the list of choices, useful when called from another script. -h | --help: Show this help page. EOF } address="" move_silent_flag="0" show_back_choice="0" # Logging utility function, use in place of echo. log() { logging log --source "$THIS_FILE" "$@" } action_footer() { cat <<'EOF' ___ __ _ / _ |____/ /_(_)__ ___ / __ / __/ __/ / _ \/ _ \ /_/ |_\__/\__/_/\___/_//_/ EOF } # Prevent hyprctl dispatch calls from printing to the console. hypr_dispatch() { hyprctl dispatch "$@" >/dev/null 2>&1 return $? } parse_workspace_id() { local workspace_name="" read -r workspace_name log "Parsing selected workspace name: $workspace_name" if [[ -z $workspace_name ]]; then log --error "No workspace set to move window to." && exit 1 fi if [[ $workspace_name =~ ^special ]]; then log "Special workspace, returning name." echo $workspace_name else local id="$(hyprctl workspaces -j | jq -r ".[] | select(.name | contains(\"$workspace_name\")) | .id")" log "Selected workspace id: $id" echo "$id" fi } move_to_workspace() { log "Moving window: '$address'" log "Prompting for workspace to move to..." local action="movetoworkspace" if [[ $move_silent_flag == "1" ]]; then action="movetoworkspacesilent" fi $SCRIPTS/hypr/workspacectl picker --return-name-if-special --header="Select a workspace to move window to:" | parse_workspace_id | xargs -I{} hyprctl dispatch "$action" "{},address:$address" >/dev/null 2>&1 return $? } toggle_floating() { log "Toggling floating..." local did_handle="0" local should_prompt_for_size="1" local is_floating=$(hyprctl clients -j | jq ".[] | select(.address == \"$address\") | .floating") if [[ $is_floating == "false" ]]; then gum confirm "Would you like to set the size of the float?" should_prompt_for_size=$? fi if [[ $should_prompt_for_size == "0" ]]; then log "Prompting for size..." placeholder="Example: 80% or 1000" width=$(gum input --placeholder="$placeholder" --header="Window Width:") height=$(gum input --placeholder="$placeholder" --header="Window Height:") if [[ -n $width ]] && [[ -n $height ]]; then "$SCRIPTS/hypr/utils/windows/window-toggle-floating" "$address" --width "$width" --height "$height" did_handle="1" else log --warning "Did not get both width: '$width' and height: '$height', not setting window size." fi fi if [[ $did_handle == "0" ]]; then "$SCRIPTS/hypr/utils/windows/window-toggle-floating" "$address" fi } make_selection() { log "Prompting for window action..." local choices=( "$address:Focus the selected window.:Focus window" "$address:Close the selected window.:Close window" "$address:Close the selected window and go back to the window list.:Close window and back" "$address:Move the selected window to another workspace, focusing the window.\n\nA workspace picker will be presented to choose which workspace to move to.:Move to workspace" "$address:Move the selected window to another workspace, without focusing the window.\n\nA workspace picker will be presented to choose which workspace to move to.:Move to workspace - silent" "$address:Toggles the selected windows floating property.\n\nIf the window is not floating then you will be prompted if you want to set the size or not.:Toggle floating" "$address:Copy the window address to the system clipboard:Copy to clipboard" ) if [[ $show_back_choice == "1" ]]; then log "Adding show back choice option." choices+=("$address:Move back to window picker and reload windows.:Back") fi choices+=("$address:Quit and close the application:Quit") local choice=$( printf "%s\n" "${choices[@]}" | fzf --style=full --footer="$(action_footer)" \ --delimiter=':' --with-nth=3 \ --header="What should we do with the selected window?" \ --preview-label="[ Description ]" \ --preview='echo -e {2} | fmt -w ${FZF_PREVIEW_COLUMNS:-40}; echo -e "\n\n\e[35mSelected Window:\e[0m"; "$SCRIPTS/hypr/utils/fzf/preview-stats" window {1} "{title, workspace, address, floating}";' ) # Exit if non-zero code returned from making selection. [[ $? -gt 0 ]] && log --error "Unexpected fzf status: $?" && exit $? # Set choice to just the action portion. choice="${choice##*:}" echo "$choice" } # Set appropriate flags based on the choice and perform the action on the window address. handle_selection() { local resp="done" local choice="" read -r choice log "Action Choice: $choice" if [[ $choice == "Quit" ]]; then log "Quitting..." elif [[ $choice == "Close window" ]]; then log "Closing window..." "$SCRIPTS/hypr/close-windows" "$address" elif [[ $choice == "Close window and back" ]]; then log "Closing window and setting should go back flag." "$SCRIPTS/hypr/close-windows" "$address" resp="back:close" elif [[ $choice == "Copy to clipboard" ]]; then log "Copied window address to the clipboard." echo $address | wl-copy elif [[ $choice == "Focus window" ]]; then "$SCRIPTS/hypr/utils/windows/focus-window" $address elif [[ $choice == "Move to workspace" ]]; then move_to_workspace elif [[ $choice == "Move to workspace - silent" ]]; then move_silent_flag="1" move_to_workspace resp="back" elif [[ $choice == "Toggle floating" ]]; then toggle_floating elif [[ $choice == "Back" ]]; then resp="back" fi echo "$resp" } ################################################################################ # MAIN ################################################################################ # Setup logging file and label. source "$SCRIPTS/hypr/logging" setup-logging "$LOG_FILE" "$LOG_LABEL" while [[ $# -gt 0 ]]; do if [[ $1 == "-h" ]] || [[ $1 == "--help" ]]; then usage && exit 0 elif [[ $1 == "-a" ]] || [[ $1 == "--active" ]]; then class=$(hyprctl activewindow -j | jq -r '.class') if [[ $class == "com.ghostty.windowctl" ]]; then # Select the previously focused window if we were launched in a new terminal window. address=$(hyprctl clients -j | jq -r '.[] | select(.focusHistoryID == 1) | .address') else # Select the active address if not. address=$(hyprctl activewindow -j | jq -r '.address') fi elif [[ $1 == "--show-back" ]]; then show_back_choice="1" else address=$1 fi shift done # If an address not supplied then read from stdin, which allows us to pipe the address into # this command. if [[ -z $address ]]; then read -p "Window address: " address fi # Load colors if they haven't been loaded already. [[ -z ${FZF_DEFAULT_OPTS} ]] && [[ -f $SCRIPTS/catppuccin-colors ]] && source $SCRIPTS/catppuccin-colors if [[ -z $address ]]; then log --error "Address not set." exit 1 fi res=$(make_selection | handle_selection) log "Action result: $res" # Returns "done | back | back:close" for parent script to know how to handle. echo "$res"