浏览代码

dev: automated commit - 2025-11-11 11:58:51

Mariano Z. 2 月之前
父节点
当前提交
7dbe7f4685
共有 3 个文件被更改,包括 121 次插入15 次删除
  1. 49 4
      local-bin/.local/bin/dev-launcher
  2. 67 11
      local-bin/.local/bin/launch-or-focus
  3. 5 0
      zsh/.config/zsh/functions/utils.zsh

+ 49 - 4
local-bin/.local/bin/dev-launcher

@@ -5,12 +5,21 @@ set -euo pipefail
 CACHE_MAX_AGE=300
 MRU_SIZE=20
 
+# Debug logging (set DEBUG=1 to enable)
+DEBUG="${DEBUG:-0}"
+
+debug() {
+    [ "$DEBUG" = "1" ] && echo "[DEBUG] $*" >&2 || true
+}
+
 # Parse arguments - flags first, then DEV_DIR
 NO_CACHE=false
 CLEAR_CACHE=false
 EDITOR="${EDITOR:-nvim}"
 DEV_DIR=""
 
+debug "Starting dev-launcher with args: $*"
+
 for arg in "$@"; do
     case "$arg" in
     --help | -h)
@@ -37,11 +46,16 @@ EOF
 done
 
 DEV_DIR="${DEV_DIR:-$HOME/Dev}"
+debug "DEV_DIR: $DEV_DIR"
+debug "NO_CACHE: $NO_CACHE"
+debug "CLEAR_CACHE: $CLEAR_CACHE"
 
 # Setup cache files (unique per dev directory)
 DEV_DIR_HASH=$(echo -n "$DEV_DIR" | sha256sum | cut -d' ' -f1 | head -c 16)
 CACHE_FILE="$HOME/.cache/dev-launcher-cache-${DEV_DIR_HASH}"
 MRU_FILE="$HOME/.cache/dev-launcher-mru-${DEV_DIR_HASH}"
+debug "CACHE_FILE: $CACHE_FILE"
+debug "MRU_FILE: $MRU_FILE"
 
 # Handle --clear-cache
 if [ "$CLEAR_CACHE" = true ]; then
@@ -52,17 +66,29 @@ fi
 
 # Find git repositories
 find_git_repos() {
+    debug "find_git_repos: checking cache..."
     if [ "$NO_CACHE" = false ] && [ -f "$CACHE_FILE" ]; then
         local cache_age=$(($(date +%s) - $(stat -c %Y "$CACHE_FILE" 2>/dev/null || echo 0)))
-        [ $cache_age -lt $CACHE_MAX_AGE ] && cat "$CACHE_FILE" && return
+        debug "Cache age: ${cache_age}s (max: ${CACHE_MAX_AGE}s)"
+        if [ $cache_age -lt $CACHE_MAX_AGE ]; then
+            debug "Using cached repos"
+            cat "$CACHE_FILE"
+            return
+        fi
+        debug "Cache expired, rescanning..."
     fi
 
+    debug "Scanning for git repositories in $DEV_DIR..."
     if command -v fd >/dev/null 2>&1; then
+        debug "Using fd for scanning"
         fd -H -t d "^\.git$" "$DEV_DIR" -d 3 -0 | xargs -0 -n1 dirname | sort -u >"$CACHE_FILE"
     else
+        debug "Using find for scanning"
         find "$DEV_DIR" -maxdepth 3 -type d -name ".git" -print0 |
             xargs -0 -n1 dirname | sort -u >"$CACHE_FILE"
     fi
+    local repo_count=$(wc -l < "$CACHE_FILE")
+    debug "Found $repo_count repositories"
     cat "$CACHE_FILE"
 }
 
@@ -106,18 +132,27 @@ sort_by_mru() {
 # Main execution
 REPOS=$(find_git_repos)
 
-[ -z "$REPOS" ] && notify-send "Dev Launcher" "No git repositories found in $DEV_DIR" 2>/dev/null && exit 1
+if [ -z "$REPOS" ]; then
+    debug "No repositories found!"
+    notify-send "Dev Launcher" "No git repositories found in $DEV_DIR" 2>/dev/null || true
+    exit 1
+fi
+debug "Found repositories, proceeding..."
 
 # Build display list (relative paths) and mapping
 DISPLAY_LIST=$(echo "$REPOS" | sed "s|^${DEV_DIR}/||")
 declare -A DISPLAY_TO_PATH
 
+debug "Building display mapping..."
 while IFS=$'\t' read -r repo display; do
     DISPLAY_TO_PATH["$display"]="$repo"
 done < <(paste <(echo "$REPOS") <(echo "$DISPLAY_LIST"))
+debug "Mapped ${#DISPLAY_TO_PATH[@]} projects"
 
 # Sort by MRU and present in tofi
+debug "Sorting by MRU..."
 SORTED_LIST=$(sort_by_mru "$DISPLAY_LIST")
+debug "Presenting in tofi..."
 SELECTED_DISPLAY=$(echo "$SORTED_LIST" | tofi \
     --prompt-text "💀 Poison: " \
     --fuzzy-match true \
@@ -139,21 +174,31 @@ SELECTED_DISPLAY=$(echo "$SORTED_LIST" | tofi \
     --border-color '#31748f' \
     --prompt-color '#f6c177')
 
-[ -z "$SELECTED_DISPLAY" ] && exit 0
+debug "Selected display: '$SELECTED_DISPLAY'"
+[ -z "$SELECTED_DISPLAY" ] && debug "No selection, exiting" && exit 0
 
 # Remove star indicator and lookup path
 SELECTED_DISPLAY_CLEAN=$(echo "$SELECTED_DISPLAY" | sed 's/^⭐ //')
 SELECTED="${DISPLAY_TO_PATH[$SELECTED_DISPLAY_CLEAN]:-}"
 
-[ -z "$SELECTED" ] || [ ! -d "$SELECTED" ] && exit 0
+debug "Selected display (clean): '$SELECTED_DISPLAY_CLEAN'"
+debug "Selected path: '$SELECTED'"
+
+[ -z "$SELECTED" ] || [ ! -d "$SELECTED" ] && debug "Invalid selection, exiting" && exit 0
 
 # Update MRU and launch
+debug "Updating MRU..."
 update_mru "$SELECTED_DISPLAY_CLEAN"
 
 PROJECT_NAME=$(get_project_name "$SELECTED")
 SESSION_NAME="dev-${PROJECT_NAME}"
 CLASS_NAME="com.mzunino.dev.${PROJECT_NAME}"
 
+debug "Project name: $PROJECT_NAME"
+debug "Session name: $SESSION_NAME"
+debug "Class name: $CLASS_NAME"
+debug "Launching ghostty with launch-or-focus..."
+
 launch-or-focus ghostty \
     --working-directory="$SELECTED" \
     --title="$PROJECT_NAME" \

+ 67 - 11
local-bin/.local/bin/launch-or-focus

@@ -3,6 +3,13 @@ set -euo pipefail
 
 # Script to launch an application or focus it if already running in sway
 # Usage: launch-or-focus <command> [args...]
+# Set DEBUG=1 to enable debug logging
+
+DEBUG="${DEBUG:-0}"
+
+debug() {
+    [ "$DEBUG" = "1" ] && echo "[DEBUG] $*" >&2 || true
+}
 
 if [ $# -eq 0 ]; then
     echo "Usage: $0 <command> [args...]" >&2
@@ -14,6 +21,9 @@ shift
 ARGS=("$@")
 
 APP_NAME=$(basename "$COMMAND")
+debug "Command: $COMMAND"
+debug "App name: $APP_NAME"
+debug "Args: ${ARGS[*]}"
 
 # Extract --class and --title values from args if present
 # Handle both --class VALUE and --class=VALUE formats
@@ -22,25 +32,35 @@ TITLE_NAME=""
 for i in "${!ARGS[@]}"; do
     if [[ "${ARGS[$i]}" =~ ^--class=(.+)$ ]]; then
         CLASS_NAME="${BASH_REMATCH[1]}"
+        debug "Found class (format --class=VALUE): $CLASS_NAME"
     elif [ "${ARGS[$i]}" = "--class" ] && [ $((i+1)) -lt ${#ARGS[@]} ]; then
         CLASS_NAME="${ARGS[$((i+1))]}"
+        debug "Found class (format --class VALUE): $CLASS_NAME"
     elif [[ "${ARGS[$i]}" =~ ^--title=(.+)$ ]]; then
         TITLE_NAME="${BASH_REMATCH[1]}"
+        debug "Found title (format --title=VALUE): $TITLE_NAME"
     elif [ "${ARGS[$i]}" = "--title" ] && [ $((i+1)) -lt ${#ARGS[@]} ]; then
         TITLE_NAME="${ARGS[$((i+1))]}"
+        debug "Found title (format --title VALUE): $TITLE_NAME"
     fi
 done
+debug "Extracted CLASS_NAME: '$CLASS_NAME'"
+debug "Extracted TITLE_NAME: '$TITLE_NAME'"
 
 find_window_by_class() {
     local class="$1"
-    swaymsg -t get_tree | jq -r --arg class "$class" '
+    debug "Searching for window by class: $class"
+    local result
+    result=$(swaymsg -t get_tree | jq -r --arg class "$class" '
         recurse(.nodes[]?, .floating_nodes[]?) |
         select(
             ((.window_properties.class | type) == "string" and .window_properties.class == $class) or
             ((.app_id | type) == "string" and .app_id == $class)
         ) |
         .id
-    ' | head -n 1
+    ' | head -n 1)
+    debug "find_window_by_class result: '$result'"
+    echo "$result"
 }
 
 find_window_by_title() {
@@ -48,6 +68,8 @@ find_window_by_title() {
     local app="$2"
     local result
     
+    debug "Searching for window by title: '$title' and app: '$app'"
+    
     # Search for windows matching both app and title (most specific)
     result=$(swaymsg -t get_tree | jq -r --arg title "$title" --arg app "$app" '
         recurse(.nodes[]?, .floating_nodes[]?) |
@@ -61,28 +83,36 @@ find_window_by_title() {
         .id
     ' | head -n 1)
     
+    debug "find_window_by_title (app+title) result: '$result'"
     [ -n "$result" ] && [ "$result" != "null" ] && echo "$result" && return
     
     # Fall back to title-only exact match
+    debug "Falling back to title-only exact match"
     result=$(swaymsg -t get_tree | jq -r --arg title "$title" '
         recurse(.nodes[]?, .floating_nodes[]?) |
         select((.name | type) == "string" and .name == $title) |
         .id
     ' | head -n 1)
     
+    debug "find_window_by_title (title only) result: '$result'"
     [ -n "$result" ] && [ "$result" != "null" ] && echo "$result" && return
     
     # Final fallback: title-only case-insensitive match
-    swaymsg -t get_tree | jq -r --arg title "$title" '
+    debug "Falling back to title-only case-insensitive match"
+    result=$(swaymsg -t get_tree | jq -r --arg title "$title" '
         recurse(.nodes[]?, .floating_nodes[]?) |
         select((.name | type) == "string" and (.name | test($title; "i"))) |
         .id
-    ' | head -n 1
+    ' | head -n 1)
+    debug "find_window_by_title (case-insensitive) result: '$result'"
+    echo "$result"
 }
 
 find_window() {
     local app_name="$1"
-    swaymsg -t get_tree | jq -r --arg app "$app_name" '
+    debug "Searching for window by app name: $app_name"
+    local result
+    result=$(swaymsg -t get_tree | jq -r --arg app "$app_name" '
         recurse(.nodes[]?, .floating_nodes[]?) |
         select(
             ((.app_id | type) == "string" and (.app_id == $app or (.app_id | test($app; "i")))) or
@@ -90,22 +120,48 @@ find_window() {
             ((.name | type) == "string" and (.name | test($app; "i")))
         ) |
         .id
-    ' | head -n 1
+    ' | head -n 1)
+    debug "find_window result: '$result'"
+    echo "$result"
 }
 
 focus_window() {
     local window_id="$1"
+    debug "Focusing window ID: $window_id"
     swaymsg "[con_id=$window_id]" focus
 }
 
 WINDOW_ID=""
 
-[ -n "$CLASS_NAME" ] && WINDOW_ID=$(find_window_by_class "$CLASS_NAME")
-([ -z "$WINDOW_ID" ] || [ "$WINDOW_ID" = "null" ]) && [ -n "$TITLE_NAME" ] && WINDOW_ID=$(find_window_by_title "$TITLE_NAME" "$APP_NAME")
-([ -z "$WINDOW_ID" ] || [ "$WINDOW_ID" = "null" ]) && WINDOW_ID=$(find_window "$APP_NAME")
-([ -z "$WINDOW_ID" ] || [ "$WINDOW_ID" = "null" ]) && WINDOW_ID=$(find_window "${APP_NAME,,}")
+debug "Starting window search..."
+# Only search by class/title if provided - don't fall back to generic app search
+# This prevents matching the wrong window
+if [ -n "$CLASS_NAME" ]; then
+    WINDOW_ID=$(find_window_by_class "$CLASS_NAME")
+    debug "After class search: WINDOW_ID='$WINDOW_ID'"
+fi
+
+if ([ -z "$WINDOW_ID" ] || [ "$WINDOW_ID" = "null" ]) && [ -n "$TITLE_NAME" ]; then
+    WINDOW_ID=$(find_window_by_title "$TITLE_NAME" "$APP_NAME")
+    debug "After title search: WINDOW_ID='$WINDOW_ID'"
+fi
+
+# Only fall back to generic app search if we don't have class or title
+# This means the user wants to focus any instance of the app
+if ([ -z "$WINDOW_ID" ] || [ "$WINDOW_ID" = "null" ]) && [ -z "$CLASS_NAME" ] && [ -z "$TITLE_NAME" ]; then
+    WINDOW_ID=$(find_window "$APP_NAME")
+    debug "After app name search (no class/title): WINDOW_ID='$WINDOW_ID'"
+    
+    ([ -z "$WINDOW_ID" ] || [ "$WINDOW_ID" = "null" ]) && WINDOW_ID=$(find_window "${APP_NAME,,}")
+    debug "After lowercase app name search: WINDOW_ID='$WINDOW_ID'"
+fi
 
-[ -n "$WINDOW_ID" ] && [ "$WINDOW_ID" != "null" ] && [ "$WINDOW_ID" -eq "$WINDOW_ID" ] 2>/dev/null && focus_window "$WINDOW_ID" && exit 0
+if [ -n "$WINDOW_ID" ] && [ "$WINDOW_ID" != "null" ] && [ "$WINDOW_ID" -eq "$WINDOW_ID" ] 2>/dev/null; then
+    debug "Window found! Focusing window ID: $WINDOW_ID"
+    focus_window "$WINDOW_ID"
+    exit 0
+fi
 
+debug "No matching window found, launching new instance"
 "$COMMAND" "${ARGS[@]}" >/dev/null 2>&1 &
 disown

+ 5 - 0
zsh/.config/zsh/functions/utils.zsh

@@ -66,3 +66,8 @@ alias fml='font-manager list'
 alias fms='font-manager status'
 alias fmc='font-manager clean'
 alias fma='font-manager all'
+
+function mcd() {
+  mkdir -p "$1" && cd "$1" || return
+}
+compdef _cd mcd