Sfoglia il codice sorgente

dev: automated commit - 2025-09-05 14:49:59

Mariano Z. 5 mesi fa
parent
commit
c84dfa059e

+ 19 - 0
sway/.config/sway/config.d/keybindings

@@ -121,3 +121,22 @@ bindsym {
     button3 floating toggle
     $mod+button3 floating toggle
 }
+
+# Presentation Mode
+mode "present" {
+    # command starts mirroring
+    bindsym m mode "default"; exec wl-present mirror
+    # these commands modify an already running mirroring window
+    bindsym o mode "default"; exec wl-present set-output
+    bindsym r mode "default"; exec wl-present set-region
+    bindsym Shift+r mode "default"; exec wl-present unset-region
+    bindsym s mode "default"; exec wl-present set-scaling
+    bindsym f mode "default"; exec wl-present toggle-freeze
+    bindsym c mode "default"; exec wl-present custom
+
+    # return to default mode
+    bindsym Return mode "default"
+    bindsym Escape mode "default"
+}
+
+bindsym $mod+Shift+m mode "present"

+ 3 - 26
zsh/.config/zsh/.zprofile

@@ -1,27 +1,4 @@
-# === Variables específicas para sesión gráfica (Wayland/Sway) ===
-export ZDOTDIR=~/.config/zsh
-export MOZ_ENABLE_WAYLAND=1
-export QT_QPA_PLATFORM=wayland-egl
-export QT_WAYLAND_DISABLE_WINDOWDECORATION=1
-export QT_QPA_PLATFORMTHEME=qt5ct
-export QT_STYLE_OVERRIDE=kvantum
-export CLUTTER_BACKEND=wayland
-export GDK_BACKEND=wayland
-export ECORE_EVAS_ENGINE=wayland_egl
-export ELM_ENGINE=wayland_wgl
-export SDL_VIDEODRIVER=wayland
-export _JAVA_AWT_WM_NONREPARENTING=1
-export XDG_CURRENT_DESKTOP=sway
-export XDG_SESSION_TYPE=wayland
-
-unset SSH_AGENT_PID
-if [ "${gnupg_SSH_AUTH_SOCK_by:-0}" -ne $$ ]; then
-	export SSH_AUTH_SOCK="$(gpgconf --list-dirs agent-ssh-socket)"
-fi
-export GPG_TTY=$(tty)
-gpg-connect-agent updatestartuptty /bye >/dev/null
-
-if [ -z "$WAYLAND_DISPLAY" ] && [ "$XDG_VTNR" -eq 1 ]; then
-    exec sway
-fi
+source ~/.config/env
 
+# If running from tty1 start sway
+[ "$(tty)" = "/dev/tty1" ] && exec dbus-run-session sway

+ 6 - 3
zsh/.config/zsh/.zshrc

@@ -1,9 +1,12 @@
 source $ZDOTDIR/init.zsh
 
-# Initialize completions with defer
+# Initialize completions immediately
 autoload -Uz compinit
 if [ "$(date +'%j')" != "$(stat -f '%Sm' -t '%j' ~/.zcompdump 2>/dev/null)" ]; then
-    zsh-defer compinit
+    compinit
 else
-    zsh-defer compinit -C
+    compinit -C
 fi
+
+# Load completion registrations
+source $ZDOTDIR/completions.zsh

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

@@ -0,0 +1,48 @@
+#!/bin/zsh
+# Completion registration file
+# This file handles all completion registrations
+
+# Load custom completion files
+for completion_file in ~/.local/share/zsh/*-autocomplete.zsh; do
+    if [ -f "$completion_file" ]; then
+        source "$completion_file"
+    fi
+done
+
+# Lazy loading function for completions
+_lazy_load_completion() {
+    local cmd="$1"
+    local completion_cmd="$2"
+    
+    eval "${cmd}() {
+        unfunction $cmd
+        eval \"\$($completion_cmd)\"
+        $cmd \"\$@\"
+    }"
+}
+
+# Load lightweight completions immediately
+if command -v eza &> /dev/null; then compdef eza=ls; fi
+
+# Defer heavy completions with lazy loading
+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
+
+# Load remaining completions normally (they're lightweight)
+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
+
+# Custom completion for kf function using kubectx contexts
+_kf_completion() {
+    local -a contexts
+    # Get all contexts and extract unique cluster names (remove -read and -security suffixes)
+    contexts=($(kubectx 2>/dev/null | sed 's/-read$//; s/-security$//' | sort -u))
+    
+    if [[ ${#contexts[@]} -gt 0 ]]; then
+        _values 'cluster' "${contexts[@]}"
+    fi
+}
+
+# Register the completion
+compdef _kf_completion kf

+ 406 - 193
zsh/.config/zsh/functions.zsh

@@ -1,27 +1,64 @@
 #!/bin/zsh
 
+# =============================================================================
+# NAVIGATION UTILITIES
+# =============================================================================
+
 eval "$(zoxide init zsh)"
 
-zi() { z "$@" }
-za() { z "$@" }
-zrm() { zoxide remove "$@" }
+# 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 {
-  for i in $*; do
-    setsid nohup xdg-open $i > /dev/null 2> /dev/null
+  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
-# Package manager detection with caching
+# =============================================================================
+
+# 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
@@ -31,15 +68,17 @@ function _package_manager {
   elif [[ -f package-lock.json ]]; then
     pkg_manager="npm"
   else
-    pkg_manager="pnpm"
+    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 jq -e ".scripts[\"$1\"] != null" package.json >/dev/null 2>&1; 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
@@ -47,10 +86,18 @@ function _package_manager {
   fi
 }
 
-# Improved development commit with optional message
+# 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"
+    echo "Error: Not in a git repository" >&2
     return 1
   fi
 
@@ -69,13 +116,35 @@ function dc() {
     commit_msg="dev: automated commit - ${timestamp}"
   fi
 
-  # pass other args
-  git commit -m "$commit_msg" --no-gpg-sign "$@"
-  git push &>/dev/null || { echo "Push failed"; return 1; }
+  # 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
 }
 
-# Git branch cleanup helper
+# 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")
 
@@ -100,117 +169,136 @@ function git-clean() {
       echo "$branches_to_delete" | xargs -I{} git push origin --delete {}
       echo "Remote branches deleted"
     fi
+  else
+    echo "Operation cancelled"
   fi
 }
 
-function sm { /opt/sublime_merge/sublime_merge $1; }
+# Open Sublime Merge
+function sm {
+  if [[ ! -f /opt/sublime_merge/sublime_merge ]]; then
+    echo "Error: Sublime Merge not found at /opt/sublime_merge/sublime_merge" >&2
+    return 1
+  fi
+  /opt/sublime_merge/sublime_merge "$@"
+}
 
+# Quick access to Neovim config
 function vimrc {
-  cd $XDG_CONFIG_HOME/nvim
+  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 - >/dev/null
+  cd "$original_dir"
 }
 
+# Quick access to Zsh config
 function zshrc {
-  cd $XDG_CONFIG_HOME/zsh
+  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 - >/dev/null
+  cd "$original_dir"
 }
 
-# FILE SHARING AND NETWORKING
-function upload_file() {
-  local usage="Usage: $0 [-o] <file>"
-  local one_time=true
-
-  # Parse options
-  while getopts ":o" opt; do
-    case ${opt} in
-      o ) one_time=false ;;
-      \? )
-        echo "Invalid option: -$OPTARG" >&2
-        echo $usage
-        return 1 ;;
-    esac
-  done
-  shift $((OPTIND -1))
-
-  # Check file argument
+# 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 $usage
+    echo "Error: Port number required" >&2
+    echo "Usage: expose <port>" >&2
     return 1
   fi
-  if [[ ! -f "$1" ]]; then
-    echo "Error: File not found: $1"
+  
+  # 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
-
-  local url="https://drop.mz.uy"
-  echo "Uploading $1 to $url... (one-time: ${one_time})"
-
-  # Prepare upload options
-  local form_data=("-F" "file=@$1")
-  if $one_time; then
-    form_data+=("-F" "one_time=")
-  fi
-
-  # Try up to 3 times with a short delay between attempts
-  local max_attempts=3
-  local attempt=1
-  local success=false
-
-  while (( attempt <= max_attempts )) && ! $success; do
-    if (( attempt > 1 )); then
-      echo "Retry attempt $attempt of $max_attempts..."
-      sleep 1
-    fi
-
-    local full_response=$(curl -i "${form_data[@]}" "$url" 2>/dev/null)
-    local curl_status=$?
-
-    if [[ $curl_status -eq 0 ]]; then
-      local url_response=$(echo "$full_response" | tail -n 1)
-      local token=$(echo "$full_response" | grep -i "X-Token:" | awk '{print $2}' | tr -d '\r')
-
-      if [[ -n "$url_response" ]]; then
-        echo -n "$url_response" | wl-copy
-        echo "✓ Uploaded: $url_response (copied to clipboard)"
-
-        if [[ -n "$token" ]]; then
-          echo "Management token: $token"
-        fi
-
-        success=true
-        break
-      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
-
-    (( attempt++ ))
-  done
-
-  if ! $success; then
-    echo "× Failed to upload file after $max_attempts attempts"
-    return 1
   fi
+  
+  echo "Creating SSH tunnel for port $1..."
+  ssh marianozunino@srv.us -R 1:localhost:"$1"
 }
 
-function expose() {
-  if [ -z "$1" ]; then
-    echo "Usage: expose <port>"
+# 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
-  ssh marianozunino@srv.us -R 1:localhost:$1
-}
-
-function ppid {
-  lsof -i :$1
+  
+  # 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 [ -z "$1" ]; then
+  # Show help if requested
+  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
 
@@ -218,14 +306,23 @@ function kf {
   local cluster="oc-$1-eks-cluster"
   local svc_filter=""
 
-  if [ ! -z "$2" ]; then
+  if [[ -n "$2" ]]; then
     svc_filter="-l app.kubernetes.io/instance=$2"
   fi
 
-  sudo -E kubefwd svc -n ${namespace} -x ${cluster} ${svc_filter}
+  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"
+  sudo -E kubefwd svc -n "${namespace}" -x "${cluster}" ${svc_filter}
 }
 
+# =============================================================================
 # SYSTEM AND UTILITY FUNCTIONS
+# =============================================================================
+
 # Lazy-load handler for heavy tools
 function _lazy_load() {
   local cmd="$1"
@@ -241,102 +338,181 @@ function _lazy_load() {
 # Example: lazy load kubectl completion
 _lazy_load kubectl "kubectl completion zsh"
 
+# Configure Wacom tablet for current session
 function wacom {
-    if [ "$XDG_SESSION_TYPE" = "wayland" ]; then
-        systemctl --user enable opentabletdriver --now
-        otd loadsettings ~/Sync/wacom/wacom.json
+  # 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
-        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 "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 {
-    if [ -n "$SSH_TTY" ] || [ -n "$SSH_CLIENT" ] || [ -n "$SSH_CONNECTION" ]; then
-        bat --plain --paging=never "$@"
-    else
-        bat "$@"
-    fi
+  # 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() {
-    local mirror_mode=false
-
-    # Verificar flags
-    while [[ $# -gt 0 ]]; do
-        case $1 in
-            -m|--mirror)
-                mirror_mode=true
-                shift
-                ;;
-            *)
-                shift
-                ;;
-        esac
-    done
-
-    # Obtener estado actual del monitor interno
-    current_state=$(swaymsg -t get_outputs | jq -r '.[] | select(.name == "eDP-1") | "\(.current_mode.width)x\(.current_mode.height):\(.scale)"')
-
-    # Detectar monitores externos conectados
-    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
+  # 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
 
-    if [[ "$mirror_mode" == true ]] || [[ -n "$external_monitor" ]]; then
-        echo "Switching to mirror mode (1920x1080)..."
+  # 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
 
-        # Configurar monitor interno a 1920x1080
-        swaymsg output eDP-1 resolution 1920x1080@120Hz scale 1.0 pos 0 0
+  # 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)"')
 
-        # Configurar monitor externo si está conectado
-        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 "Monitor interno configurado a 1920x1080 (sin monitor externo detectado)"
-        fi
+  # 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
 
-    elif [[ "$current_state" == "2880x1920:2.0" ]]; then
-        echo "Switching to 1920x1080 (16:9)..."
-        swaymsg output eDP-1 resolution 1920x1080@120Hz scale 1.0
+  if [[ "$mirror_mode" == true ]] || [[ -n "$external_monitor" ]]; then
+    echo "Switching to mirror mode (1920x1080)..."
 
-        # Deshabilitar mirroring si hay monitor externo
-        if [[ -n "$external_monitor" ]]; then
-            swaymsg output "$external_monitor" pos 1920 0
-            echo "Extended mode: $external_monitor positioned to the right"
-        fi
+    # 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 "Switching to 2880x1920 (3:2) native..."
-        swaymsg output eDP-1 resolution 2880x1920@120Hz scale 2.0
-
-        # Deshabilitar mirroring si hay monitor externo
-        if [[ -n "$external_monitor" ]]; then
-            swaymsg output "$external_monitor" pos 1440 0
-            echo "Extended mode: $external_monitor positioned to the right"
-        fi
+      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
 
-    # Mostrar estado final
-    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))"'
+  # 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
+  
   export GTK_THEME=HighContrast
   export GDK_THEME=HighContrast
   export QT_STYLE_OVERRIDE=HighContrast
   export XDG_CURRENT_DESKTOP=GNOME
 
-  # Reiniciar configuración GTK
+  # Reset GTK configuration
   unset GTK2_RC_FILES
   unset GTK_RC_FILES
 
@@ -344,9 +520,26 @@ function cb {
 }
 
 
+# Create a new git repository on remote server
 function zrepo() {
-  if [ -z "$1" ]; then
-    echo "Usage: zrepo <repo>"
+  # 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
 
@@ -354,40 +547,65 @@ function zrepo() {
   local SERVER="git@zvps"
   local PATH_ON_SERVER="/var/git/$REPO.git"
 
-  ssh $SERVER "
+  echo "Creating repository '$REPO' on $SERVER..."
+  
+  ssh "$SERVER" "
     if [ -d $PATH_ON_SERVER ]; then
-      echo 'Error: repo already exists'
+      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
-  " || return 1
+  " || {
+    echo "Failed to create repository" >&2
+    return 1
+  }
 
-  echo "Repo created on $SERVER:$PATH_ON_SERVER"
+      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 repo."
+    echo "Remote 'origin' added to your local repository"
   else
-    echo "Run 'git clone $SERVER:$PATH_ON_SERVER' to clone the repo."
+    echo "To clone this repository, run:"
+    echo "  git clone $SERVER:$PATH_ON_SERVER"
   fi
 }
 
 
 
+# Check if a command exists
 function _has {
-  return $( whence $1 >/dev/null )
+  if [[ $# -eq 0 ]]; then
+    echo "Usage: _has <command>" >&2
+    return 1
+  fi
+  
+  whence "$1" >/dev/null 2>&1
 }
 
-# History-based directory navigation
+# 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
@@ -395,24 +613,19 @@ if [[ -v TMUX ]]; then
   }
 fi
 
-# COMPLETIONS
-for completion_file in ~/.local/share/zsh/*-autocomplete.zsh; do
-    echo $completion_file
-    if [ -f "$completion_file" ]; then
-        source "$completion_file"
-    fi
-done
 
-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 kubefwd &> /dev/null; then eval "$(kubefwd completion zsh)"; fi
-if command -v bombadil &> /dev/null; then eval "$(bombadil generate-completions zsh)"; fi
-if command -v eza &> /dev/null; then compdef eza=ls; fi
+# =============================================================================
+# ALIASES
+# =============================================================================
 
+# Development aliases
 alias dev='~/Dev/marianozunino/dev/dev'
 alias p='_package_manager'
 alias fo='fopen'
-alias drop='upload_file'
-alias dump='upload_file'
-alias pport=ppid
-alias unChonk="echo '🧹 Starting the great node_modules purge...' && find . -name 'node_modules' -type d -prune -exec sh -c 'echo \"💥 Deleting {}\" && rm -rf \"{}\"' \;"
+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 \"{}\"' \;"
+
+
+

+ 51 - 22
zsh/.config/zsh/init.zsh

@@ -1,14 +1,7 @@
 PLUGIN_DIR="$HOME/.local/share/zsh/plugins"
-PLUGIN_LOCK="$PLUGIN_DIR/.plugins.lock"
-[ -d "$PLUGIN_DIR" ] || mkdir -p "$PLUGIN_DIR"
+mkdir -p "$PLUGIN_DIR"
 
-# Reinstall function
-update-plugins() {
-  rm -fr "$PLUGIN_DIR"
-  echo "Plugin lock removed. Restart your shell to reinstall plugins."
-}
-
-# Define plugins: "github_repo name"
+# Install plugins (only if missing)
 plugins=(
   "romkatv/zsh-defer"
   "zsh-users/zsh-autosuggestions"
@@ -21,28 +14,64 @@ plugins=(
   "zsh-users/zsh-syntax-highlighting"
 )
 
-# Only install plugins if lock file doesn't exist
-if [ ! -f "$PLUGIN_LOCK" ]; then
+# Plugin management function
+zap() {
+  echo "⚡ Updating plugins..."
+
+  # Update plugins sequentially (clean output)
   for plugin in "${plugins[@]}"; do
     plugin_name=${plugin##*/}
+    
     if [ ! -d "$PLUGIN_DIR/$plugin_name" ]; then
       echo "Installing $plugin_name"
       git clone --quiet "https://github.com/$plugin" "$PLUGIN_DIR/$plugin_name" --depth=1
+    else
+      old_hash=$(git -C "$PLUGIN_DIR/$plugin_name" rev-parse HEAD 2>/dev/null)
+      
+      git -C "$PLUGIN_DIR/$plugin_name" fetch --quiet
+      git -C "$PLUGIN_DIR/$plugin_name" reset --hard origin/HEAD --quiet
+      
+      new_hash=$(git -C "$PLUGIN_DIR/$plugin_name" rev-parse HEAD 2>/dev/null)
+      
+      if [ "$old_hash" = "$new_hash" ]; then
+        echo "✓ $plugin_name (up to date)"
+      else
+        echo "↑ $plugin_name (${old_hash:0:7} → ${new_hash:0:7})"
+      fi
     fi
   done
-  date > "$PLUGIN_LOCK"
-fi
+  
+  for dir in "$PLUGIN_DIR"/*; do
+    if [ -d "$dir" ]; then
+      plugin_name=$(basename "$dir")
+      if [[ ! " ${plugins[@]##*/} " =~ " $plugin_name " ]]; then
+        echo "Removing unused plugin: $plugin_name"
+        rm -rf "$dir"
+      fi
+    fi
+  done
+  
+  echo "Plugin update complete!"
+}
+
+for plugin in "${plugins[@]}"; do
+  plugin_name=${plugin##*/}
+  [ -d "$PLUGIN_DIR/$plugin_name" ] || git clone --quiet "https://github.com/$plugin" "$PLUGIN_DIR/$plugin_name" --depth=1
+done
 
 # Source plugins
 source "$PLUGIN_DIR/zsh-defer/zsh-defer.plugin.zsh"
-source "$PLUGIN_DIR/zsh-autosuggestions/zsh-autosuggestions.zsh"
-source "$PLUGIN_DIR/zsh-autopair/autopair.zsh"
-source "$PLUGIN_DIR/zsh-history-substring-search/zsh-history-substring-search.zsh"
-source "$PLUGIN_DIR/fzf-tab/fzf-tab.plugin.zsh"
-source "$PLUGIN_DIR/fzf/shell/completion.zsh"
-source "$PLUGIN_DIR/fzf/shell/key-bindings.zsh"
+
+# Defer heavy plugins for faster startup
+zsh-defer source "$PLUGIN_DIR/zsh-autosuggestions/zsh-autosuggestions.zsh"
+zsh-defer source "$PLUGIN_DIR/zsh-autopair/autopair.zsh"
+zsh-defer source "$PLUGIN_DIR/zsh-history-substring-search/zsh-history-substring-search.zsh"
+zsh-defer source "$PLUGIN_DIR/fzf-tab/fzf-tab.plugin.zsh"
+zsh-defer source "$PLUGIN_DIR/fzf/shell/completion.zsh"
+zsh-defer source "$PLUGIN_DIR/fzf/shell/key-bindings.zsh"
+zsh-defer source "$PLUGIN_DIR/vim/vim.plugin.zsh"
+
 source "$PLUGIN_DIR/minimal/minimal.zsh"
-source "$PLUGIN_DIR/vim/vim.plugin.zsh"
 
 # Source config files
 source "$ZDOTDIR/opts.zsh"
@@ -51,6 +80,6 @@ source "$ZDOTDIR/maintenance.zsh"
 
 # Defer loading
 zsh-defer source "$PLUGIN_DIR/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh"
-for config in mise.zsh tmux.zsh functions.zsh alias.zsh keymap.zsh path.zsh pnpm.zsh opts.zsh; do
+for config in mise.zsh tmux.zsh functions.zsh alias.zsh keymap.zsh path.zsh pnpm.zsh; do
   zsh-defer source "$ZDOTDIR/$config"
-done
+done

+ 2 - 3
zsh/.config/zsh/mise.zsh

@@ -1,9 +1,8 @@
 # Source it
 eval "$($HOME/.local/bin/mise activate zsh)"
 
-# Install mise if not present
-if ! command -v mise &> /dev/null
-then
+# Install mise if not present (with caching to avoid repeated checks)
+if ! command -v mise &> /dev/null && [[ ! -f ~/.local/bin/mise ]]; then
 	echo "Installing mise..."
 	mkdir -p ~/.local/bin
 	curl https://mise.jdx.dev/mise-latest-linux-x64 > ~/.local/bin/mise

+ 16 - 0
zsh/.config/zsh/opts.zsh

@@ -13,6 +13,7 @@ setopt HIST_FCNTL_LOCK
 setopt SHARE_HISTORY
 setopt AUTO_CD
 
+# History file configuration - per host
 HISTORY_IGNORE='(*.git/hooks*)'
 LESSHISTFILE="-"
 HISTFILE="$ZDOTDIR/zsh_history_$HOST"
@@ -20,6 +21,21 @@ HISTFILESIZE=100000
 HISTSIZE=100000
 SAVEHIST=100000
 
+# Ensure history file exists and has proper permissions
+if [[ ! -f "$HISTFILE" ]]; then
+    touch "$HISTFILE"
+    chmod 644 "$HISTFILE"  # More permissive permissions
+fi
+
+# Additional history safeguards
+# Backup history on each session start (only if file is significantly large)
+if [[ -f "$HISTFILE" && -w "$HISTFILE" ]]; then
+    # Create backup if history file is large enough (> 10KB) to avoid frequent small backups
+    if [[ $(stat -f%z "$HISTFILE" 2>/dev/null || stat -c%s "$HISTFILE" 2>/dev/null) -gt 10240 ]]; then
+        cp "$HISTFILE" "${HISTFILE}.bak" 2>/dev/null || true
+    fi
+fi
+
 MNML_INFOLN=()
 MNML_PROMPT=(mnml_ssh mnml_status 'mnml_cwd 2 0' mnml_git mnml_keymap )
 MNML_RPROMPT=()

BIN
zsh/.config/zsh/zsh_history_main