#!/bin/sh term_setup() { stty=$(stty -g) stty -icanon -echo printf '\033[?1049h\033[?7l\033[?25l\033[2J\033[1;%sr' \ "$((LINES - 2))" } term_reset() { stty "$stty" printf '\033[?7h\033[?25h\033[2J\033[;r\033[?1049l' } term_resize() { set -f set +f -- $(stty size) LINES=$1 COLUMNS=$2 # space for status_line bottom=$((LINES - 2)) } hist_search() { hist=0 j=1 for file do case ${PWD%%/}/$file in "$old_pwd") y=$j y2=$((j > bottom ? bottom : j)) esac j=$((j + 1)) done } list_print() { printf '\033[2J\033[H' i=1 end=$((bottom + 1)) case $hist in 1) hist_search "$@" esac case $((y - bottom)) in [0-9]*) shift "$((y - bottom))" esac for file do case $i in "$y2") printf '\033[31;7m' esac case $((i - end)) in -*) printf '%s\033[m\033[B\r' "$file" esac i=$((i + 1)) done printf '\033[%sH' "$((y > bottom ? bottom : y))" } redraw() { list_print "$@" status_line "($y/$#) $PWD" } status_line() { printf '\0337\033[%sH\033[31;7m%-*s\033[m\0338' \ "$LINES" "$COLUMNS" "$1" } prompt() { printf '\0337\033[%sH%s\033[?25h' "$LINES" "$1" case $2 in r) stty icanon echo read -r ans ||: stty -icanon -echo ;; esac printf '\0338\033[?25l' status_line "($y/$#) $PWD" } print_line() { offset=$1 case $offset in "$y") printf '\033[31;7m' esac shift "$offset" printf '\033[K%s\033[m\r' "$1" case $offset in "$y") cur=$1 esac } main() { set -e esc_char=$(printf '\033') bs_char=$(printf '\177') cd "${1:-"$PWD"}" set -- * term_resize term_setup trap 'term_reset' EXIT INT trap 'term_resize; term_setup; y=1 y2=1; redraw "$@"' WINCH y=1 y2=1 redraw "$@" while key=$(dd ibs=1 count=1 2>/dev/null); do case $key${esc:=0} in k?|A2) # ARROW UP case $y in -*|0|1) ;; *) y=$((y - 1)) print_line "$((y + 1))" "$@" case $y2 in 1) printf '\033[L' ;; *) printf '\033[A' y2=$((y2 > 1 ? y2 - 1 : 1)) ;; esac print_line "$y" "$@" status_line "($y/$#) $PWD" ;; esac ;; j?|B2) # ARROW DOWN case $((y - $#)) in -*) y=$((y + 1)) y2=$((y2 + 1 < bottom ? y2 + 1 : bottom)) print_line "$((y - 1))" "$@" printf '\n' print_line "$y" "$@" status_line "($y/$#) $PWD" ;; esac ;; l?|C2|"$esc") # ARROW RIGHT if cd "$cur"; then set -- * y=1 y2=1 else printf '\033[?25h' "${SHFM_OPENER:="${EDITOR:=vi}"}" "$cur" printf '\033[?25l' fi redraw "$@" ;; h?|D2|"$bs_char"?) # ARROW LEFT old_pwd=$PWD case $search in 1) search=0 ;; *) cd .. || continue ;; esac set -- * y=1 y2=1 cur=$1 hist=1 redraw "$@" ;; g?) y=1 y2=1 cur=$1 redraw "$@" ;; G?) y=$# y2=$(($# < bottom ? $# : bottom)) redraw "$@" ;; .?) case ${hidden:=1} in 1) hidden=0 set -- .[!.]* ;; *) hidden=1 set -- * ;; esac y=1 y2=1 cur=$1 redraw "$@" ;; :?) prompt "cd: " r cd "${ans:="$0"}" >/dev/null 2>&1|| continue set -- * y=1 y2=1 cur=$1 redraw "$@" ;; /?) prompt / r set -- *"$ans"* y=1 y2=1 cur=$1 search=1 redraw "$@" status_line "($y/$#) search $ans" ;; -?) cd "$OLDPWD" >/dev/null 2>&1|| continue set -- * y=1 y2=1 cur=$1 redraw "$@" ;; \~?) cd || continue set -- * y=1 y2=1 cur=$1 redraw "$@" ;; \!?) export SHFM_LEVEL SHFM_LEVEL=$((SHFM_LEVEL + 1)) term_reset "${SHELL:=/bin/sh}" term_setup redraw "$@" ;; q?) exit 0 ;; # handle keys which emit escape sequences "$esc_char"*) esc=1 ;; '[1') esc=2 ;; *) esc=0 ;; esac done } main "$@"