148 lines
5.7 KiB
Bash
148 lines
5.7 KiB
Bash
#!/usr/bin/env zsh
|
|
|
|
eval "$_z4h_opt"
|
|
setopt octalzeroes
|
|
|
|
local -i list_colors=$1
|
|
local -i list_types=$2
|
|
local -i tilde_unexpand=$3
|
|
|
|
[[ $_z4h_mode_colors[ln] != target ]]
|
|
local -i ln_target=$?
|
|
|
|
local -r nil=$'\0'
|
|
local -r or=$_z4h_mode_colors[or]
|
|
local -r ln=$_z4h_mode_colors[ln]
|
|
local -r suf=('|' '|' '' '' '' '' '/' '/' '' '' '' '' '' '' '' '*' '' '' '@' '@' '' '' '=' '=')
|
|
|
|
local -i10 m i
|
|
local buf file style
|
|
local -a files modes link link_mode
|
|
local -i MATCH
|
|
local MBEGIN MEND
|
|
|
|
while true; do
|
|
while [[ $buf != *$'\n'* ]]; do
|
|
sysread -s 4096 'buf[$#buf+1]' && continue
|
|
(( $? == 5 )) || return
|
|
return
|
|
done
|
|
|
|
files=("${(@f)buf}")
|
|
buf=$files[-1]
|
|
files[-1]=()
|
|
|
|
if (( ! list_colors && ! list_types && ! tilde_unexpand )) || ! zstat -L -A modes +mode -- $files; then
|
|
printf '%1$s\0%1$q\n' $files
|
|
continue
|
|
fi
|
|
|
|
if (( ! list_colors && ! tilde_unexpand )); then
|
|
printf '%2$s\0%2$q%1$s\n' \
|
|
${"${(@)modes/(#m)*/$suf[$((((MATCH & 61440) >> 11) | !(MATCH & 73)))]}":^files}
|
|
continue
|
|
fi
|
|
|
|
# This doesn't work the same way as GNU ls. See get_color_indicator in
|
|
# https://git.savannah.gnu.org/cgit/coreutils.git/tree/src/ls.c.
|
|
#
|
|
# TODO: fix it.
|
|
# TODO: see if this can be made faster by invoking `find` with `-printf '%Y\0%m\0%P\n'`,
|
|
# invoking `zstat -A links +link -- ${files*$'\0'*$'\0'}` and then applying some kind of
|
|
# crazy expansion.
|
|
#
|
|
# Types:
|
|
#
|
|
# ? unknown
|
|
# p fifo
|
|
# c chardev
|
|
# d directory
|
|
# b blockdev
|
|
# - normal
|
|
# s socket
|
|
# w whiteout
|
|
# l symlink (good)
|
|
# L symlink (loop)
|
|
# N symlink (nonexistent)
|
|
|
|
if (( tilde_unexpand )); then
|
|
# This implementation is the same as below except that $file in the second output field
|
|
# is replaced with ${(D)file}.
|
|
for file m in ${files:^modes}; do
|
|
if [[ ${style::=${${_z4h_mode_codes[$((m & 64075))]:-$'\0'}/%$'\0'/$'\0'$_z4h_name_colors[(ke)$file:t]}} \
|
|
== $'@\0.' ]]; then
|
|
if ! zstat -L -A link +link -- $file; then
|
|
printf '%1$s\0\e[%2$sm%3$s\e[0m\n' $file "${or:-$_z4h_name_colors[$file:t]}" ${(D)file}
|
|
elif ! zstat -A link_mode +mode -- $file; then
|
|
printf '%1$s\0\e[%2$sm%5$s\e[0m -> \e[%4$sm%3$q\e[0m\n' \
|
|
$file "${or:-$_z4h_name_colors[$file:t]}" \
|
|
$link "${or:-$_z4h_name_colors[$link:t]}" \
|
|
${(D)file}
|
|
elif (( ln_target )); then
|
|
printf '%1$s\0\e[%4$sm%5$s\e[0m -> \e[%4$sm%2$q\e[0m%3$s\n' \
|
|
$file $link \
|
|
"${(@0)${${_z4h_mode_codes[$((link_mode & 64075))]:-$nil}/%$nil/$nil$_z4h_name_colors[(ke)$link:t]}}" \
|
|
${(D)file}
|
|
else
|
|
printf '%1$s\0\e[%3$sm%6$s\e[0m -> \e[%5$sm%2$q\e[0m%4$s\n' \
|
|
$file $link "${ln:-$_z4h_name_colors[$link:t]}" \
|
|
"${(@0)${${_z4h_mode_codes[$((link_mode & 64075))]:-$nil}/%$nil/$nil$_z4h_name_colors[(ke)$link:t]}}" \
|
|
${(D)file}
|
|
fi
|
|
else
|
|
printf '%1$s\0\e[%3$sm%4$s\e[0m%2$s\n' $file "${(@0)style}" ${(D)file}
|
|
fi
|
|
done
|
|
elif (( $#_z4h_name_colors )); then
|
|
# This implementation works whether _z4h_name_colors is empty or not. It's about 30%
|
|
# slower than the alternative implementation below, which only works if _z4h_name_colors
|
|
# is empty.
|
|
for file m in ${files:^modes}; do
|
|
if [[ ${style::=${${_z4h_mode_codes[$((m & 64075))]:-$'\0'}/%$'\0'/$'\0'$_z4h_name_colors[(ke)$file:t]}} \
|
|
== $'@\0.' ]]; then
|
|
if ! zstat -L -A link +link -- $file; then
|
|
printf '%1$s\0\e[%2$sm%1$q\e[0m\n' $file "${or:-$_z4h_name_colors[$file:t]}"
|
|
elif ! zstat -A link_mode +mode -- $file; then
|
|
printf '%1$s\0\e[%2$sm%1$q\e[0m -> \e[%4$sm%3$q\e[0m\n' \
|
|
$file "${or:-$_z4h_name_colors[$file:t]}" \
|
|
$link "${or:-$_z4h_name_colors[$link:t]}"
|
|
elif (( ln_target )); then
|
|
printf '%1$s\0\e[%4$sm%1$q\e[0m -> \e[%4$sm%2$q\e[0m%3$s\n' \
|
|
$file $link \
|
|
"${(@0)${${_z4h_mode_codes[$((link_mode & 64075))]:-$nil}/%$nil/$nil$_z4h_name_colors[(ke)$link:t]}}"
|
|
else
|
|
printf '%1$s\0\e[%3$sm%1$q\e[0m -> \e[%5$sm%2$q\e[0m%4$s\n' \
|
|
$file $link "${ln:-$_z4h_name_colors[$link:t]}" \
|
|
"${(@0)${${_z4h_mode_codes[$((link_mode & 64075))]:-$nil}/%$nil/$nil$_z4h_name_colors[(ke)$link:t]}}"
|
|
fi
|
|
else
|
|
printf '%1$s\0\e[%3$sm%1$q\e[0m%2$s\n' $file "${(@0)style}"
|
|
fi
|
|
done
|
|
else
|
|
modes=("${(@)modes:/(#m)*/${_z4h_mode_codes[$((MATCH & 64075))]:-$nil}}")
|
|
while true; do
|
|
i=${modes[(i)@*]}
|
|
if (( i == $#modes + 1 )); then
|
|
printf '%3$s\0\e[%2$sm%3$q\e[0m%1$s\n' "${(@0)${(@)modes:^files}}"
|
|
break
|
|
elif (( i != 1 )); then
|
|
printf '%3$s\0\e[%2$sm%3$q\e[0m%1$s\n' "${(@0)${(@)modes[1,i-1]:^files}}"
|
|
shift $((i-1)) modes files
|
|
fi
|
|
file=$files[1]
|
|
shift modes files
|
|
if ! zstat -L -A link +link -- $file; then
|
|
printf '%1$s\0\e['$or'm%1$q\e[0m\n' $file
|
|
elif ! zstat -A link_mode +mode -- $file; then
|
|
printf '%1$s\0\e['$or'm%1$q\e[0m -> \e['$or'm%2$q\e[0m\n' $file $link
|
|
elif (( ln_target )); then
|
|
printf '%1$s\0\e[%4$sm%1$q\e[0m -> \e[%4$sm%2$q\e[0m%3$s\n' \
|
|
$file $link "${(@0)${_z4h_mode_codes[$((link_mode & 64075))]:-$nil}}"
|
|
else
|
|
printf '%1$s\0\e['$ln'm%1$q\e[0m -> \e[%4$sm%2$q\e[0m%3$s\n' \
|
|
$file $link "${(@0)${_z4h_mode_codes[$((link_mode & 64075))]:-$nil}}"
|
|
fi
|
|
done
|
|
fi
|
|
done
|