diff --git a/zsh/.config/zsh/.zshrc b/zsh/.config/zsh/.zshrc index 1edae66..6de6ce8 100644 --- a/zsh/.config/zsh/.zshrc +++ b/zsh/.config/zsh/.zshrc @@ -9,4 +9,4 @@ else fi # Load completion registrations -source $ZDOTDIR/completions.zsh +source $ZDOTDIR/completions/external.zsh diff --git a/zsh/.config/zsh/completions.zsh b/zsh/.config/zsh/completions.zsh deleted file mode 100644 index 0790d69..0000000 --- a/zsh/.config/zsh/completions.zsh +++ /dev/null @@ -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 \ No newline at end of file diff --git a/zsh/.config/zsh/completions/external.zsh b/zsh/.config/zsh/completions/external.zsh new file mode 100644 index 0000000..60d412f --- /dev/null +++ b/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" diff --git a/zsh/.config/zsh/functions.zsh b/zsh/.config/zsh/functions.zsh deleted file mode 100644 index a4f2392..0000000 --- a/zsh/.config/zsh/functions.zsh +++ /dev/null @@ -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 [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 " - 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 " >&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 " - 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 " >&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 [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 [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 [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 [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 " - 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 " >&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 " >&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 "; 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 "; return 1; } - echo "Installing $2..." - nix-env -iA nixpkgs.$2 - ;; - - # Remove package - remove|"-R") - [ -z "$2" ] && { echo "Usage: yay remove "; 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 [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 Search packages - yay install Install package (user) - yay remove Remove package - yay list List installed packages - yay shell 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" -} diff --git a/zsh/.config/zsh/functions/dev.zsh b/zsh/.config/zsh/functions/dev.zsh new file mode 100644 index 0000000..cf9f743 --- /dev/null +++ b/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 "; 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 "; return 1; } + echo "Installing $2..." + nix-env -iA nixpkgs.$2 + ;; + + remove|"-R") + [ -z "$2" ] && { echo "Usage: yay remove "; 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 [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 Search packages + yay install Install package (user) + yay remove Remove package + yay list List installed packages + yay shell 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 diff --git a/zsh/.config/zsh/functions/git.zsh b/zsh/.config/zsh/functions/git.zsh new file mode 100644 index 0000000..8c096b2 --- /dev/null +++ b/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 " + 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 " >&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 diff --git a/zsh/.config/zsh/functions/k8s.zsh b/zsh/.config/zsh/functions/k8s.zsh new file mode 100644 index 0000000..417cff7 --- /dev/null +++ b/zsh/.config/zsh/functions/k8s.zsh @@ -0,0 +1,126 @@ +#!/bin/zsh + +function kf { + if [[ "$1" == "-h" || "$1" == "--help" ]]; then + echo "Usage: kf [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 [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 diff --git a/zsh/.config/zsh/functions/navigation.zsh b/zsh/.config/zsh/functions/navigation.zsh new file mode 100644 index 0000000..9f33086 --- /dev/null +++ b/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 [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 & +} diff --git a/zsh/.config/zsh/functions/stow.zsh b/zsh/.config/zsh/functions/stow.zsh new file mode 100644 index 0000000..aefcc20 --- /dev/null +++ b/zsh/.config/zsh/functions/stow.zsh @@ -0,0 +1,144 @@ +#!/bin/zsh + +function stowify() { + if [[ "$1" == "-h" || "$1" == "--help" ]]; then + echo "Usage: stowify [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 [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 diff --git a/zsh/.config/zsh/functions/system.zsh b/zsh/.config/zsh/functions/system.zsh new file mode 100644 index 0000000..a83416b --- /dev/null +++ b/zsh/.config/zsh/functions/system.zsh @@ -0,0 +1,269 @@ +#!/bin/zsh + +function expose() { + if [[ "$1" == "-h" || "$1" == "--help" ]]; then + echo "Usage: expose " + 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 " >&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 " + 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 " >&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 " >&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 diff --git a/zsh/.config/zsh/functions/utils.zsh b/zsh/.config/zsh/functions/utils.zsh new file mode 100644 index 0000000..3295927 --- /dev/null +++ b/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' diff --git a/zsh/.config/zsh/init.zsh b/zsh/.config/zsh/init.zsh index 009297f..af8490c 100644 --- a/zsh/.config/zsh/init.zsh +++ b/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 diff --git a/zsh/.config/zsh/zsh_history_main b/zsh/.config/zsh/zsh_history_main index 7027593..7cb803f 100644 Binary files a/zsh/.config/zsh/zsh_history_main and b/zsh/.config/zsh/zsh_history_main differ diff --git a/zsh/.zshenv b/zsh/.zshenv index ac87eee..a061945 100644 --- a/zsh/.zshenv +++ b/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" +