# ============================================================================ # FZF-Powered Utilities # ============================================================================ # Additional fuzzy finders for various system exploration tasks. # # Features: # - envf: Environment variable browser # - pathf: PATH explorer # - procf: Process manager # - aliasf: Alias browser # - funcf: Function browser # - histf: Enhanced history search # ============================================================================ # Prevent double-sourcing [[ -n "$_DF_FZF_EXTRAS_LOADED" ]] && return 0 typeset -g _DF_FZF_EXTRAS_LOADED=1 # Source utils source "${0:A:h}/../lib/utils.zsh" 2>/dev/null || \ source "$HOME/.dotfiles/zsh/lib/utils.zsh" 2>/dev/null || { # Fallback definitions DF_GREEN=$'\033[0;32m' DF_YELLOW=$'\033[1;33m' DF_RED=$'\033[0;31m' DF_CYAN=$'\033[0;36m' DF_BLUE=$'\033[0;34m' DF_NC=$'\033[0m' df_print_error() { echo -e "${DF_RED}✗${DF_NC} $1" >&2; } df_print_success() { echo -e "${DF_GREEN}✓${DF_NC} $1"; } df_print_warning() { echo -e "${DF_YELLOW}⚠${DF_NC} $1"; } df_print_info() { echo -e "${DF_CYAN}ℹ${DF_NC} $1"; } df_print_step() { echo -e "${DF_BLUE}==>${DF_NC} $1"; } df_print_section() { echo -e "${DF_CYAN}$1:${DF_NC}"; } } # ============================================================================ # Check FZF # ============================================================================ _fzf_check() { if ! command -v fzf &>/dev/null; then df_print_error "fzf not installed" df_print_info "Install: sudo pacman -S fzf" return 1 fi return 0 } # Common fzf options _fzf_common_opts() { echo "--height=60% --layout=reverse --border=rounded --info=inline" } # ============================================================================ # Environment Variable Browser # ============================================================================ envf() { _fzf_check || return 1 local selected=$(env | sort | fzf $(_fzf_common_opts) \ --prompt="Env > " \ --preview='echo {} | cut -d= -f1 | xargs -I{} bash -c "echo -e \"Variable: {}\n\nValue:\n\"; printenv {}"' \ --preview-window=right:50%:wrap \ --header="Enter: copy value | Ctrl-E: edit | Ctrl-U: unset") [[ -z "$selected" ]] && return local var_name="${selected%%=*}" local var_value="${selected#*=}" echo "" echo -e "${DF_CYAN}$var_name${DF_NC}=$var_value" echo "" # Copy to clipboard if available if command -v wl-copy &>/dev/null; then echo -n "$var_value" | wl-copy df_print_success "Value copied to clipboard" elif command -v xclip &>/dev/null; then echo -n "$var_value" | xclip -selection clipboard df_print_success "Value copied to clipboard" fi } # Set/edit environment variable interactively env-set() { local var_name="$1" if [[ -z "$var_name" ]]; then _fzf_check || return 1 var_name=$(env | cut -d= -f1 | sort | fzf $(_fzf_common_opts) \ --prompt="Select var to edit > " \ --header="Select existing variable or type new name") [[ -z "$var_name" ]] && return fi local current_value="${(P)var_name}" echo "Variable: $var_name" echo "Current: ${current_value:-(not set)}" echo "" read -r "new_value?New value: " if [[ -n "$new_value" ]]; then export "$var_name"="$new_value" df_print_success "Set $var_name=$new_value" fi } # ============================================================================ # PATH Explorer # ============================================================================ pathf() { _fzf_check || return 1 local selected=$(echo "$PATH" | tr ':' '\n' | nl -ba | \ fzf $(_fzf_common_opts) \ --prompt="PATH > " \ --preview='dir=$(echo {} | awk "{print \$2}"); if [[ -d "$dir" ]]; then echo "Directory: $dir" echo "" echo "Executables:" ls -1 "$dir" 2>/dev/null | head -30 count=$(ls -1 "$dir" 2>/dev/null | wc -l) [[ $count -gt 30 ]] && echo "... and $((count-30)) more" else echo "Directory not found: $dir" fi' \ --preview-window=right:50% \ --header="PATH entries (in order)") [[ -z "$selected" ]] && return local dir=$(echo "$selected" | awk '{print $2}') echo "" df_print_section "Directory: $dir" if [[ -d "$dir" ]]; then ls -la "$dir" | head -20 else df_print_warning "Directory does not exist" fi } # Add to PATH interactively path-add() { local dir="${1:-$PWD}" if [[ ! -d "$dir" ]]; then df_print_error "Not a directory: $dir" return 1 fi dir=$(realpath "$dir") if [[ ":$PATH:" == *":$dir:"* ]]; then df_print_warning "Already in PATH: $dir" return 0 fi echo "Add to PATH: $dir" echo "" echo "1) Prepend (higher priority)" echo "2) Append (lower priority)" echo "3) Cancel" echo "" read -k1 "choice?Choice [1]: " echo "" case "${choice:-1}" in 1) export PATH="$dir:$PATH" df_print_success "Prepended to PATH" ;; 2) export PATH="$PATH:$dir" df_print_success "Appended to PATH" ;; *) echo "Cancelled" ;; esac } # ============================================================================ # Process Manager # ============================================================================ procf() { _fzf_check || return 1 # Preview without sudo - only show info accessible to current user local selected=$(ps aux --sort=-%mem | \ fzf $(_fzf_common_opts) \ --prompt="Process > " \ --header-lines=1 \ --preview='pid=$(echo {} | awk "{print \$2}"); echo "=== Process Details ===" ps -p $pid -o pid,ppid,user,%cpu,%mem,stat,start,time,args 2>/dev/null || echo "Process may have exited" echo "" echo "=== Command Line ===" cat /proc/$pid/cmdline 2>/dev/null | tr "\0" " " || echo "(not accessible)" echo "" echo "=== Working Directory ===" readlink /proc/$pid/cwd 2>/dev/null || echo "(not accessible)" echo "" echo "=== File Descriptors (owned by you) ===" ls -l /proc/$pid/fd 2>/dev/null | head -10 || echo "(not accessible)"' \ --preview-window=right:50%:wrap \ --header="Process list | Enter: actions | (sorted by memory)") [[ -z "$selected" ]] && return local pid=$(echo "$selected" | awk '{print $2}') local user=$(echo "$selected" | awk '{print $1}') local cmd=$(echo "$selected" | awk '{for(i=11;i<=NF;i++) printf $i" "; print ""}') echo "" df_print_section "Selected Process" echo " PID: $pid" echo " User: $user" echo " CMD: ${cmd:0:60}" echo "" echo "Actions:" echo " 1) Show full details" echo " 2) Send SIGTERM (graceful stop)" echo " 3) Send SIGKILL (force kill)" echo " 4) Send SIGHUP (reload config)" echo " 5) Open files (requires sudo)" echo " 6) Cancel" echo "" read -k1 "action?Action [1]: " echo "" case "${action:-1}" in 1) echo "" ps -p "$pid" -f echo "" echo "Command line:" cat /proc/$pid/cmdline 2>/dev/null | tr '\0' ' ' echo "" ;; 2) df_print_step "Sending SIGTERM to $pid..." if kill -TERM "$pid" 2>/dev/null; then df_print_success "Signal sent" else df_print_warning "Failed - trying with sudo..." sudo kill -TERM "$pid" && df_print_success "Signal sent" || df_print_error "Failed" fi ;; 3) df_print_step "Sending SIGKILL to $pid..." if kill -KILL "$pid" 2>/dev/null; then df_print_success "Signal sent" else df_print_warning "Failed - trying with sudo..." sudo kill -KILL "$pid" && df_print_success "Signal sent" || df_print_error "Failed" fi ;; 4) df_print_step "Sending SIGHUP to $pid..." if kill -HUP "$pid" 2>/dev/null; then df_print_success "Signal sent" else df_print_warning "Failed - trying with sudo..." sudo kill -HUP "$pid" && df_print_success "Signal sent" || df_print_error "Failed" fi ;; 5) echo "" df_print_step "Open files for PID $pid:" sudo lsof -p "$pid" 2>/dev/null | head -30 || df_print_error "Failed to get open files" ;; *) echo "Cancelled" ;; esac } # Quick kill by name killf() { _fzf_check || return 1 local selected=$(ps aux | grep -v "grep" | \ fzf $(_fzf_common_opts) \ --prompt="Kill > " \ --header-lines=1 \ --multi \ --preview='pid=$(echo {} | awk "{print \$2}"); ps -p $pid -o pid,ppid,user,%cpu,%mem,stat,args 2>/dev/null' \ --header="Select process(es) to kill (Tab to select multiple)") [[ -z "$selected" ]] && return echo "$selected" | while read -r line; do local pid=$(echo "$line" | awk '{print $2}') local cmd=$(echo "$line" | awk '{for(i=11;i<=NF;i++) printf $i" "; print ""}') df_print_step "Killing PID $pid (${cmd:0:40})" if kill "$pid" 2>/dev/null; then df_print_success "Killed" else df_print_warning "Trying with sudo..." sudo kill "$pid" && df_print_success "Killed" || df_print_error "Failed" fi done } # ============================================================================ # Alias Browser # ============================================================================ aliasf() { _fzf_check || return 1 local selected=$(alias | sed "s/^alias //" | sort | \ fzf $(_fzf_common_opts) \ --prompt="Alias > " \ --preview='name=$(echo {} | cut -d= -f1); cmd=$(echo {} | cut -d= -f2- | sed "s/^'\''//;s/'\''$//"); echo "Alias: $name" echo "" echo "Expands to:" echo "$cmd" echo "" echo "Type: $(type $name 2>/dev/null || echo "alias")"' \ --preview-window=right:50%:wrap \ --header="Enter: insert alias | Ctrl-E: edit definition") [[ -z "$selected" ]] && return local alias_name="${selected%%=*}" print -z "$alias_name " } # ============================================================================ # Function Browser # ============================================================================ funcf() { _fzf_check || return 1 local selected=$(print -l ${(ok)functions} | grep -v "^_" | sort | \ fzf $(_fzf_common_opts) \ --prompt="Function > " \ --preview='whence -f {}' \ --preview-window=right:60%:wrap \ --header="Shell functions | Enter: insert | Ctrl-V: view source") [[ -z "$selected" ]] && return print -z "$selected " } # ============================================================================ # Enhanced History Search # ============================================================================ histf() { _fzf_check || return 1 local selected=$(fc -ln 1 | tac | awk '!seen[$0]++' | \ fzf $(_fzf_common_opts) \ --prompt="History > " \ --no-sort \ --header="Command history (newest first) | Enter: execute | Ctrl-E: edit") [[ -z "$selected" ]] && return print -z "$selected" } # ============================================================================ # File Finder (enhanced) # ============================================================================ ff() { _fzf_check || return 1 local search_dir="${1:-.}" local query="${2:-}" local cmd="find $search_dir -type f 2>/dev/null" # Use fd if available (faster) if command -v fd &>/dev/null; then cmd="fd --type f . $search_dir" fi local selected=$(eval "$cmd" | \ fzf $(_fzf_common_opts) \ --query="$query" \ --prompt="File > " \ --preview=' file={} if file "$file" | grep -q "text"; then bat --style=numbers --color=always "$file" 2>/dev/null || cat "$file" else file "$file" echo "" ls -lh "$file" fi' \ --preview-window=right:60% \ --header="Files | Enter: open | Ctrl-E: edit | Ctrl-Y: copy path") [[ -z "$selected" ]] && return echo "$selected" } # Open file with appropriate application ffo() { local file=$(ff "$@") [[ -z "$file" ]] && return if [[ -f "$file" ]]; then if file "$file" | grep -q "text"; then ${EDITOR:-vim} "$file" else xdg-open "$file" 2>/dev/null || open "$file" 2>/dev/null fi fi } # ============================================================================ # Directory Finder # ============================================================================ fdir() { _fzf_check || return 1 local search_dir="${1:-.}" local cmd="find $search_dir -type d 2>/dev/null" if command -v fd &>/dev/null; then cmd="fd --type d . $search_dir" fi local selected=$(eval "$cmd" | \ fzf $(_fzf_common_opts) \ --prompt="Directory > " \ --preview='ls -la {} | head -30' \ --preview-window=right:50% \ --header="Directories | Enter: cd") [[ -z "$selected" ]] && return cd "$selected" } # ============================================================================ # Git Helpers # ============================================================================ # Git branch switcher gbf() { _fzf_check || return 1 if ! git rev-parse --git-dir &>/dev/null; then df_print_error "Not a git repository" return 1 fi local selected=$(git branch -a --color=always | grep -v '/HEAD\s' | \ fzf $(_fzf_common_opts) \ --ansi \ --prompt="Branch > " \ --preview='git log --oneline --graph --color=always $(echo {} | sed "s/.* //" | sed "s#remotes/##") -- | head -20' \ --header="Git branches | Enter: checkout") [[ -z "$selected" ]] && return local branch=$(echo "$selected" | sed "s/.* //" | sed "s#remotes/[^/]*/##") git checkout "$branch" } # Git commit browser glogf() { _fzf_check || return 1 if ! git rev-parse --git-dir &>/dev/null; then df_print_error "Not a git repository" return 1 fi local selected=$(git log --oneline --color=always | \ fzf $(_fzf_common_opts) \ --ansi \ --prompt="Commit > " \ --preview='git show --color=always $(echo {} | cut -d" " -f1)' \ --preview-window=right:60% \ --header="Git commits | Enter: show | Ctrl-D: diff") [[ -z "$selected" ]] && return local commit=$(echo "$selected" | cut -d" " -f1) git show "$commit" } # ============================================================================ # Help # ============================================================================ fzf-help() { cat << 'EOF' FZF Utilities Environment: envf Browse environment variables env-set [VAR] Set/edit environment variable Path: pathf Explore PATH directories path-add [DIR] Add directory to PATH Process: procf Browse and manage processes killf Fuzzy kill processes Shell: aliasf Browse aliases funcf Browse functions histf Search command history Files: ff [DIR] Find files ffo [DIR] Find and open file fdir [DIR] Find and cd to directory Git: gbf Branch switcher glogf Commit browser EOF } # ============================================================================ # Aliases # ============================================================================ alias envbrowse='envf' alias pathbrowse='pathf' alias proc='procf'