瀏覽代碼

dev: automated commit - 2025-10-22 10:22:22

Mariano Z. 3 月之前
父節點
當前提交
c705bcd86d

+ 1 - 1
zsh/.config/zsh/.zshrc

@@ -9,4 +9,4 @@ else
 fi
 
 # Load completion registrations
-source $ZDOTDIR/completions.zsh
+source $ZDOTDIR/completions/external.zsh

+ 0 - 114
zsh/.config/zsh/completions.zsh

@@ -1,114 +0,0 @@
-#!/bin/zsh
-
-_lazy_load_completion() {
-    local cmd="$1"
-    local completion_cmd="$2"
-
-    eval "${cmd}() {
-        unfunction $cmd
-        eval \"\$($completion_cmd)\"
-        $cmd \"\$@\"
-    }"
-}
-
-for completion_file in ~/.local/share/zsh/*-autocomplete.zsh(N); do
-    if [ -f "$completion_file" ]; then
-        source "$completion_file"
-    fi
-done
-
-if command -v eza &> /dev/null; then 
-    compdef _ls eza
-fi
-
-if command -v kubefwd &> /dev/null; then 
-    _lazy_load_completion kubefwd "kubefwd completion zsh"
-fi
-
-if command -v bombadil &> /dev/null; then 
-    _lazy_load_completion bombadil "bombadil generate-completions zsh"
-fi
-
-if command -v rop &> /dev/null; then 
-    eval "$(rop completion zsh)"
-fi
-
-if command -v goq &> /dev/null; then 
-    eval "$(goq completion zsh)"
-fi
-
-if command -v drop &> /dev/null; then 
-    eval "$(drop completion zsh)"
-fi
-
-if command -v mora &> /dev/null; then 
-    eval "$(mora completion zsh)"
-fi
-
-_kf_completion() {
-    local -a contexts
-    contexts=($(kubectx 2>/dev/null | sed 's/-read$//; s/-security$//' | sort -u))
-    
-    # Use _describe instead of _values for better compatibility
-    _describe 'cluster' contexts
-}
-
-_rmq_passwd_completion() {
-    local -a environments
-    environments=($(kubectl config get-contexts -o name 2>/dev/null | grep '^oc-.*-eks-cluster$' | sed 's/^oc-//; s/-eks-cluster$//' | sort -u))
-
-    if [[ ${#environments[@]} -gt 0 ]]; then
-        _describe 'environments' environments
-    fi
-}
-
-_yay_completion() {
-    local cur prev opts
-    COMPREPLY=()
-    cur="${COMP_WORDS[COMP_CWORD]}"
-    prev="${COMP_WORDS[COMP_CWORD-1]}"
-
-    opts="-Syyu -Syu -Ss -S -R -Q -Si -Sc help install remove list clean"
-
-    COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
-    return 0
-}
-
-_yay_zsh_completion() {
-    local -a opts
-    opts=(
-        '-Syyu:Update system'
-        '-Syu:Update system'
-        '-Ss:Search packages'
-        '-S:Install system-wide'
-        '-R:Remove package'
-        '-Q:List installed'
-        '-Si:Package info'
-        '-Sc:Clean cache'
-        '-p:Open nix-shell with packages'
-        'help:Show help'
-        'install:Install to user env'
-        'remove:Remove from user env'
-        'list:List installed packages'
-        'clean:Clean nix store'
-        'shell:Start nix-shell with packages'
-    )
-    _describe 'yay commands' opts
-}
-
-_kf_completion() {
-    local -a contexts
-    contexts=($(kubectx 2>/dev/null | sed 's/-read$//; s/-security$//' | sort -u))
-
-    if [[ ${#contexts[@]} -gt 0 ]]; then
-        _values 'cluster' "${contexts[@]}"
-    fi
-}
-compdef _kf_completion kf
-compdef _rmq_passwd_completion rmq-passwd
-
-if [[ -n "${BASH_VERSION:-}" ]]; then
-    complete -F _yay_completion yay
-elif [[ -n "${ZSH_VERSION:-}" ]]; then
-    compdef _yay_zsh_completion yay
-fi

+ 59 - 0
zsh/.config/zsh/completions/external.zsh

@@ -0,0 +1,59 @@
+#!/bin/zsh
+
+_lazy_load_completion() {
+    local cmd="$1"
+    local completion_cmd="$2"
+
+    eval "${cmd}() {
+        unfunction $cmd
+        eval \"\$($completion_cmd)\"
+        $cmd \"\$@\"
+    }"
+}
+
+for completion_file in ~/.local/share/zsh/*-autocomplete.zsh(N); do
+    if [ -f "$completion_file" ]; then
+        source "$completion_file"
+    fi
+done
+
+if command -v eza &> /dev/null; then 
+    compdef _ls eza
+fi
+
+if command -v kubefwd &> /dev/null; then 
+    _lazy_load_completion kubefwd "kubefwd completion zsh"
+fi
+
+if command -v bombadil &> /dev/null; then 
+    _lazy_load_completion bombadil "bombadil generate-completions zsh"
+fi
+
+if command -v rop &> /dev/null; then 
+    eval "$(rop completion zsh)"
+fi
+
+if command -v goq &> /dev/null; then 
+    eval "$(goq completion zsh)"
+fi
+
+if command -v drop &> /dev/null; then 
+    eval "$(drop completion zsh)"
+fi
+
+if command -v mora &> /dev/null; then 
+    eval "$(mora completion zsh)"
+fi
+
+_lazy_load() {
+  local cmd="$1"
+  local loader="$2"
+
+  eval "${cmd}() {
+    unfunction $cmd
+    eval \"\$($loader)\"
+    $cmd \"\$@\"
+  }"
+}
+
+_lazy_load kubectl "kubectl completion zsh"

+ 0 - 954
zsh/.config/zsh/functions.zsh

@@ -1,954 +0,0 @@
-#!/bin/zsh
-
-# =============================================================================
-# NAVIGATION UTILITIES
-# =============================================================================
-
-eval "$(zoxide init zsh)"
-
-# Zoxide aliases with better names
-zcd() { z "$@" }
-zadd() { z "$@" }
-zremove() { zoxide remove "$@" }
-
-# Legacy aliases for backward compatibility
-alias zi=zcd
-alias za=zadd
-alias zrm=zremove
-
-# Open files with xdg-open (non-blocking)
-function open {
-  if [[ $# -eq 0 ]]; then
-    echo "Usage: open <file1> [file2] ..."
-    echo "Opens files using the system default application"
-    return 1
-  fi
-
-  for i in "$@"; do
-    if [[ ! -e "$i" ]]; then
-      echo "Warning: '$i' does not exist" >&2
-      continue
-    fi
-    setsid nohup xdg-open "$i" > /dev/null 2> /dev/null &
-  done
-}
-
-# Find and open files with fzf
-function fopen() {
-  if ! command -v fd >/dev/null 2>&1; then
-    echo "Error: fd is not installed" >&2
-    return 1
-  fi
-
-  if ! command -v fzf >/dev/null 2>&1; then
-    echo "Error: fzf is not installed" >&2
-    return 1
-  fi
-
-  local selected
-  selected=$(fd "$@" | fzf --preview 'bat --color=always --style=numbers --line-range=:500 {}')
-  [[ -n "$selected" ]] && setsid nohup xdg-open "$selected" >/dev/null 2>&1 &
-}
-
-# =============================================================================
-# DEVELOPMENT TOOLS
-# =============================================================================
-
-# Smart package manager detection and execution
-function _package_manager {
-  local pkg_manager=""
-
-  # Detect package manager based on lock files
-  if [[ -f bun.lockb ]]; then
-    pkg_manager="bun"
-  elif [[ -f pnpm-lock.yaml ]]; then
-    pkg_manager="pnpm"
-  elif [[ -f yarn.lock ]]; then
-    pkg_manager="yarn"
-  elif [[ -f package-lock.json ]]; then
-    pkg_manager="npm"
-  else
-    pkg_manager="pnpm"  # Default fallback
-  fi
-
-  # Auto-detect npm scripts if command exists in package.json
-  if [[ -f package.json ]] && [[ $1 != "run" ]] && [[ $1 != "install" ]] && [[ $1 != "add" ]] && [[ $1 != "remove" ]] && [[ $1 != "i" ]] && [[ $1 != "rm" ]]; then
-    if command -v jq >/dev/null 2>&1 && jq -e ".scripts[\"$1\"] != null" package.json >/dev/null 2>&1; then
-      set -- "run" "$@"
-    fi
-  fi
-
-  # Execute with corepack if available, otherwise direct command
-  if command -v corepack >/dev/null 2>&1; then
-    corepack ${pkg_manager} "$@"
-  else
-    command ${pkg_manager} "$@"
-  fi
-}
-
-# Quick development commit with auto-push
-function dc() {
-  # Show help if requested
-  if [[ "$1" == "-h" || "$1" == "--help" ]]; then
-    echo "Usage: dc [commit_message]"
-    echo "Quickly commit all changes and push to remote"
-    echo "If no message provided, uses timestamp-based message"
-    return 0
-  fi
-
-  if ! git rev-parse --is-inside-work-tree &>/dev/null; then
-    echo "Error: Not in a git repository" >&2
-    return 1
-  fi
-
-  if [[ -z $(git status --porcelain) ]]; then
-    echo "No changes to commit"
-    return 0
-  fi
-
-  git add .
-
-  local commit_msg
-  if [[ -n "$1" ]]; then
-    commit_msg="$1"
-  else
-    local timestamp=$(date +"%Y-%m-%d %H:%M:%S")
-    commit_msg="dev: automated commit - ${timestamp}"
-  fi
-
-  # Commit with message and push
-  if git commit -m "$commit_msg" --no-gpg-sign; then
-    if git push &>/dev/null; then
-      echo "Committed and pushed successfully"
-    else
-      echo "Warning: Commit successful but push failed" >&2
-      return 1
-    fi
-  else
-    echo "Commit failed" >&2
-    return 1
-  fi
-}
-
-# Clean up merged git branches
-function git-clean() {
-  # Show help if requested
-  if [[ "$1" == "-h" || "$1" == "--help" ]]; then
-    echo "Usage: git-clean"
-    echo "Safely delete merged branches (both local and optionally remote)"
-    echo "Protects main, master, and develop branches"
-    return 0
-  fi
-
-  if ! git rev-parse --is-inside-work-tree &>/dev/null; then
-    echo "Error: Not in a git repository" >&2
-    return 1
-  fi
-
-  local current_branch=$(git rev-parse --abbrev-ref HEAD)
-  local branches_to_delete=$(git branch --merged | grep -v "^\*" | grep -v "master" | grep -v "main" | grep -v "develop")
-
-  if [[ -z "$branches_to_delete" ]]; then
-    echo "No merged branches to clean up"
-    return 0
-  fi
-
-  echo "The following merged branches will be deleted:"
-  echo "$branches_to_delete"
-  echo -n "Continue? [y/N] "
-  read confirm
-
-  if [[ "$confirm" =~ ^[Yy]$ ]]; then
-    echo "$branches_to_delete" | xargs git branch -d
-    echo "Branches deleted locally"
-
-    echo -n "Delete remote branches too? [y/N] "
-    read confirm_remote
-
-    if [[ "$confirm_remote" =~ ^[Yy]$ ]]; then
-      echo "$branches_to_delete" | xargs -I{} git push origin --delete {}
-      echo "Remote branches deleted"
-    fi
-  else
-    echo "Operation cancelled"
-  fi
-}
-
-# Quick access to Neovim config
-function vimrc {
-  if [[ -z "$XDG_CONFIG_HOME" ]]; then
-    echo "Error: XDG_CONFIG_HOME not set" >&2
-    return 1
-  fi
-
-  local original_dir=$(pwd)
-  cd "$XDG_CONFIG_HOME/nvim" || {
-    echo "Error: Cannot access $XDG_CONFIG_HOME/nvim" >&2
-    return 1
-  }
-  nvim
-  cd "$original_dir"
-}
-
-
-function nixrc {
-  if [[ -z "$XDG_CONFIG_HOME" ]]; then
-    echo "Error: XDG_CONFIG_HOME not set" >&2
-    return 1
-  fi
-
-  local original_dir=$(pwd)
-  cd "$XDG_CONFIG_HOME/nixos" || {
-    echo "Error: Cannot access $XDG_CONFIG_HOME/nixos" >&2
-    return 1
-  }
-  nvim
-  cd "$original_dir"
-}
-
-# Quick access to Zsh config
-function zshrc {
-  if [[ -z "$XDG_CONFIG_HOME" ]]; then
-    echo "Error: XDG_CONFIG_HOME not set" >&2
-    return 1
-  fi
-
-  local original_dir=$(pwd)
-  cd "$XDG_CONFIG_HOME/zsh" || {
-    echo "Error: Cannot access $XDG_CONFIG_HOME/zsh" >&2
-    return 1
-  }
-  nvim
-  cd "$original_dir"
-}
-
-# Expose local port through SSH tunnel
-function expose() {
-  # Show help if requested
-  if [[ "$1" == "-h" || "$1" == "--help" ]]; then
-    echo "Usage: expose <port>"
-    echo "Create SSH tunnel to expose local port through remote server"
-    echo "Example: expose 3000  # Exposes localhost:3000"
-    return 0
-  fi
-
-  if [[ -z "$1" ]]; then
-    echo "Error: Port number required" >&2
-    echo "Usage: expose <port>" >&2
-    return 1
-  fi
-
-  # Validate port number
-  if ! [[ "$1" =~ ^[0-9]+$ ]] || [[ "$1" -lt 1 ]] || [[ "$1" -gt 65535 ]]; then
-    echo "Error: Invalid port number. Must be between 1-65535" >&2
-    return 1
-  fi
-
-  # Check if port is already in use
-  if lsof -i ":$1" >/dev/null 2>&1; then
-    echo "Warning: Port $1 is already in use" >&2
-    echo "Current processes using port $1:"
-    lsof -i ":$1"
-    echo -n "Continue anyway? [y/N] "
-    read confirm
-    if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
-      echo "Operation cancelled"
-      return 1
-    fi
-  fi
-
-  echo "Creating SSH tunnel for port $1..."
-  ssh marianozunino@srv.us -R 1:localhost:"$1"
-}
-
-# Find process using a specific port
-function ppid {
-  # Show help if requested
-  if [[ "$1" == "-h" || "$1" == "--help" ]]; then
-    echo "Usage: ppid <port>"
-    echo "Find processes using the specified port"
-    echo "Alias: pport"
-    return 0
-  fi
-
-  if [[ -z "$1" ]]; then
-    echo "Error: Port number required" >&2
-    echo "Usage: ppid <port>" >&2
-    return 1
-  fi
-
-  # Validate port number
-  if ! [[ "$1" =~ ^[0-9]+$ ]] || [[ "$1" -lt 1 ]] || [[ "$1" -gt 65535 ]]; then
-    echo "Error: Invalid port number. Must be between 1-65535" >&2
-    return 1
-  fi
-
-  lsof -i ":$1"
-}
-
-# Alias for ppid function
-alias pport="ppid"
-
-# =============================================================================
-# KUBERNETES AND DEVOPS
-# =============================================================================
-
-# # Kubernetes port forwarding with kubefwd
-# function kf {
-#   if [[ "$1" == "-h" || "$1" == "--help" ]]; then
-#     echo "Usage: kf <cluster> [service-name]"
-#     echo "Forward Kubernetes services using kubefwd"
-#     echo "Example: kf prod my-service"
-#     return 0
-#   fi
-#
-#   if [[ -z "$1" ]]; then
-#     echo "Error: Cluster name required" >&2
-#     echo "Usage: kf <cluster> [service-name]" >&2
-#     return 1
-#   fi
-#
-#   local namespace="oc-app"
-#   local cluster="$1"
-#   local svc_filter=""
-#
-#   if [[ -n "$2" ]]; then
-#     svc_filter="-l app.kubernetes.io/instance=$2"
-#   fi
-#
-#   if ! command -v kubefwd >/dev/null 2>&1; then
-#     echo "Error: kubefwd is not installed" >&2
-#     return 1
-#   fi
-#
-#   echo "Starting kubefwd for cluster: $cluster"
-#   kubefwd svc -n "${namespace}" -x "${cluster}" ${svc_filter} --nonsudo
-# }
-#
-
-# Forward multiple services from a given namespace
-
-function kf {
-  # Show help
-  if [[ "$1" == "-h" || "$1" == "--help" ]]; then
-    echo "Usage: kf <cluster> [service-name[:port]] [service-name[:port]] ..."
-    echo "Example: kf oc-dev-internal-eks-cluster oc-activate-web"
-    echo "Example: kf oc-dev-internal-eks-cluster oc-activate-web:8080"
-    echo "Example: kf oc-dev-internal-eks-cluster oc-activate-web:8080 oc-member-dossier:8081"
-    return 0
-  fi
-
-  local cluster="$1"
-  shift
-
-  if [[ -z "$cluster" ]]; then
-    echo "Error: Missing cluster" >&2
-    echo "Usage: kf <cluster> [service-name[:port]] [service-name[:port]] ..." >&2
-    return 1
-  fi
-
-  # Show available services if none specified
-  if [[ $# -eq 0 ]]; then
-    echo "🔌 Available services in cluster: $cluster"
-    kubectl --context "$cluster" -n oc-app get svc -o name | sed 's/service\//   - /'
-    return 0
-  fi
-
-  echo "🔌 Forwarding services (cluster: $cluster)"
-  
-  # Clean up existing port-forwards
-  local existing_pids
-  existing_pids=$(pgrep -f "kubectl.*port-forward" || true)
-  if [[ -n "$existing_pids" ]]; then
-    echo "$existing_pids" | xargs kill 2>/dev/null || true
-    existing_pids=$(pgrep -f "kubectl.*port-forward" || true)
-    if [[ -n "$existing_pids" ]]; then
-      echo "$existing_pids" | xargs kill -9 2>/dev/null || true
-      sleep 0.5
-    fi
-  fi
-  
-  local pids=()
-
-  # Process each service
-  for service_spec in "$@"; do
-    # Parse service:port format
-    local service_name local_port
-    if [[ "$service_spec" == *":"* ]]; then
-      service_name="${service_spec%:*}"
-      local_port="${service_spec##*:}"
-    else
-      service_name="$service_spec"
-      local_port=""
-    fi
-
-    # Find service in oc-app namespace
-    local svc
-    svc=$(kubectl --context "$cluster" -n oc-app get svc -o name | grep "^service/$service_name$" || true)
-    
-    if [[ -z "$svc" ]]; then
-      echo "⚠️  Service '$service_name' not found in namespace 'oc-app' - skipping"
-      echo "   Available services:"
-      kubectl --context "$cluster" -n oc-app get svc -o name | sed 's/service\//   - /' | head -5
-      continue
-    fi
-
-    local name="${svc#service/}"
-    local service_port
-    service_port=$(kubectl --context "$cluster" -n oc-app get "svc/$name" -o jsonpath='{.spec.ports[0].port}')
-    local forward_port="${local_port:-$service_port}"
-
-    # Check if port is in use
-    local port_info
-    port_info=$(lsof -i :$forward_port 2>/dev/null)
-    if [[ -n "$port_info" ]]; then
-      local pid=$(echo "$port_info" | tail -n +2 | awk '{print $2}' | head -1)
-      local process=$(echo "$port_info" | tail -n +2 | awk '{print $1}' | head -1)
-      echo "⚠️  Port $forward_port in use by $process (PID: $pid) - skipping $name"
-      continue
-    fi
-
-    # Start port-forward
-    if [[ -n "$local_port" ]]; then
-      echo "→ Forwarding $name (service port $service_port) to local port $forward_port"
-    else
-      echo "→ Forwarding $name on port $forward_port"
-    fi
-    
-    kubectl --context "$cluster" -n oc-app port-forward "svc/$name" "$forward_port:$service_port" >/dev/null 2>&1 &
-    local pid=$!
-
-    # Verify port-forward started successfully
-    sleep 0.5
-    if ! kill -0 $pid 2>/dev/null; then
-      echo "❌ Failed to start port-forward for $name on port $forward_port"
-      continue
-    fi
-
-    pids+=($pid)
-  done
-
-  if [[ ${#pids[@]} -eq 0 ]]; then
-    echo "❌ No port-forwards were started successfully"
-    return 1
-  fi
-
-  echo "→ All forwards running (PIDs: ${pids[*]})"
-  echo "→ Press Ctrl+C to stop"
-
-  # Handle Ctrl+C cleanup
-  trap 'echo; echo "🛑 Stopping port-forwards..."; for pid in ${pids[*]}; do kill $pid 2>/dev/null; done; sleep 1; for pid in ${pids[*]}; do kill -9 $pid 2>/dev/null; done; wait ${pids[*]} 2>/dev/null; return 0' INT
-
-  wait
-}
-
-
-# =============================================================================
-# SYSTEM AND UTILITY FUNCTIONS
-# =============================================================================
-
-# Lazy-load handler for heavy tools
-function _lazy_load() {
-  local cmd="$1"
-  local loader="$2"
-
-  eval "${cmd}() {
-    unfunction $cmd
-    eval \"\$($loader)\"
-    $cmd \"\$@\"
-  }"
-}
-
-# Example: lazy load kubectl completion
-_lazy_load kubectl "kubectl completion zsh"
-
-# Configure Wacom tablet for current session
-function wacom {
-  # Show help if requested
-  if [[ "$1" == "-h" || "$1" == "--help" ]]; then
-    echo "Usage: wacom"
-    echo "Configure Wacom tablet for current display session"
-    echo "Supports both Wayland and X11 sessions"
-    return 0
-  fi
-
-  if [[ "$XDG_SESSION_TYPE" = "wayland" ]]; then
-    if ! command -v otd >/dev/null 2>&1; then
-      echo "Error: opentabletdriver (otd) not found" >&2
-      return 1
-    fi
-
-    systemctl --user enable opentabletdriver --now
-
-    local config_file="$HOME/Sync/System/Configs/wacom/wacom.json"
-    if [[ -f "$config_file" ]]; then
-      otd loadsettings "$config_file"
-      echo "Wacom configured for Wayland"
-    else
-      echo "Warning: Config file not found at $config_file" >&2
-    fi
-  else
-    if ! command -v xsetwacom >/dev/null 2>&1; then
-      echo "Error: xsetwacom not found" >&2
-      return 1
-    fi
-
-    xsetwacom --set "Wacom One by Wacom S Pen stylus" ResetArea
-    xsetwacom --set "Wacom One by Wacom S Pen stylus" MapToOutput DisplayPort-0
-    xsetwacom --set "Wacom One by Wacom S Pen stylus" Rotate half
-
-    xsetwacom --set "Wacom One by Wacom S Pen eraser" ResetArea
-    xsetwacom --set "Wacom One by Wacom S Pen eraser" MapToOutput DisplayPort-0
-
-    echo "Wacom configured for X11"
-  fi
-}
-
-# Enhanced cat with bat, context-aware display
-function cat {
-  # Show help if requested
-  if [[ "$1" == "-h" || "$1" == "--help" ]]; then
-    echo "Usage: cat [file1] [file2] ..."
-    echo "Enhanced cat using bat with syntax highlighting"
-    echo "Automatically adjusts output for SSH sessions"
-    return 0
-  fi
-
-  if ! command -v bat >/dev/null 2>&1; then
-    echo "Warning: bat not found, falling back to system cat" >&2
-    command cat "$@"
-    return $?
-  fi
-
-  if [[ -n "$SSH_TTY" ]] || [[ -n "$SSH_CLIENT" ]] || [[ -n "$SSH_CONNECTION" ]]; then
-    bat --plain --paging=never "$@"
-  else
-    bat "$@"
-  fi
-}
-
-# Toggle display resolution and configuration
-function toggle_resolution() {
-  # Show help if requested
-  if [[ "$1" == "-h" || "$1" == "--help" ]]; then
-    echo "Usage: toggle_resolution [-m|--mirror]"
-    echo "Toggle between different display resolutions and modes"
-    echo "Options:"
-    echo "  -m, --mirror    Force mirror mode"
-    return 0
-  fi
-
-  local mirror_mode=false
-
-  # Parse flags
-  while [[ $# -gt 0 ]]; do
-    case $1 in
-      -m|--mirror)
-        mirror_mode=true
-        shift
-        ;;
-      *)
-        shift
-        ;;
-    esac
-  done
-
-  # Check if swaymsg is available
-  if ! command -v swaymsg >/dev/null 2>&1; then
-    echo "Error: swaymsg not found. This function requires Sway window manager" >&2
-    return 1
-  fi
-
-  # Check if jq is available
-  if ! command -v jq >/dev/null 2>&1; then
-    echo "Error: jq not found. Required for JSON parsing" >&2
-    return 1
-  fi
-
-  # Get current state of internal monitor
-  local current_state
-  current_state=$(swaymsg -t get_outputs | jq -r '.[] | select(.name == "eDP-1") | "\(.current_mode.width)x\(.current_mode.height):\(.scale)"')
-
-  # Detect connected external monitors
-  local external_monitor=""
-  if swaymsg -t get_outputs | jq -r '.[].name' | grep -q "DP-2"; then
-    external_monitor="DP-2"
-  elif swaymsg -t get_outputs | jq -r '.[].name' | grep -q "HDMI-A-1"; then
-    external_monitor="HDMI-A-1"
-  fi
-
-  if [[ "$mirror_mode" == true ]] || [[ -n "$external_monitor" ]]; then
-    echo "Switching to mirror mode (1920x1080)..."
-
-    # Configure internal monitor to 1920x1080
-    swaymsg output eDP-1 resolution 1920x1080@120Hz scale 1.0 pos 0 0
-
-    # Configure external monitor if connected
-    if [[ -n "$external_monitor" ]]; then
-      swaymsg output "$external_monitor" resolution 1920x1080@60Hz pos 0 0
-      echo "Mirror mode enabled: eDP-1 + $external_monitor at 1920x1080"
-    else
-      echo "Internal monitor configured to 1920x1080 (no external monitor detected)"
-    fi
-
-  elif [[ "$current_state" == "2880x1920:2.0" ]]; then
-    echo "Switching to 1920x1080 (16:9)..."
-    swaymsg output eDP-1 resolution 1920x1080@120Hz scale 1.0
-
-    # Disable mirroring if external monitor is present
-    if [[ -n "$external_monitor" ]]; then
-      swaymsg output "$external_monitor" pos 1920 0
-      echo "Extended mode: $external_monitor positioned to the right"
-    fi
-
-  else
-    echo "Switching to 2880x1920 (3:2) native..."
-    swaymsg output eDP-1 resolution 2880x1920@120Hz scale 2.0
-
-    # Disable mirroring if external monitor is present
-    if [[ -n "$external_monitor" ]]; then
-      swaymsg output "$external_monitor" pos 1440 0
-      echo "Extended mode: $external_monitor positioned to the right"
-    fi
-  fi
-
-  # Show final state
-  echo "Current configuration:"
-  swaymsg -t get_outputs | jq -r '.[] | select(.active == true) | "  \(.name): \(.current_mode.width)x\(.current_mode.height)@\(.current_mode.refresh/1000)Hz scale:\(.scale) pos:(\(.rect.x),\(.rect.y))"'
-}
-
-# Launch Code::Blocks with high contrast theme
-function cb {
-  # Show help if requested
-  if [[ "$1" == "-h" || "$1" == "--help" ]]; then
-    echo "Usage: cb [codeblocks-args]"
-    echo "Launch Code::Blocks with high contrast theme"
-    return 0
-  fi
-
-  if [[ ! -f /usr/bin/codeblocks ]]; then
-    echo "Error: Code::Blocks not found at /usr/bin/codeblocks" >&2
-    return 1
-  fi
-
-  # Store original values
-  local original_gtk_theme="$GTK_THEME"
-  local original_gdk_theme="$GDK_THEME"
-  local original_qt_style="$QT_STYLE_OVERRIDE"
-  local original_xdg_desktop="$XDG_CURRENT_DESKTOP"
-
-  # Set high contrast theme temporarily
-  GTK_THEME=HighContrast \
-  GDK_THEME=HighContrast \
-  QT_STYLE_OVERRIDE=HighContrast \
-  XDG_CURRENT_DESKTOP=GNOME \
-  GTK2_RC_FILES="" \
-  GTK_RC_FILES="" \
-  /usr/bin/codeblocks "$@"
-
-  # Restore original values
-  export GTK_THEME="$original_gtk_theme"
-  export GDK_THEME="$original_gdk_theme"
-  export QT_STYLE_OVERRIDE="$original_qt_style"
-  export XDG_CURRENT_DESKTOP="$original_xdg_desktop"
-}
-
-
-# Create a new git repository on remote server
-function zrepo() {
-  # Show help if requested
-  if [[ "$1" == "-h" || "$1" == "--help" ]]; then
-    echo "Usage: zrepo <repo-name>"
-    echo "Create a new bare git repository on remote server"
-    echo "Example: zrepo my-project"
-    return 0
-  fi
-
-  if [[ -z "$1" ]]; then
-    echo "Error: Repository name required" >&2
-    echo "Usage: zrepo <repo-name>" >&2
-    return 1
-  fi
-
-  # Validate repository name (basic check)
-  if [[ ! "$1" =~ ^[a-zA-Z0-9_-]+$ ]]; then
-    echo "Error: Repository name contains invalid characters" >&2
-    echo "Use only letters, numbers, hyphens, and underscores" >&2
-    return 1
-  fi
-
-  local REPO="$1"
-  local SERVER="git@zvps"
-  local PATH_ON_SERVER="/var/git/$REPO.git"
-
-  echo "Creating repository '$REPO' on $SERVER..."
-
-  ssh "$SERVER" "
-    if [ -d $PATH_ON_SERVER ]; then
-      echo 'Error: Repository '$REPO' already exists'
-      exit 1
-    fi
-    mkdir -p $PATH_ON_SERVER &&
-    git init --bare $PATH_ON_SERVER &&
-    chown -R git:git $PATH_ON_SERVER &&
-    chmod -R 755 $PATH_ON_SERVER
-  " || {
-    echo "Failed to create repository" >&2
-    return 1
-  }
-
-      echo "Repository created on $SERVER:$PATH_ON_SERVER"
-
-  if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
-    git remote add origin "$SERVER:$PATH_ON_SERVER"
-    echo "Remote 'origin' added to your local repository"
-  else
-    echo "To clone this repository, run:"
-    echo "  git clone $SERVER:$PATH_ON_SERVER"
-  fi
-}
-
-
-
-# Check if a command exists
-function _has {
-  if [[ $# -eq 0 ]]; then
-    echo "Usage: _has <command>" >&2
-    return 1
-  fi
-
-  whence "$1" >/dev/null 2>&1
-}
-
-# History-based directory navigation with fzf
-function cdr {
-  # Show help if requested
-  if [[ "$1" == "-h" || "$1" == "--help" ]]; then
-    echo "Usage: cdr"
-    echo "Navigate to recently visited directories using fzf"
-    return 0
-  fi
-
-  if ! command -v fzf >/dev/null 2>&1; then
-    echo "Error: fzf is not installed" >&2
-    return 1
-  fi
-
-  local dir
-  dir=$(dirs -pl | awk '!x[$0]++' | fzf --height 40% --reverse)
-  [[ -n "$dir" ]] && cd "$dir"
-}
-
-# Fix swaymsg when running inside tmux
-if [[ -v TMUX ]]; then
-  function swaymsg {
-    export SWAYSOCK=$XDG_RUNTIME_DIR/sway-ipc.$UID.$(pgrep -x sway).sock
-    command swaymsg "$@"
-  }
-fi
-
-
-# =============================================================================
-# ALIASES
-# =============================================================================
-
-# Development aliases
-alias dev='~/Dev/marianozunino/dev/dev'
-alias p='_package_manager'
-alias fo='fopen'
-alias pport='ppid'
-
-# Node.js cleanup alias
-alias unChonk="echo 'Starting the great node_modules purge...' && find . -name 'node_modules' -type d -prune -exec sh -c 'echo \"Deleting {}\" && rm -rf \"{}\"' \;"
-
-# Font management
-alias fm='font-manager'
-alias fml='font-manager list'
-alias fms='font-manager status'
-alias fmc='font-manager clean'
-alias fma='font-manager all'
-
-# Advanced font management function
-function font-switch() {
-    # Show help if requested
-    if [[ "$1" == "-h" || "$1" == "--help" ]]; then
-        echo "Usage: font-switch [font-name]"
-        echo "Quickly switch between font sets"
-        echo "Example: font-switch jetbrains-mono"
-        return 0
-    fi
-
-    if [[ -z "$1" ]]; then
-        echo "Available fonts:"
-        font-manager list
-        return 0
-    fi
-
-    local font_name="$1"
-
-    # Check if font exists
-    if ! font-manager list | grep -q "$font_name"; then
-        echo "Error: Font '$font_name' not found" >&2
-        echo "Available fonts:" >&2
-        font-manager list >&2
-        return 1
-    fi
-
-    echo "Switching to $font_name fonts..."
-    font-manager clean
-    font-manager extract "$font_name"
-
-    # Reload terminal if in kitty
-    if [[ "$TERM" == "xterm-kitty" ]] && command -v kitty >/dev/null 2>&1; then
-        echo "Reloading kitty configuration..."
-        kitty @ set-colors --all ~/.config/kitty/kitty.conf
-    fi
-
-    echo "Font switch complete!"
-}
-
-# Font preview function
-function font-preview() {
-    # Show help if requested
-    if [[ "$1" == "-h" || "$1" == "--help" ]]; then
-        echo "Usage: font-preview [font-name]"
-        echo "Preview fonts in terminal"
-        echo "Example: font-preview jetbrains-mono"
-        return 0
-    fi
-
-    if [[ -z "$1" ]]; then
-        echo "Error: Font name required" >&2
-        echo "Usage: font-preview [font-name]" >&2
-        return 1
-    fi
-
-    local font_name="$1"
-    local preview_text="The quick brown fox jumps over the lazy dog
-ABCDEFGHIJKLMNOPQRSTUVWXYZ
-abcdefghijklmnopqrstuvwxyz
-0123456789
-!@#$%^&*()_+-=[]{}|;':\",./<>?"
-
-    echo "Previewing font: $font_name"
-    echo "----------------------------------------"
-    echo "$preview_text" | font-manager extract "$font_name" && echo "$preview_text"
-}
-
-yay() {
-    case "$1" in
-        # System update
-        update|"-Syu")
-            echo "Updating NixOS system..."
-              nh os switch ~/.config/nixos --update --ask
-            ;;
-
-        # Search packages
-        search|"-Ss")
-            [ -z "$2" ] && { echo "Usage: yay search <package>"; return 1; }
-            echo "Searching for '$2'..."
-            nix search nixpkgs "$2" 2>/dev/null || nix-env -qaP | grep -i "$2"
-            ;;
-
-        # Install package to user environment
-        install|"-S")
-            [ -z "$2" ] && { echo "Usage: yay install <package>"; return 1; }
-            echo "Installing $2..."
-            nix-env -iA nixpkgs.$2
-            ;;
-
-        # Remove package
-        remove|"-R")
-            [ -z "$2" ] && { echo "Usage: yay remove <package>"; return 1; }
-            echo "Removing $2..."
-            nix-env -e "$2"
-            ;;
-
-        # List installed packages
-        list|"-Q")
-            echo "Installed packages:"
-            nix-env -q
-            ;;
-
-        # nix-shell quick run
-        shell|"-p")
-            shift
-            if [ $# -eq 0 ]; then
-                echo "Usage: yay shell <pkg1> [pkg2 ...]"
-                return 1
-            fi
-            echo "Starting nix-shell with: $*"
-            nix-shell -p "$@"
-            ;;
-
-        # Clean up
-        clean|"-Sc")
-            echo "Cleaning nix store..."
-            nix-collect-garbage
-            sudo nix-collect-garbage -d
-            ;;
-
-        # Help
-        help|"-h")
-            bat -Pp << 'EOF'
-yay - Simple NixOS package manager wrapper
-
-Commands:
-  yay                    Rebuild system
-  yay update             Update system
-  yay search <pkg>       Search packages
-  yay install <pkg>      Install package (user)
-  yay remove <pkg>       Remove package
-  yay list               List installed packages
-  yay shell <pkg...>     Start nix-shell with packages
-  yay clean              Clean package cache
-  yay help               Show this help
-
-Note: For system packages, edit ~/.config/nixos/configuration.nix
-EOF
-            ;;
-
-        # Default: rebuild system
-        "")
-            echo "Rebuilding NixOS system..."
-              nh os switch ~/.config/nixos --ask
-            ;;
-
-        # Try to install unknown commands
-        *)
-            if [[ ! "$1" =~ ^- ]]; then
-                echo "Installing '$1'..."
-                nix-env -iA nixpkgs.$1
-            else
-                echo "Unknown option: $1"
-                echo "Run 'yay help' for available commands"
-                return 1
-            fi
-            ;;
-    esac
-}
-
-function nas() {
-  rclone mount --vfs-cache-mode writes --dir-cache-time 5s --no-check-certificate --allow-other nas: /home/mzunino/nas
-}
-
-
-
-function ocr(){
-  grim -g "$(slurp)" - \
-    | magick - -colorspace gray -negate -brightness-contrast 15x40 -sharpen 0x2 -threshold 60% - \
-    | tesseract stdin stdout -l eng+equ --psm 6 --oem 3 \
-    -c preserve_interword_spaces=1 \
-    -c tessedit_char_blacklist='‘’”“”´`–—•' \
-    | sed -E '
-  s/[“”]/"/g;
-  s/[‘’]/"/g;
-  s/’/'"'"'/g;
-  s/[éèê]/8/g;
-  s/í/i/g;
-  s/—/-/g;
-  s/“/"/g;
-  ' \
-    | wl-copy
-  notify-send "✅ OCR copied to clipboard"
-}

+ 197 - 0
zsh/.config/zsh/functions/dev.zsh

@@ -0,0 +1,197 @@
+#!/bin/zsh
+
+function _package_manager {
+  local pkg_manager=""
+
+  if [[ -f bun.lockb ]]; then
+    pkg_manager="bun"
+  elif [[ -f pnpm-lock.yaml ]]; then
+    pkg_manager="pnpm"
+  elif [[ -f yarn.lock ]]; then
+    pkg_manager="yarn"
+  elif [[ -f package-lock.json ]]; then
+    pkg_manager="npm"
+  else
+    pkg_manager="pnpm"
+  fi
+
+  if [[ -f package.json ]] && [[ $1 != "run" ]] && [[ $1 != "install" ]] && [[ $1 != "add" ]] && [[ $1 != "remove" ]] && [[ $1 != "i" ]] && [[ $1 != "rm" ]]; then
+    if command -v jq >/dev/null 2>&1 && jq -e ".scripts[\"$1\"] != null" package.json >/dev/null 2>&1; then
+      set -- "run" "$@"
+    fi
+  fi
+
+  if command -v corepack >/dev/null 2>&1; then
+    corepack ${pkg_manager} "$@"
+  else
+    command ${pkg_manager} "$@"
+  fi
+}
+
+function vimrc {
+  if [[ -z "$XDG_CONFIG_HOME" ]]; then
+    echo "Error: XDG_CONFIG_HOME not set" >&2
+    return 1
+  fi
+
+  local original_dir=$(pwd)
+  cd "$XDG_CONFIG_HOME/nvim" || {
+    echo "Error: Cannot access $XDG_CONFIG_HOME/nvim" >&2
+    return 1
+  }
+  nvim
+  cd "$original_dir"
+}
+
+function nixrc {
+  if [[ -z "$XDG_CONFIG_HOME" ]]; then
+    echo "Error: XDG_CONFIG_HOME not set" >&2
+    return 1
+  fi
+
+  local original_dir=$(pwd)
+  cd "$XDG_CONFIG_HOME/nixos" || {
+    echo "Error: Cannot access $XDG_CONFIG_HOME/nixos" >&2
+    return 1
+  }
+  nvim
+  cd "$original_dir"
+}
+
+function zshrc {
+  if [[ -z "$XDG_CONFIG_HOME" ]]; then
+    echo "Error: XDG_CONFIG_HOME not set" >&2
+    return 1
+  fi
+
+  local original_dir=$(pwd)
+  cd "$XDG_CONFIG_HOME/zsh" || {
+    echo "Error: Cannot access $XDG_CONFIG_HOME/zsh" >&2
+    return 1
+  }
+  nvim
+  cd "$original_dir"
+}
+
+function yay() {
+  case "$1" in
+    update|"-Syu")
+      echo "Updating NixOS system..."
+      nh os switch ~/.config/nixos --update --ask
+      ;;
+
+    search|"-Ss")
+      [ -z "$2" ] && { echo "Usage: yay search <package>"; return 1; }
+      echo "Searching for '$2'..."
+      nix search nixpkgs "$2" 2>/dev/null || nix-env -qaP | grep -i "$2"
+      ;;
+
+    install|"-S")
+      [ -z "$2" ] && { echo "Usage: yay install <package>"; return 1; }
+      echo "Installing $2..."
+      nix-env -iA nixpkgs.$2
+      ;;
+
+    remove|"-R")
+      [ -z "$2" ] && { echo "Usage: yay remove <package>"; return 1; }
+      echo "Removing $2..."
+      nix-env -e "$2"
+      ;;
+
+    list|"-Q")
+      echo "Installed packages:"
+      nix-env -q
+      ;;
+
+    shell|"-p")
+      shift
+      if [ $# -eq 0 ]; then
+        echo "Usage: yay shell <pkg1> [pkg2 ...]"
+        return 1
+      fi
+      echo "Starting nix-shell with: $*"
+      nix-shell -p "$@"
+      ;;
+
+    clean|"-Sc")
+      echo "Cleaning nix store..."
+      nix-collect-garbage
+      sudo nix-collect-garbage -d
+      ;;
+
+    help|"-h")
+      bat -Pp << 'EOF'
+yay - Simple NixOS package manager wrapper
+
+Commands:
+  yay                    Rebuild system
+  yay update             Update system
+  yay search <pkg>       Search packages
+  yay install <pkg>      Install package (user)
+  yay remove <pkg>       Remove package
+  yay list               List installed packages
+  yay shell <pkg...>     Start nix-shell with packages
+  yay clean              Clean package cache
+  yay help               Show this help
+
+Note: For system packages, edit ~/.config/nixos/configuration.nix
+EOF
+      ;;
+
+    "")
+      echo "Rebuilding NixOS system..."
+      nh os switch ~/.config/nixos --ask
+      ;;
+
+    *)
+      if [[ ! "$1" =~ ^- ]]; then
+        echo "Installing '$1'..."
+        nix-env -iA nixpkgs.$1
+      else
+        echo "Unknown option: $1"
+        echo "Run 'yay help' for available commands"
+        return 1
+      fi
+      ;;
+  esac
+}
+
+_package_manager_completion() {
+  local -a commands
+  commands=(
+    'run:Run npm script'
+    'install:Install dependencies'
+    'add:Add dependency'
+    'remove:Remove dependency'
+    'dev:Start dev server'
+    'build:Build project'
+    'test:Run tests'
+    'lint:Run linter'
+  )
+  _describe 'package manager commands' commands
+}
+
+_yay_completion() {
+  local -a opts
+  opts=(
+    '-Syyu:Update system'
+    '-Syu:Update system'
+    '-Ss:Search packages'
+    '-S:Install system-wide'
+    '-R:Remove package'
+    '-Q:List installed'
+    '-Si:Package info'
+    '-Sc:Clean cache'
+    '-p:Open nix-shell with packages'
+    'help:Show help'
+    'install:Install to user env'
+    'remove:Remove from user env'
+    'list:List installed packages'
+    'clean:Clean nix store'
+    'shell:Start nix-shell with packages'
+  )
+  _describe 'yay commands' opts
+}
+
+compdef _package_manager_completion _package_manager p
+compdef _yay_completion yay

+ 169 - 0
zsh/.config/zsh/functions/git.zsh

@@ -0,0 +1,169 @@
+#!/bin/zsh
+
+function dc() {
+  if [[ "$1" == "-h" || "$1" == "--help" ]]; then
+    echo "Usage: dc [commit_message]"
+    echo "Quickly commit all changes and push to remote"
+    echo "If no message provided, uses timestamp-based message"
+    return 0
+  fi
+
+  if ! git rev-parse --is-inside-work-tree &>/dev/null; then
+    echo "Error: Not in a git repository" >&2
+    return 1
+  fi
+
+  if [[ -z $(git status --porcelain) ]]; then
+    echo "No changes to commit"
+    return 0
+  fi
+
+  git add .
+
+  local commit_msg
+  if [[ -n "$1" ]]; then
+    commit_msg="$1"
+  else
+    local timestamp=$(date +"%Y-%m-%d %H:%M:%S")
+    commit_msg="dev: automated commit - ${timestamp}"
+  fi
+
+  if git commit -m "$commit_msg" --no-gpg-sign; then
+    if git push &>/dev/null; then
+      echo "Committed and pushed successfully"
+    else
+      echo "Warning: Commit successful but push failed" >&2
+      return 1
+    fi
+  else
+    echo "Commit failed" >&2
+    return 1
+  fi
+}
+
+function nu() {
+  if [[ "$1" == "-h" || "$1" == "--help" ]]; then
+    echo "Usage: nu [commit_message]"
+    echo "Quickly commit NixOS changes and push to remote"
+    echo "If no message provided, uses timestamp-based message"
+    return 0
+  fi
+
+  local original_dir=$(pwd)
+  if [[ -z "$XDG_CONFIG_HOME" ]]; then
+    echo "Error: XDG_CONFIG_HOME not set" >&2
+    return 1
+  fi
+
+  cd "$XDG_CONFIG_HOME/nixos" || {
+    echo "Error: Cannot access $XDG_CONFIG_HOME/nixos" >&2
+    return 1
+  }
+
+  if ! git rev-parse --is-inside-work-tree &>/dev/null; then
+    echo "Error: Not in a git repository" >&2
+    cd "$original_dir"
+    return 1
+  fi
+
+  if [[ -z $(git status --porcelain) ]]; then
+    echo "No changes to commit"
+    cd "$original_dir"
+    return 0
+  fi
+
+  git add .
+
+  local commit_msg
+  if [[ -n "$1" ]]; then
+    commit_msg="$1"
+  else
+    local timestamp=$(date +"%Y-%m-%d %H:%M:%S")
+    commit_msg="nixos: automated commit - ${timestamp}"
+  fi
+
+  if git commit -m "$commit_msg" --no-gpg-sign; then
+    if git push &>/dev/null; then
+      echo "NixOS changes committed and pushed successfully"
+    else
+      echo "Warning: Commit successful but push failed" >&2
+      cd "$original_dir"
+      return 1
+    fi
+  else
+    echo "Commit failed" >&2
+    cd "$original_dir"
+    return 1
+  fi
+
+  cd "$original_dir"
+}
+
+function zrepo() {
+  if [[ "$1" == "-h" || "$1" == "--help" ]]; then
+    echo "Usage: zrepo <repo-name>"
+    echo "Create a new bare git repository on remote server"
+    echo "Example: zrepo my-project"
+    return 0
+  fi
+
+  if [[ -z "$1" ]]; then
+    echo "Error: Repository name required" >&2
+    echo "Usage: zrepo <repo-name>" >&2
+    return 1
+  fi
+
+  local REPO="$1"
+  local SERVER="git@zvps"
+  local PATH_ON_SERVER="/var/git/$REPO.git"
+
+  echo "Creating repository '$REPO' on $SERVER..."
+
+  ssh "$SERVER" "
+    if [ -d $PATH_ON_SERVER ]; then
+      echo 'Error: Repository '$REPO' already exists'
+      exit 1
+    fi
+    mkdir -p $PATH_ON_SERVER &&
+    git init --bare $PATH_ON_SERVER &&
+    chown -R git:git $PATH_ON_SERVER &&
+    chmod -R 755 $PATH_ON_SERVER
+  " || {
+    echo "Failed to create repository" >&2
+    return 1
+  }
+
+  echo "Repository created on $SERVER:$PATH_ON_SERVER"
+
+  if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
+    git remote add origin "$SERVER:$PATH_ON_SERVER"
+    echo "Remote 'origin' added to your local repository"
+  else
+    echo "To clone this repository, run:"
+    echo "  git clone $SERVER:$PATH_ON_SERVER"
+  fi
+}
+
+_dc_completion() {
+  local -a messages
+  messages=(
+    'fix:'
+    'feat:'
+    'docs:'
+    'style:'
+    'refactor:'
+    'test:'
+    'chore:'
+  )
+  _describe 'commit types' messages
+}
+
+_zrepo_completion() {
+  local -a repos
+  # Could be enhanced to fetch from remote server
+  repos=()
+  _describe 'repository names' repos
+}
+
+compdef _dc_completion dc
+compdef _zrepo_completion zrepo

+ 126 - 0
zsh/.config/zsh/functions/k8s.zsh

@@ -0,0 +1,126 @@
+#!/bin/zsh
+
+function kf {
+  if [[ "$1" == "-h" || "$1" == "--help" ]]; then
+    echo "Usage: kf <cluster> [service-name[:port]] [service-name[:port]] ..."
+    echo "Example: kf oc-dev-internal-eks-cluster oc-activate-web"
+    echo "Example: kf oc-dev-internal-eks-cluster oc-activate-web:8080"
+    echo "Example: kf oc-dev-internal-eks-cluster oc-activate-web:8080 oc-member-dossier:8081"
+    return 0
+  fi
+
+  local cluster="$1"
+  shift
+
+  if [[ -z "$cluster" ]]; then
+    echo "Error: Missing cluster" >&2
+    echo "Usage: kf <cluster> [service-name[:port]] [service-name[:port]] ..." >&2
+    return 1
+  fi
+
+  if [[ $# -eq 0 ]]; then
+    echo "🔌 Available services in cluster: $cluster"
+    kubectl --context "$cluster" -n oc-app get svc -o name | sed 's/service\//   - /'
+    return 0
+  fi
+
+  echo "🔌 Forwarding services (cluster: $cluster)"
+  
+  local existing_pids
+  existing_pids=$(pgrep -f "kubectl.*port-forward" || true)
+  if [[ -n "$existing_pids" ]]; then
+    echo "$existing_pids" | xargs kill 2>/dev/null || true
+    existing_pids=$(pgrep -f "kubectl.*port-forward" || true)
+    if [[ -n "$existing_pids" ]]; then
+      echo "$existing_pids" | xargs kill -9 2>/dev/null || true
+      sleep 0.5
+    fi
+  fi
+  
+  local pids=()
+
+  for service_spec in "$@"; do
+    local service_name local_port
+    if [[ "$service_spec" == *":"* ]]; then
+      service_name="${service_spec%:*}"
+      local_port="${service_spec##*:}"
+    else
+      service_name="$service_spec"
+      local_port=""
+    fi
+
+    local svc
+    svc=$(kubectl --context "$cluster" -n oc-app get svc -o name | grep "^service/$service_name$" || true)
+    
+    if [[ -z "$svc" ]]; then
+      echo "⚠️  Service '$service_name' not found in namespace 'oc-app' - skipping"
+      echo "   Available services:"
+      kubectl --context "$cluster" -n oc-app get svc -o name | sed 's/service\//   - /' | head -5
+      continue
+    fi
+
+    local name="${svc#service/}"
+    local service_port
+    service_port=$(kubectl --context "$cluster" -n oc-app get "svc/$name" -o jsonpath='{.spec.ports[0].port}')
+    local forward_port="${local_port:-$service_port}"
+
+    local port_info
+    port_info=$(lsof -i :$forward_port 2>/dev/null)
+    if [[ -n "$port_info" ]]; then
+      local pid=$(echo "$port_info" | tail -n +2 | awk '{print $2}' | head -1)
+      local process=$(echo "$port_info" | tail -n +2 | awk '{print $1}' | head -1)
+      echo "⚠️  Port $forward_port in use by $process (PID: $pid) - skipping $name"
+      continue
+    fi
+
+    if [[ -n "$local_port" ]]; then
+      echo "→ Forwarding $name (service port $service_port) to local port $forward_port"
+    else
+      echo "→ Forwarding $name on port $forward_port"
+    fi
+    
+    kubectl --context "$cluster" -n oc-app port-forward "svc/$name" "$forward_port:$service_port" >/dev/null 2>&1 &
+    local pid=$!
+
+    sleep 0.5
+    if ! kill -0 $pid 2>/dev/null; then
+      echo "❌ Failed to start port-forward for $name on port $forward_port"
+      continue
+    fi
+
+    pids+=($pid)
+  done
+
+  if [[ ${#pids[@]} -eq 0 ]]; then
+    echo "❌ No port-forwards were started successfully"
+    return 1
+  fi
+
+  echo "→ All forwards running (PIDs: ${pids[*]})"
+  echo "→ Press Ctrl+C to stop"
+
+  trap 'echo; echo "🛑 Stopping port-forwards..."; for pid in ${pids[*]}; do kill $pid 2>/dev/null; done; sleep 1; for pid in ${pids[*]}; do kill -9 $pid 2>/dev/null; done; wait ${pids[*]} 2>/dev/null; return 0' INT
+
+  wait
+}
+
+_kf_completion() {
+  local -a contexts
+  contexts=($(kubectx 2>/dev/null | sed 's/-read$//; s/-security$//' | sort -u))
+
+  if [[ ${#contexts[@]} -gt 0 ]]; then
+    _describe 'cluster' contexts
+  fi
+}
+
+_rmq_passwd_completion() {
+  local -a environments
+  environments=($(kubectl config get-contexts -o name 2>/dev/null | grep '^oc-.*-eks-cluster$' | sed 's/^oc-//; s/-eks-cluster$//' | sort -u))
+
+  if [[ ${#environments[@]} -gt 0 ]]; then
+    _describe 'environments' environments
+  fi
+}
+
+compdef _kf_completion kf
+compdef _rmq_passwd_completion rmq-passwd

+ 43 - 0
zsh/.config/zsh/functions/navigation.zsh

@@ -0,0 +1,43 @@
+#!/bin/zsh
+
+eval "$(zoxide init zsh)"
+
+zcd() { z "$@" }
+zadd() { z "$@" }
+zremove() { zoxide remove "$@" }
+
+alias zi=zcd
+alias za=zadd
+alias zrm=zremove
+
+function open {
+  if [[ $# -eq 0 ]]; then
+    echo "Usage: open <file1> [file2] ..."
+    echo "Opens files using the system default application"
+    return 1
+  fi
+
+  for i in "$@"; do
+    if [[ ! -e "$i" ]]; then
+      echo "Warning: '$i' does not exist" >&2
+      continue
+    fi
+    setsid nohup xdg-open "$i" > /dev/null 2> /dev/null &
+  done
+}
+
+function fopen() {
+  if ! command -v fd >/dev/null 2>&1; then
+    echo "Error: fd is not installed" >&2
+    return 1
+  fi
+
+  if ! command -v fzf >/dev/null 2>&1; then
+    echo "Error: fzf is not installed" >&2
+    return 1
+  fi
+
+  local selected
+  selected=$(fd "$@" | fzf --preview 'bat --color=always --style=numbers --line-range=:500 {}')
+  [[ -n "$selected" ]] && setsid nohup xdg-open "$selected" >/dev/null 2>&1 &
+}

+ 144 - 0
zsh/.config/zsh/functions/stow.zsh

@@ -0,0 +1,144 @@
+#!/bin/zsh
+
+function stowify() {
+  if [[ "$1" == "-h" || "$1" == "--help" ]]; then
+    echo "Usage: stowify <path> [module-name]"
+    echo "Create a new stow module from an existing directory"
+    echo ""
+    echo "Examples:"
+    echo "  stowify ~/.config/test"
+    echo "  stowify ~/.config/test my-test-config"
+    echo "  stowify /etc/nginx nginx-config"
+    echo ""
+    echo "This will:"
+    echo "  1. Create ~/dotfiles/[module-name]/ directory"
+    echo "  2. Move the directory structure to the stow package"
+    echo "  3. Create symlinks back to original locations"
+    echo "  4. Run stow to install the package"
+    return 0
+  fi
+
+  if [[ -z "$1" ]]; then
+    echo "Error: Path required" >&2
+    echo "Usage: stowify <path> [module-name]" >&2
+    return 1
+  fi
+
+  local source_path="$1"
+  local module_name="$2"
+
+  # Resolve absolute path
+  if [[ ! "$source_path" =~ ^/ ]]; then
+    source_path="$(realpath "$source_path")"
+  fi
+
+  # Check if source exists
+  if [[ ! -e "$source_path" ]]; then
+    echo "Error: Path '$source_path' does not exist" >&2
+    return 1
+  fi
+
+  # Determine module name if not provided
+  if [[ -z "$module_name" ]]; then
+    module_name=$(basename "$source_path")
+  fi
+
+  # Validate module name
+  if [[ ! "$module_name" =~ ^[a-zA-Z0-9_-]+$ ]]; then
+    echo "Error: Module name '$module_name' contains invalid characters" >&2
+    echo "Use only letters, numbers, hyphens, and underscores" >&2
+    return 1
+  fi
+
+  local dotfiles_dir="$HOME/dotfiles"
+  local stow_package_dir="$dotfiles_dir/$module_name"
+
+  # Check if dotfiles directory exists
+  if [[ ! -d "$dotfiles_dir" ]]; then
+    echo "Error: Dotfiles directory '$dotfiles_dir' not found" >&2
+    echo "Make sure you're using stow for dotfiles management" >&2
+    return 1
+  fi
+
+  # Check if module already exists
+  if [[ -d "$stow_package_dir" ]]; then
+    echo "Error: Module '$module_name' already exists in dotfiles" >&2
+    echo "Use a different name or remove the existing module first" >&2
+    return 1
+  fi
+
+  echo "Creating stow module '$module_name' from '$source_path'..."
+
+  # Create the stow package directory
+  mkdir -p "$stow_package_dir"
+
+  # Determine the relative path structure
+  local relative_path=""
+  if [[ "$source_path" == "$HOME"* ]]; then
+    # Home directory - create ~ structure
+    relative_path="${source_path#$HOME/}"
+    if [[ "$relative_path" == "$HOME" ]]; then
+      relative_path=""
+    fi
+  else
+    # System directory - create absolute structure
+    relative_path="$source_path"
+  fi
+
+  # Create the directory structure in the stow package
+  if [[ -n "$relative_path" ]]; then
+    mkdir -p "$stow_package_dir/$(dirname "$relative_path")"
+  fi
+
+  # Move the directory to the stow package
+  if [[ -d "$source_path" ]]; then
+    if [[ -n "$relative_path" ]]; then
+      mv "$source_path" "$stow_package_dir/$relative_path"
+    else
+      # Special case for home directory
+      echo "Error: Cannot stowify the entire home directory" >&2
+      rmdir "$stow_package_dir"
+      return 1
+    fi
+  else
+    # Single file
+    if [[ -n "$relative_path" ]]; then
+      mv "$source_path" "$stow_package_dir/$relative_path"
+    else
+      mv "$source_path" "$stow_package_dir/"
+    fi
+  fi
+
+  echo "Directory moved to stow package: $stow_package_dir"
+
+  # Run stow to create symlinks
+  echo "Running stow to create symlinks..."
+  cd "$dotfiles_dir"
+  
+  if stow "$module_name"; then
+    echo "✅ Successfully created stow module '$module_name'"
+    echo "📁 Package location: $stow_package_dir"
+    echo "🔗 Symlinks created back to original locations"
+    echo ""
+    echo "To manage this module:"
+    echo "  stow $module_name          # Install/update"
+    echo "  stow -D $module_name        # Uninstall"
+    echo "  stow -R $module_name        # Restow"
+  else
+    echo "❌ Stow failed. You may need to manually resolve conflicts." >&2
+    echo "The directory has been moved to: $stow_package_dir" >&2
+    return 1
+  fi
+}
+
+_stowify_completion() {
+  local context state line
+  typeset -A opt_args
+
+  _arguments -C \
+    '1:path:_files -/' \
+    '2:module-name:()' \
+    '(-h --help)'{-h,--help}'[Show help]'
+}
+
+compdef _stowify_completion stowify

+ 269 - 0
zsh/.config/zsh/functions/system.zsh

@@ -0,0 +1,269 @@
+#!/bin/zsh
+
+function expose() {
+  if [[ "$1" == "-h" || "$1" == "--help" ]]; then
+    echo "Usage: expose <port>"
+    echo "Create SSH tunnel to expose local port through remote server"
+    echo "Example: expose 3000  # Exposes localhost:3000"
+    return 0
+  fi
+
+  if [[ -z "$1" ]]; then
+    echo "Error: Port number required" >&2
+    echo "Usage: expose <port>" >&2
+    return 1
+  fi
+
+  if ! [[ "$1" =~ ^[0-9]+$ ]] || [[ "$1" -lt 1 ]] || [[ "$1" -gt 65535 ]]; then
+    echo "Error: Invalid port number. Must be between 1-65535" >&2
+    return 1
+  fi
+
+  if lsof -i ":$1" >/dev/null 2>&1; then
+    echo "Warning: Port $1 is already in use" >&2
+    echo "Current processes using port $1:"
+    lsof -i ":$1"
+    echo -n "Continue anyway? [y/N] "
+    read confirm
+    if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
+      echo "Operation cancelled"
+      return 1
+    fi
+  fi
+
+  echo "Creating SSH tunnel for port $1..."
+  ssh marianozunino@srv.us -R 1:localhost:"$1"
+}
+
+function ppid {
+  if [[ "$1" == "-h" || "$1" == "--help" ]]; then
+    echo "Usage: ppid <port>"
+    echo "Find processes using the specified port"
+    echo "Alias: pport"
+    return 0
+  fi
+
+  if [[ -z "$1" ]]; then
+    echo "Error: Port number required" >&2
+    echo "Usage: ppid <port>" >&2
+    return 1
+  fi
+
+  if ! [[ "$1" =~ ^[0-9]+$ ]] || [[ "$1" -lt 1 ]] || [[ "$1" -gt 65535 ]]; then
+    echo "Error: Invalid port number. Must be between 1-65535" >&2
+    return 1
+  fi
+
+  lsof -i ":$1"
+}
+
+alias pport="ppid"
+
+function wacom {
+  if [[ "$1" == "-h" || "$1" == "--help" ]]; then
+    echo "Usage: wacom"
+    echo "Configure Wacom tablet for current display session"
+    echo "Supports both Wayland and X11 sessions"
+    return 0
+  fi
+
+  if [[ "$XDG_SESSION_TYPE" = "wayland" ]]; then
+    if ! command -v otd >/dev/null 2>&1; then
+      echo "Error: opentabletdriver (otd) not found" >&2
+      return 1
+    fi
+
+    systemctl --user enable opentabletdriver --now
+
+    local config_file="$HOME/Sync/System/Configs/wacom/wacom.json"
+    if [[ -f "$config_file" ]]; then
+      otd loadsettings "$config_file"
+      echo "Wacom configured for Wayland"
+    else
+      echo "Warning: Config file not found at $config_file" >&2
+    fi
+  else
+    if ! command -v xsetwacom >/dev/null 2>&1; then
+      echo "Error: xsetwacom not found" >&2
+      return 1
+    fi
+
+    xsetwacom --set "Wacom One by Wacom S Pen stylus" ResetArea
+    xsetwacom --set "Wacom One by Wacom S Pen stylus" MapToOutput DisplayPort-0
+    xsetwacom --set "Wacom One by Wacom S Pen stylus" Rotate half
+
+    xsetwacom --set "Wacom One by Wacom S Pen eraser" ResetArea
+    xsetwacom --set "Wacom One by Wacom S Pen eraser" MapToOutput DisplayPort-0
+
+    echo "Wacom configured for X11"
+  fi
+}
+
+function cat {
+  if [[ "$1" == "-h" || "$1" == "--help" ]]; then
+    echo "Usage: cat [file1] [file2] ..."
+    echo "Enhanced cat using bat with syntax highlighting"
+    echo "Automatically adjusts output for SSH sessions"
+    return 0
+  fi
+
+  if ! command -v bat >/dev/null 2>&1; then
+    echo "Warning: bat not found, falling back to system cat" >&2
+    command cat "$@"
+    return $?
+  fi
+
+  if [[ -n "$SSH_TTY" ]] || [[ -n "$SSH_CLIENT" ]] || [[ -n "$SSH_CONNECTION" ]]; then
+    bat --plain --paging=never "$@"
+  else
+    bat "$@"
+  fi
+}
+
+function toggle_resolution() {
+  if [[ "$1" == "-h" || "$1" == "--help" ]]; then
+    echo "Usage: toggle_resolution [-m|--mirror]"
+    echo "Toggle between different display resolutions and modes"
+    echo "Options:"
+    echo "  -m, --mirror    Force mirror mode"
+    return 0
+  fi
+
+  local mirror_mode=false
+
+  while [[ $# -gt 0 ]]; do
+    case $1 in
+      -m|--mirror)
+        mirror_mode=true
+        shift
+        ;;
+      *)
+        shift
+        ;;
+    esac
+  done
+
+  if ! command -v swaymsg >/dev/null 2>&1; then
+    echo "Error: swaymsg not found. This function requires Sway window manager" >&2
+    return 1
+  fi
+
+  if ! command -v jq >/dev/null 2>&1; then
+    echo "Error: jq not found. Required for JSON parsing" >&2
+    return 1
+  fi
+
+  local current_state
+  current_state=$(swaymsg -t get_outputs | jq -r '.[] | select(.name == "eDP-1") | "\(.current_mode.width)x\(.current_mode.height):\(.scale)"')
+
+  local external_monitor=""
+  if swaymsg -t get_outputs | jq -r '.[].name' | grep -q "DP-2"; then
+    external_monitor="DP-2"
+  elif swaymsg -t get_outputs | jq -r '.[].name' | grep -q "HDMI-A-1"; then
+    external_monitor="HDMI-A-1"
+  fi
+
+  if [[ "$mirror_mode" == true ]] || [[ -n "$external_monitor" ]]; then
+    echo "Switching to mirror mode (1920x1080)..."
+
+    swaymsg output eDP-1 resolution 1920x1080@120Hz scale 1.0 pos 0 0
+
+    if [[ -n "$external_monitor" ]]; then
+      swaymsg output "$external_monitor" resolution 1920x1080@60Hz pos 0 0
+      echo "Mirror mode enabled: eDP-1 + $external_monitor at 1920x1080"
+    else
+      echo "Internal monitor configured to 1920x1080 (no external monitor detected)"
+    fi
+
+  elif [[ "$current_state" == "2880x1920:2.0" ]]; then
+    echo "Switching to 1920x1080 (16:9)..."
+    swaymsg output eDP-1 resolution 1920x1080@120Hz scale 1.0
+
+    if [[ -n "$external_monitor" ]]; then
+      swaymsg output "$external_monitor" pos 1920 0
+      echo "Extended mode: $external_monitor positioned to the right"
+    fi
+
+  else
+    echo "Switching to 2880x1920 (3:2) native..."
+    swaymsg output eDP-1 resolution 2880x1920@120Hz scale 2.0
+
+    if [[ -n "$external_monitor" ]]; then
+      swaymsg output "$external_monitor" pos 1440 0
+      echo "Extended mode: $external_monitor positioned to the right"
+    fi
+  fi
+
+  echo "Current configuration:"
+  swaymsg -t get_outputs | jq -r '.[] | select(.active == true) | "  \(.name): \(.current_mode.width)x\(.current_mode.height)@\(.current_mode.refresh/1000)Hz scale:\(.scale) pos:(\(.rect.x),\(.rect.y))"'
+}
+
+function cb {
+  if [[ "$1" == "-h" || "$1" == "--help" ]]; then
+    echo "Usage: cb [codeblocks-args]"
+    echo "Launch Code::Blocks with high contrast theme"
+    return 0
+  fi
+
+  if [[ ! -f /usr/bin/codeblocks ]]; then
+    echo "Error: Code::Blocks not found at /usr/bin/codeblocks" >&2
+    return 1
+  fi
+
+  local original_gtk_theme="$GTK_THEME"
+  local original_gdk_theme="$GDK_THEME"
+  local original_qt_style="$QT_STYLE_OVERRIDE"
+  local original_xdg_desktop="$XDG_CURRENT_DESKTOP"
+
+  GTK_THEME=HighContrast \
+  GDK_THEME=HighContrast \
+  QT_STYLE_OVERRIDE=HighContrast \
+  XDG_CURRENT_DESKTOP=GNOME \
+  GTK2_RC_FILES="" \
+  GTK_RC_FILES="" \
+  /usr/bin/codeblocks "$@"
+
+  export GTK_THEME="$original_gtk_theme"
+  export GDK_THEME="$original_gdk_theme"
+  export QT_STYLE_OVERRIDE="$original_qt_style"
+  export XDG_CURRENT_DESKTOP="$original_xdg_desktop"
+}
+
+function nas() {
+  rclone mount --vfs-cache-mode writes --dir-cache-time 5s --no-check-certificate --allow-other nas: /home/mzunino/nas
+}
+
+function ocr(){
+  grim -g "$(slurp)" - \
+    | magick - -colorspace gray -negate -brightness-contrast 15x40 -sharpen 0x2 -threshold 60% - \
+    | tesseract stdin stdout -l eng+equ --psm 6 --oem 3 \
+    -c preserve_interword_spaces=1 \
+    -c tessedit_char_blacklist='''""´`–—•' \
+    | sed -E '
+  s/[""]/"/g;
+  s/[''']/"/g;
+  s/'/'"'"'/g;
+  s/[éèê]/8/g;
+  s/í/i/g;
+  s/—/-/g;
+  s/"/"/g;
+  ' \
+    | wl-copy
+  notify-send "✅ OCR copied to clipboard"
+}
+
+function _has {
+  if [[ $# -eq 0 ]]; then
+    echo "Usage: _has <command>" >&2
+    return 1
+  fi
+
+  whence "$1" >/dev/null 2>&1
+}
+
+if [[ -v TMUX ]]; then
+  function swaymsg {
+    export SWAYSOCK=$XDG_RUNTIME_DIR/sway-ipc.$UID.$(pgrep -x sway).sock
+    command swaymsg "$@"
+  }
+fi

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

@@ -0,0 +1,68 @@
+#!/bin/zsh
+
+function font-switch() {
+  if [[ "$1" == "-h" || "$1" == "--help" ]]; then
+    echo "Usage: font-switch [font-name]"
+    echo "Quickly switch between font sets"
+    echo "Example: font-switch jetbrains-mono"
+    return 0
+  fi
+
+  if [[ -z "$1" ]]; then
+    echo "Available fonts:"
+    font-manager list
+    return 0
+  fi
+
+  local font_name="$1"
+
+  if ! font-manager list | grep -q "$font_name"; then
+    echo "Error: Font '$font_name' not found" >&2
+    echo "Available fonts:" >&2
+    font-manager list >&2
+    return 1
+  fi
+
+  echo "Switching to $font_name fonts..."
+  font-manager clean
+  font-manager extract "$font_name"
+
+  if [[ "$TERM" == "xterm-kitty" ]] && command -v kitty >/dev/null 2>&1; then
+    echo "Reloading kitty configuration..."
+    kitty @ set-colors --all ~/.config/kitty/kitty.conf
+  fi
+
+  echo "Font switch complete!"
+}
+
+function font-preview() {
+  if [[ "$1" == "-h" || "$1" == "--help" ]]; then
+    echo "Usage: font-preview [font-name]"
+    echo "Preview fonts in terminal"
+    echo "Example: font-preview jetbrains-mono"
+    return 0
+  fi
+
+  if [[ -z "$1" ]]; then
+    echo "Error: Font name required" >&2
+    echo "Usage: font-preview [font-name]" >&2
+    return 1
+  fi
+
+  local font_name="$1"
+  local preview_text="The quick brown fox jumps over the lazy dog
+ABCDEFGHIJKLMNOPQRSTUVWXYZ
+abcdefghijklmnopqrstuvwxyz
+0123456789
+!@#$%^&*()_+-=[]{}|;':\",./<>?"
+
+  echo "Previewing font: $font_name"
+  echo "----------------------------------------"
+  echo "$preview_text" | font-manager extract "$font_name" && echo "$preview_text"
+}
+
+alias fm='font-manager'
+alias fml='font-manager list'
+alias fms='font-manager status'
+alias fmc='font-manager clean'
+alias fma='font-manager all'

+ 11 - 1
zsh/.config/zsh/init.zsh

@@ -82,6 +82,16 @@ source "$ZDOTDIR/rose-pine.sh"
 
 # Defer loading
 zsh-defer source "$PLUGIN_DIR/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh"
-for config in tmux.zsh functions.zsh alias.zsh keymap.zsh path.zsh pnpm.zsh mise.zsh; do
+
+# Load function files
+for func_file in "$ZDOTDIR/functions"/*.zsh; do
+  zsh-defer source "$func_file"
+done
+
+# Load external completions
+zsh-defer source "$ZDOTDIR/completions/external.zsh"
+
+# Load other config files
+for config in tmux.zsh alias.zsh keymap.zsh path.zsh pnpm.zsh mise.zsh; do
   zsh-defer source "$ZDOTDIR/$config"
 done

二進制
zsh/.config/zsh/zsh_history_main


+ 1 - 0
zsh/.zshenv

@@ -26,3 +26,4 @@ export GTK2_RC_FILES="$XDG_CONFIG_HOME/gtk-2.0/gtkrc-2.0"
 export WGETRC="$XDG_CONFIG_HOME/wgetrc"
 export JAVA_HOME="/usr/lib/jvm/default"
 export PATH="$HOME/.local/bin:$PATH"
+