102 lines
3.1 KiB
Bash
Executable File
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
|