Files
dotfiles/.config/zsh/autoload/ls-show-hidden
druckdev 4d1b540778 zsh:ls-show-hidden: Bug fixes around -d flag
Fix behavior to match ls's when the -d flag but no files or directories
were passed.

Fix bug that the function thinks -d is passed when a long option that
contains a 'd' (as --group-directories-first) is specified and thus
just emulates plain `ls` in that case.
2020-11-02 17:46:26 +01:00

83 lines
2.4 KiB
Bash
Executable File

## 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"}
builtin local -a dirs files
# Pop files and folders from arguments and put them in the corresponding array.
# All other arguments are kept.
for arg in "$@"; do
shift
if [[ -d "$arg" ]]; then
dirs+="$arg"
elif [[ -e "$arg" ]]; then
files+="$arg"
else
set -- "$@" "$arg"
fi
done
# Print working directory when only flags were given as arguments.
if ! (( ${#dirs} + ${#files} )); then
dirs+=.
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 "${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 "$@" -- "${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} - 1 )) || echo "$separator$dir:"
# Print directory. $all_flag has to be unquoted else ls will fail.
command ls "$@" $all_flag -- "$dir"
separator="\n"
done
# vim: ft=zsh