From 2a7ebf2a97100748786425a6e9a5127877fcbca8 Mon Sep 17 00:00:00 2001 From: Fabio Scotto di Santolo Date: Fri, 27 Mar 2026 22:07:08 +0100 Subject: [PATCH] Add zoxide and custom case-insensitive cd function to bashrc --- ansible/inventory/group_vars/all.yml | 1 + dotfiles/common/.bashrc | 107 ++++++++++++++++++++++++++- 2 files changed, 107 insertions(+), 1 deletion(-) diff --git a/ansible/inventory/group_vars/all.yml b/ansible/inventory/group_vars/all.yml index d889779..b9c57e2 100644 --- a/ansible/inventory/group_vars/all.yml +++ b/ansible/inventory/group_vars/all.yml @@ -26,6 +26,7 @@ common_packages: - zip - vim - fzf + - zoxide common_dotfiles: - name: .bashrc diff --git a/dotfiles/common/.bashrc b/dotfiles/common/.bashrc index 44c74f9..a1fb18c 100644 --- a/dotfiles/common/.bashrc +++ b/dotfiles/common/.bashrc @@ -33,7 +33,6 @@ __history_sync() { # --- shell options set -o emacs shopt -s cmdhist -shopt -s cdspell # --- PATH [ -d "$HOME/.local/bin" ] && PATH="$HOME/.local/bin:$PATH" @@ -270,6 +269,14 @@ do fi done +# ========================= +# zoxide - smarter cd +# ========================= + +if command -v zoxide >/dev/null 2>&1; then + eval "$(zoxide init bash)" +fi + # ========================= # Portable helpers # ========================= @@ -279,6 +286,104 @@ mkcd() { mkdir -p -- "$1" && cd -- "$1" || return } +__cd_resolve_case_insensitive() { + local target="$1" + local base rest component entry name + local -a parts matches + + if [[ "$target" == /* ]]; then + base="/" + rest=${target#/} + else + base="." + rest=$target + fi + + IFS='/' read -r -a parts <<< "$rest" + + for component in "${parts[@]}"; do + [ -n "$component" ] || continue + + case "$component" in + .|..) + base="$base/$component" + continue + ;; + esac + + matches=() + + if [[ "$component" == .* ]]; then + for entry in "$base"/.*; do + [ -d "$entry" ] || continue + name=${entry##*/} + case "$name" in + .|..) continue ;; + esac + [[ ${name,,} == ${component,,} ]] && matches+=("$entry") + done + else + for entry in "$base"/*; do + [ -d "$entry" ] || continue + name=${entry##*/} + [[ ${name,,} == ${component,,} ]] && matches+=("$entry") + done + fi + + case ${#matches[@]} in + 0) + return 1 + ;; + 1) + base=${matches[0]} + ;; + *) + printf 'cd: ambiguous case-insensitive match for %s\n' "$target" >&2 + printf '%s\n' "${matches[@]}" >&2 + return 2 + ;; + esac + done + + printf '%s\n' "$base" +} + +cd() { + local resolved status + + if builtin cd "$@" 2>/dev/null; then + return 0 + fi + status=$? + + if [ $# -ne 1 ]; then + builtin cd "$@" + return $? + fi + + case "$1" in + ''|-|-*) + builtin cd "$@" + return $? + ;; + esac + + resolved=$(__cd_resolve_case_insensitive "$1") + status=$? + + case $status in + 0) + builtin cd -- "$resolved" + ;; + 2) + return 1 + ;; + *) + builtin cd "$@" + ;; + esac +} + extract() { [ $# -eq 1 ] || { printf 'usage: extract \n' >&2