Files
dotfiles/.config/zsh/autoload/ls-show-hidden

102 lines
3.1 KiB
Bash
Executable File

#!/usr/bin/env zsh
## Author: druckdev
## Created: 2019-10-21
##
## An ls wrapper that adds the -A flag (show hidden files except . and ..) when
## there are no visible files or the directory matches the pattern (POSIX ERE)
## defined in $LS_SHOW_ALL_DIRS.
# Do not include hidden files when globbing and expand to an empty string
# instead of giving an error when no files match.
builtin emulate -L zsh -o no_glob_dots -o null_glob
# Overwrite here or before calling to change the directories in which hidden
# files should always be listed.
builtin local LS_SHOW_ALL_DIRS=${LS_SHOW_ALL_DIRS:-"dotfiles|\.config"}
# ANSI escape codes to print in color
builtin local ansi_bold_red=$'\e[31;1m'
builtin local ansi_reset=$'\e[m'
builtin local LS_COMMAND=ls
# Use GNU version if available under MacOS
if [[ $OSTYPE =~ darwin ]] && (( $+commands[gls] )); then
LS_COMMAND=gls
fi
builtin local non_existing=0 no_flags_from_here=0
builtin local -a dirs files
# Pop files and folders from arguments and put them in the corresponding array,
# keep flags (ls takes flag-arguments behind a '=') and warn when non-existing
# arguments were passed.
for arg in "$@"; do
shift
if [[ $arg = '--' ]] && (( ! no_flags_from_here )); then
no_flags_from_here=1
elif [[ ${arg#-} != $arg ]] && (( ! no_flags_from_here )); then
set -- "$@" "$arg"
elif [[ -d $arg ]]; then
dirs+="$arg"
elif [[ -e $arg || -L $arg ]]; then
files+="$arg"
else
printf >&2 "%s%s: cannot access '%s': No such file or directory%s\n" \
"$ansi_bold_red" "$0" "$arg" "$ansi_reset"
non_existing=1
fi
done
# Print working directory when only flags were given as arguments.
if ! (( $#dirs + $#files + $non_existing )); then
dirs+=.
elif ! (( $#dirs + $#files )); then
return 2
fi
# Just pass everything to ls when the -d flag is given since then the -A flag
# makes no difference.
# Remove all long options because `getopts` cannot handle those and sees for
# example -d in --group-directories-first. Remove the resulting empty strings
# afterwards since that confuses `getopts` apparently.
builtin local -a all_opts empty
all_opts=("$@")
empty=("")
set -- "${(@)${(@)all_opts//--*}:|empty}"
while getopts d flag 2>/dev/null; do
[[ $flag = "d" ]] || continue
command $LS_COMMAND "$all_opts[@]" -- "$files[@]" "$dirs[@]"
return
done
# Restore options.
set -- "$all_opts[@]"
unset all_opts empty
builtin local separator=""
# Print files.
if (( $#files )); then
command $LS_COMMAND "$@" -- "$files[@]"
# Print a newline between files and folder segment.
separator="\n"
fi
# Print directories.
builtin local all_flag
builtin local -a content
for dir in ${(@f)dirs}; do
content=( "$dir"/* )
# If the directory contains no visible files or it matches a pattern, then
# show hidden files when listing
if (( ! $#content )) || [[ ${dir:A} =~ ${LS_SHOW_ALL_DIRS:-^$} ]]; then
all_flag="-A"
else
all_flag=
fi
# If there are multiple items to list, print a newline (if ls was already
# executed) followed by the dir-name.
! (( $#dirs + $#files + $non_existing - 1 )) || echo "$separator$dir:"
# Print directory. $all_flag has to be unquoted else ls will fail.
command $LS_COMMAND "$@" $all_flag -- "$dir"
separator="\n"
done