# Utilities for file system navigation # Useful when the current directory was recreated alias recd='cd $PWD' # [c]hange [d]irectory [e]xisting - cd into the first existing directory cde() { local _dir="$1" while ! test -d "$_dir" do _dir="$(dirname "$_dir")" done cd "$_dir" "${@:2}" } # Go up a number of dirs up() { if [[ $# < 1 ]] ; then cd .. else CDSTR="" for i in {1..$1} ; do CDSTR="../$CDSTR" done cd $CDSTR fi } # Switch directory & ls cl() { builtin cd $1 ls --almost-all --group-directories-first --file-type } # cd but search for data dirs and run ls after switching to target dir cd() { if test -d "$DATA" && test "${1:--}" != "-" -a ! -d "$1" -a $# -eq 1 then dir=$(fd --no-ignore --glob "$1*" "$DATA" --maxdepth 2 --type d --max-results 1 2>/dev/null) test -n "$dir" && cd "$dir" else builtin cd "$@" && # we have to use two ls commands here, since: # - a single ls command hangs on multi-column formats when combined with color # - column malaligns output with ANSI escape sequences (view with LESS="" less) # column --fillrows --output-width $(expr $COLUMNS + 20) # pr -4 -l1 -W $COLUMNS -S" " command ls --sort=none --quote-name | head -12 | xargs ls --sort=time --format=vertical --directory --literal --classify --color=always --width $COLUMNS | head -3 code=$? && test $code -eq 141 || return $code fi } # LOCATE {{{1 # TODO no double heading with bat alias fselect='fzf -0 -1 --reverse --height=40% --keep-right | while read f; do test -d "$f" && cd "$f" || { highlight "$f" && print -s b \"$f\" && b "$f"; }; done'; loci() { locate --all --ignore-case --basename --existing "$@" | command grep --extended-regexp --ignore-case --color=always $(echo "$|${@:$#}" | sed 's/ /|/g') | fselect } alias loc='noglob loci' alias uloc='noglob sudo updatedb && loci' # locate exactly locei() { locate --all --basename "\\$1" "$@" | fselect } alias loce='noglob locei' # locate all alias loca='noglob sudo updatedb -l 0 --prunenames "" --prunefs "tmpfs sysfs debugfs" --prunepaths "" -o /var/cache/locate-all.db && sudo chmod +r /var/cache/locate-all.db && loci --database /var/cache/locate-all.db' hunta() { unbuffer hunt -h "$@" / | less -RF +G } # ZOXIDE {{{1 alias c=z # Listing for quick directory switcher based on zoxide and fzf alias zoxide-list='noglob zoxide query -sl' __zx_ls="ls --almost-all --color --human-readable --group-directories-first --file-type" alias fzf-dir="fzf -0 -1 --tiebreak=index \ --preview-window=30% --preview='$__zx_ls {}' \ --height=80% --reverse --keep-right" # fzf for zoxide - returns the selected path stripped of its score zoxide-fzf() { fzf-dir -n2.. --preview="$__zx_ls {2..}" "$@" | sed 's|.* /|/|' } # Locate directories and add 0 zoxide score locate-zox() { locate --basename --ignore-case "$@" | # TODO too slow # while read -r file; do test -d "$file" && echo "$file"; done | sed 's/^/ 0 /' } # Switch directory heuristically using zoxide and locate d() { test "$1" != "-" -a ! -d "$1" -a $# -eq 1 || { cd "$@" && return; } local query="$(zoxide-list "$@")" # First find out whether there is an obvious match # (score at least ten times above runner-up and score above 20) # which is not the current directory # If not select with fzf, using locate to find extra options target="$(if test -n "$query" && expr "$(echo "$query" | sed 's| \+\([^ ]\+\).*|\1|;q')" \> 20 \& \ $(echo "$query" | sed 'N;s|/.* \([0-9]\+\)|> 10 * \1|;q' | sed 's| */.*||') >/dev/null && [[ ! "$(echo "$query" | head -1)" =~ ".*$PWD" ]] then echo "$query" | head -1 else test -n "$query" && echo "$query"; locate-zox "$@" fi | zoxide-fzf)" test $? -lt 2 && test -z "$target" && sudo updatedb && target="$(locate --basename "$@" | fzf-dir)" test -n "$target" && cde "$target" } # Switch directory interactively using zoxide and locate di() { test "$1" = "-" || local dir=$({ zoxide-list "$@"; locate-zox "$@" } | zoxide-fzf) cd "${dir:-$1}" }