From 52b78aadf8c707683a660f069bea2d2a1efa3506 Mon Sep 17 00:00:00 2001 From: Michael Housh Date: Tue, 7 Oct 2025 14:40:04 -0400 Subject: [PATCH] feat: Updates windowctl subcommands, fixes some logging bugs. Need to remove old files and update keybinds to use windowctl subcommands. --- env/.local/scripts/hypr/logging | 37 +++++-- .../scripts/hypr/utils/windows/close-windows | 8 ++ .../scripts/hypr/utils/windows/focus-window | 84 ++++++++++++++++ .../hypr/utils/windows/window-action-picker | 22 +---- .../hypr/utils/windows/windowctl-picker | 97 +++++++++++++++++++ env/.local/scripts/hypr/windowctl | 85 ++++++---------- gen | 7 +- 7 files changed, 257 insertions(+), 83 deletions(-) create mode 100755 env/.local/scripts/hypr/utils/windows/focus-window create mode 100755 env/.local/scripts/hypr/utils/windows/windowctl-picker diff --git a/env/.local/scripts/hypr/logging b/env/.local/scripts/hypr/logging index f9b2b5e..fcbb75a 100755 --- a/env/.local/scripts/hypr/logging +++ b/env/.local/scripts/hypr/logging @@ -27,10 +27,13 @@ # log --warning "My warning message." # log --error "My error message." # +set -e +set -o nounset +set -o pipefail -LOG_FILE=(${LOG_FILE:-}) -LOG_INVOCATION_ID=${LOG_INVOCATION_ID:-} -LOG_LABEL=${LOG_LABEL:-()} +LOG_FILE=${LOG_FILE:-""} +LOG_INVOCATION_ID=${LOG_INVOCATION_ID:-""} +LOG_LABEL=${LOG_LABEL:-""} # Run in dry run mode, which just prints to the console and does # not log to the files. LOG_ENABLE_DRY_RUN=${LOG_ENABLE_DRY_RUN:-"0"} @@ -104,14 +107,23 @@ logging() { if [[ $LOG_ENABLE_DRY_RUN == "0" ]]; then # Loop over log files logging message to each file. for i in "${!LOG_FILE[@]}"; do - prefix="[id: $LOG_INVOCATION_ID][time: $($SCRIPTS/isosec)][label: ${LOG_LABEL[i]}][source: $source_file] : " - m="$prefix $msg" - echo -e "$m" >>${LOG_FILE[i]} + local file=${LOG_FILE[i]} + local id=$LOG_INVOCATION_ID + local label=${LOG_LABEL[i]:-"$LOG_LABEL"} + local time=$("$SCRIPTS/isosec") + + if [[ -z $file ]] || [[ -z $id ]] || [[ -z $label ]]; then + echo "Loggging not properly setup." + exit 1 + fi + local prefix="[id: $id][time: $time][source: \e[32m$source_file\e[0m][\e[34m$label\e[0m] :" + local m="$prefix $msg" + echo -e "$m" >>"$file" done # Also log errors and warning messages to the console. if [[ $error_flag == "1" ]] || [[ $warn_flag == "1" ]]; then - echo -e "[id: $LOG_INVOCATION_ID]$msg" + echo -e "[id: $id]$msg" fi else # Dry run mode, so just log to the console @@ -141,14 +153,19 @@ setup-logging() { exit 1 fi - LOG_FILE+=("$file") + # Only add files that aren't already in the LOG_FILE. + if [[ ! $LOG_FILE =~ $file ]]; then + LOG_FILE+=("$file") + fi + LOG_INVOCATION_ID=${LOG_INVOCATION_ID:-$RANDOM} - if [[ -n $LOG_LABEL ]]; then + if [[ -n $LOG_LABEL ]] && [[ ! $LOG_LABEL =~ $label ]]; then LOG_LABEL+=("${LOG_LABEL[@]}=>$label") - else + elif [[ ! $LOG_LABEL =~ $label ]]; then LOG_LABEL+=("$label") fi + export LOG_FILE export LOG_LABEL export LOG_INVOCATION_ID diff --git a/env/.local/scripts/hypr/utils/windows/close-windows b/env/.local/scripts/hypr/utils/windows/close-windows index 2e0aed1..cd1a297 100755 --- a/env/.local/scripts/hypr/utils/windows/close-windows +++ b/env/.local/scripts/hypr/utils/windows/close-windows @@ -1,5 +1,9 @@ #!/usr/bin/env bash +set -e +set -o nounset +set -o pipefail + THIS_FILE=${BASH_SOURCE[0]} LOG_LABEL=$(basename "$THIS_FILE") # Allows script name to be set when called from a parent script or defaults to filename. @@ -98,6 +102,10 @@ close() { fi } +################################################################################ +# MAIN +################################################################################ + # Setup logging file and label source "$SCRIPTS/hypr/logging" setup-logging "$LOG_LABEL" diff --git a/env/.local/scripts/hypr/utils/windows/focus-window b/env/.local/scripts/hypr/utils/windows/focus-window new file mode 100755 index 0000000..0e3261d --- /dev/null +++ b/env/.local/scripts/hypr/utils/windows/focus-window @@ -0,0 +1,84 @@ +#!/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") +THIS=${THIS:-$LOG_LABEL} +LOG_FILE=${LOG_FILE:-"/tmp/$LOG_LABEL.log"} + +usage() { + cat <
+ +FLAGS: + -h | --help: Show this help page. + +EOF +} + +# Logging utility function, use in place of echo. +log() { + logging log --source "$THIS_FILE" "$@" +} + +# Prevent hyprctl dispatch calls from printing to the console. +hypr_dispatch() { + hyprctl dispatch "$@" >/dev/null 2>&1 + return $? +} + +focus_window() { + local address=$1 + log "Focusing window, selection: $address" + local name=$(hyprctl clients -j | jq -r ".[] | select(.address == \"$address\") | .workspace.name") + local active_workspace=$(hyprctl activewindow -j | jq -r ".workspace.name") + + log "Window workspace: '$name', active workspace: '$active_workspace'" + if [[ $name =~ ^special ]] && [[ ! $active_workspace == $name ]]; then + log "Toggling special workspace prior to focusing window." + name="${name#special:*}" + hypr_dispatch togglespecialworkspace $name + fi + hypr_dispatch focuswindow "address:$address" +} + +################################################################################ +# MAIN +################################################################################ + +# Setup logging file and label. +source "$SCRIPTS/hypr/logging" +setup-logging "$LOG_FILE" "$LOG_LABEL" +address="" + +while [[ $# -gt 0 ]]; do + if [[ $1 == "-h" ]] || [[ $1 == "--help" ]]; then + usage && exit 0 + else + address=$1 + fi + shift +done + +if [[ -z $address ]]; then + log "Reading address from stdin." + # If an address not supplied then read from stdin, which allows us to pipe the address into + # this command. + read -p "Window address: " address +fi + +if [[ -z $address ]]; then + log --error "No address supplied." && exit 1 +fi + +focus_window $address && exit $? diff --git a/env/.local/scripts/hypr/utils/windows/window-action-picker b/env/.local/scripts/hypr/utils/windows/window-action-picker index dc69cd3..8aef6c5 100755 --- a/env/.local/scripts/hypr/utils/windows/window-action-picker +++ b/env/.local/scripts/hypr/utils/windows/window-action-picker @@ -7,6 +7,7 @@ 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} address="" @@ -17,7 +18,7 @@ if [[ $# == 1 ]]; then else # If an address not supplied then read from stdin, which allows us to pipe the address into # this command. - read -r address + read -p "Window address: " address fi # Logging utility function, use in place of echo. @@ -41,21 +42,6 @@ hypr_dispatch() { return $? } -focus_window() { - log "Focusing window, selection: $address" - - local name=$(hyprctl clients -j | jq -r ".[] | select(.address == \"$address\") | .workspace.name") - local active_workspace=$(hyprctl activewindow -j | jq -r ".workspace.name") - - log "Window workspace: '$name', active workspace: '$active_workspace'" - if [[ $name =~ ^special ]] && [[ ! $active_workspace == $name ]]; then - log "Toggling special workspace prior to focusing window." - name="${name#special:*}" - hypr_dispatch togglespecialworkspace $name - fi - hypr_dispatch focuswindow "address:$address" -} - parse_workspace_id() { local workspace_name="" read -r workspace_name @@ -141,7 +127,7 @@ handle_selection() { log "Copied window address to the clipboard." echo $address | wl-copy elif [[ $choice == "Focus window" ]]; then - focus_window + "$SCRIPTS/hypr/utils/windows/focus-window" $address elif [[ $choice == "Move to workspace" ]]; then move_to_workspace elif [[ $choice == "Move to workspace - silent" ]]; then @@ -162,7 +148,7 @@ handle_selection() { # Setup logging file and label. source "$SCRIPTS/hypr/logging" -setup-logging "$LOG_LABEL" +setup-logging "$LOG_FILE" "$LOG_LABEL" if [[ -z $address ]]; then log --error "Address not set." diff --git a/env/.local/scripts/hypr/utils/windows/windowctl-picker b/env/.local/scripts/hypr/utils/windows/windowctl-picker new file mode 100755 index 0000000..193de21 --- /dev/null +++ b/env/.local/scripts/hypr/utils/windows/windowctl-picker @@ -0,0 +1,97 @@ +#!/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") +THIS=${THIS:-$LOG_LABEL} +LOG_FILE=${LOG_FILE:-"/tmp/$LOG_LABEL.log"} + +usage() { + cat < + +FLAGS: + -h | --help: Show this page. + +EOF +} + +# Logging utility function, use in place of echo. +log() { + logging log --source "$THIS_FILE" "$@" +} + +handle_selected_value() { + local selection="" + read -r selection + + if [[ -z $selection ]]; then + log "No selected value." + return 1 + fi + + log "Prompting for action, window: '$selection'" + + local res=$(echo "$selection" | "$SCRIPTS/hypr/utils/windows/window-action-picker") + log "Action callback result: $res" + echo "$res" + +} + +prompt_for_window_selection() { + local selected_value=$("$SCRIPTS/hypr/window-picker") + local status=$? + if [[ $status -ne 0 ]]; then + exit $status + fi + echo "$selected_value" +} + +################################################################################ +# MAIN +################################################################################ + +# Setup logging file and label. +source "$SCRIPTS/hypr/logging" +setup-logging $LOG_FILE $LOG_LABEL +should_quit="0" + +log "Starting $THIS..." + +while [[ $# -gt 0 ]]; do + if [[ $1 == "-h" ]] || [[ $1 == "--help" ]]; then + usage && exit 0 + elif [[ -n $1 ]]; then + address=$1 + fi + shift +done + +# Load colors if they haven't been loaded already. +[[ -z ${FZF_DEFAULT_OPTS} ]] && + [[ -f $SCRIPTS/catppuccin-colors ]] && + source $SCRIPTS/catppuccin-colors + +trap 'log "Stoping..."; should_quit="1"' SIGINT + +while [[ $should_quit -eq 0 ]]; do + res=$(prompt_for_window_selection | handle_selected_value) + + if [[ ! $res =~ ^back ]]; then + should_quit=1 + elif [[ $res == "back:close" ]]; then + sleep 0.3 # allow time for windows close, to prevent showing closed windows. + fi + + log "Should quit: $should_quit" +done diff --git a/env/.local/scripts/hypr/windowctl b/env/.local/scripts/hypr/windowctl index 3b02c31..3c72137 100755 --- a/env/.local/scripts/hypr/windowctl +++ b/env/.local/scripts/hypr/windowctl @@ -6,26 +6,27 @@ set -o pipefail THIS_FILE=${BASH_SOURCE[0]} THIS=$(basename $THIS_FILE) +LOG_LABEL=$(basename $THIS_FILE) SCRIPTS=${SCRIPTS:-$HOME/.local/scripts} +LOG_FILE=${LOG_FILE:-"/tmp/$LOG_LABEL.log"} usage() { cat < FLAGS: - - -h | --help: Show this page. + -h | --help: Show this page. COMMANDS: - - close: Close window(s). - launch: Launch in a new terminal window, user will be prompted what to do with selected window. + close: Close window(s). + focus: Focuses a window, handling special workspaces properly. + launch: Launches an interactive picker in a new terminal. + picker: Window picker that prompts for an action to perform on the window. Run "$THIS --help" for more information on a command. @@ -34,7 +35,6 @@ EOF window_class="com.ghostty.$THIS" window_padding_x="10" -should_quit="0" log() { logging log --source "$THIS_FILE" "$@" @@ -43,11 +43,15 @@ log() { launch_usage() { cat < + + +FLAGS: + -h | --help: Show this page. EOF } @@ -58,35 +62,17 @@ launch() { launch_usage && exit 0 fi + log "Launching terminal." + ghostty --class="$window_class" --window-padding-x="$window_padding_x" \ --keybind="ctrl+c=quit" \ - -e "${BASH_SOURCE[0]}" "${launch_args[@]}" + -e "${BASH_SOURCE[0]}" "$@" } -handle_selected_value() { - local selection="" - read -r selection - - if [[ -z $selection ]]; then - log "No selected value." - return 1 - fi - - log "Prompting for action, window: '$selection'" - - local res=$(echo "$selection" | "$SCRIPTS/hypr/utils/windows/window-action-picker") - log "Action callback result: $res" - echo "$res" - -} - -prompt_for_window_selection() { - local selected_value=$("$SCRIPTS/hypr/window-picker") - local status=$? - if [[ $status -ne 0 ]]; then - exit $status - fi - echo "$selected_value" +show_picker() { + log "Showing picker..." + THIS="$THIS picker" "$SCRIPTS/hypr/utils/windows/windowctl-picker" "$@" + return $? } ################################################## @@ -95,16 +81,24 @@ prompt_for_window_selection() { # Setup logging file and label. source "$SCRIPTS/hypr/logging" -setup-logging "$THIS" +setup-logging "$LOG_LABEL" while [[ $# -gt 0 ]]; do if [[ $1 == "close" ]]; then shift THIS="$THIS close" "$SCRIPTS/hypr/utils/windows/close-windows" "$@" exit $? + elif [[ $1 == "focus" ]]; then + shift + THIS="$THIS focus" "$SCRIPTS/hypr/utils/windows/focus-window" "$@" + exit $? elif [[ $1 == "launch" ]]; then shift - launch "$@" && exit 0 + launch picker "$@" && exit 0 + elif [[ $1 == "picker" ]]; then + shift + show_picker "$@" + exit $? elif [[ $1 == "-h" ]] || [[ $1 == "--help" ]]; then usage && exit 0 else @@ -113,20 +107,3 @@ while [[ $# -gt 0 ]]; do fi shift done - -# Load colors if they haven't been loaded already. -[[ -z ${FZF_DEFAULT_OPTS} ]] && - [[ -f $SCRIPTS/catppuccin-colors ]] && - source $SCRIPTS/catppuccin-colors - -trap 'log "Stoping..."; should_quit="1"' SIGINT - -while [[ $should_quit -eq 0 ]]; do - res=$(prompt_for_window_selection | handle_selected_value) - if [[ ! $res =~ ^back ]]; then - should_quit=1 - elif [[ $res == "back:close" ]]; then - sleep 0.3 # allow time for windows close, to prevent showing closed windows. - fi - log "Should quit: $should_quit" -done diff --git a/gen b/gen index 68c903b..8645a71 100755 --- a/gen +++ b/gen @@ -74,10 +74,15 @@ generate_script() { cat >"$dest" <<'EOF' #!/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") THIS=${THIS:-$LOG_LABEL} +LOG_FILE=${LOG_FILE:-"/tmp/$LOG_LABEL.log"} # Logging utility function, use in place of echo. log() { @@ -90,7 +95,7 @@ log() { # Setup logging file and label. source "$SCRIPTS/hypr/logging" -setup-logging "$LOG_LABEL" +setup-logging "$LOG_FILE" "$LOG_LABEL" log "Starting $THIS..."