dotfiles/zsh/.config/zsh/functions.zsh

954 lines
26 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/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"
}