Files
dotfiles/env/.local/scripts/hypr/utils/windows/window-action-picker

241 lines
7.4 KiB
Bash
Executable File

#!/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:-"/tmp/$LOG_LABEL.log"}
THIS=${THIS:-$LOG_LABEL}
FZF_DEFAULT_OPTS=${FZF_DEFAULT_OPTS:-""}
usage() {
cat <<EOF
Shows a picker of actions that can be performed on a window. The chosen action will
be performed on the window.
USAGE:
$ $THIS <flags> <address>
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"
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
# 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/workspace-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/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"
# 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"
echo "$res"