mirror of
				https://github.com/sharkdp/bat.git
				synced 2025-10-31 15:12:12 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			426 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			Bash
		
	
	
	
		
			Vendored
		
	
	
	
			
		
		
	
	
			426 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			Bash
		
	
	
	
		
			Vendored
		
	
	
	
| #!/usr/bin/env dash
 | |
| 
 | |
| esc() {
 | |
|     case $1 in
 | |
|         # vt100 (IL is vt102) (DECTCEM is vt520)
 | |
|         CUD)     printf '%s[%sB'    "$esc_c" "$2"      ;; # cursor down
 | |
|         CUP)     printf '%s[%s;%sH' "$esc_c" "$2" "$3" ;; # cursor home
 | |
|         CUU)     printf '%s[%sA'    "$esc_c" "$2"      ;; # cursor up
 | |
|         DECAWM)  printf '%s[?7%s'   "$esc_c" "$2"      ;; # line wrap
 | |
|         DECRC)   printf '%s8'       "$esc_c"           ;; # cursor restore
 | |
|         DECSC)   printf '%s7'       "$esc_c"           ;; # cursor save
 | |
|         DECSTBM) printf '%s[%s;%sr' "$esc_c" "$2" "$3" ;; # scroll region
 | |
|         DECTCEM) printf '%s[?25%s'  "$esc_c" "$2"      ;; # cursor visible
 | |
|         ED[0-2]) printf '%s[%sJ'    "$esc_c" "${1#ED}" ;; # clear screen
 | |
|         EL[0-2]) printf '%s[%sK'    "$esc_c" "${1#EL}" ;; # clear line
 | |
|         IL)      printf '%s[%sL'    "$esc_c" "$2"      ;; # insert line
 | |
|         SGR)     printf '%s[%s;%sm' "$esc_c" "$2" "$3" ;; # colors
 | |
| 
 | |
|         # xterm (since 1988, supported widely)
 | |
|         screen_alt) printf '%s[?1049%s' "$esc_c" "$2" ;; # alternate buffer
 | |
|     esac
 | |
| }
 | |
| 
 | |
| term_setup() {
 | |
|     stty=$(stty -g)
 | |
|     stty -icanon -echo
 | |
|     esc screen_alt h
 | |
|     esc DECAWM l
 | |
|     esc DECTCEM l
 | |
|     esc ED2
 | |
|     esc DECSTBM 1 "$((LINES - 2))"
 | |
| }
 | |
| 
 | |
| term_reset() {
 | |
|     esc DECAWM h     >&2
 | |
|     esc DECTCEM h    >&2
 | |
|     esc ED2          >&2
 | |
|     esc DECSTBM      >&2
 | |
|     esc screen_alt l >&2
 | |
|     stty "$stty"
 | |
| 
 | |
|     # needed for cd-on-exit
 | |
|     printf '%s\n' "$PWD" >&1
 | |
| }
 | |
| 
 | |
| term_resize() {
 | |
|     # false-positive, behavior intentional, globbing is disabled.
 | |
|     # shellcheck disable=2046
 | |
|     {
 | |
|         set -f
 | |
|         set +f -- $(stty size)
 | |
|     }
 | |
| 
 | |
|     LINES=$1 COLUMNS=$2
 | |
| 
 | |
|     # space for status_line
 | |
|     bottom=$((LINES - 2))
 | |
| }
 | |
| 
 | |
| term_scroll_down() {
 | |
|     case $((y - $#)) in
 | |
|         [0-9]*) return
 | |
|     esac
 | |
| 
 | |
|     y=$((y + 1))
 | |
|     y2=$((y2 + 1 < bottom ? y2 + 1 : bottom))
 | |
| 
 | |
|     line_print "$((y - 1))" "$@"
 | |
|     printf '\n'
 | |
|     line_print "$y" "$@"
 | |
|     status_line "$#"
 | |
| }
 | |
| 
 | |
| term_scroll_up() {
 | |
|     case $y in
 | |
|         -*|0|1) return
 | |
|     esac
 | |
| 
 | |
|     y=$((y - 1))
 | |
| 
 | |
|     line_print "$((y + 1))" "$@"
 | |
| 
 | |
|     case $y2 in
 | |
|         1) esc IL ;;
 | |
|         *) esc CUU; y2=$((y2 > 1 ? y2 - 1 : 1))
 | |
|     esac
 | |
| 
 | |
|     line_print "$y" "$@"
 | |
|     status_line "$#"
 | |
| }
 | |
| 
 | |
| cmd_run() {
 | |
|     stty "$stty"
 | |
|     esc DECTCEM h
 | |
|     esc DECSTBM
 | |
|     esc ED2
 | |
|     "$@" ||:
 | |
|     esc DECSTBM 1 "$((LINES - 2))"
 | |
|     esc DECTCEM l
 | |
|     stty -icanon -echo
 | |
|     hist=2
 | |
| }
 | |
| 
 | |
| file_escape() {
 | |
|     tmp=$1 safe=
 | |
| 
 | |
|     # loop over string char by char
 | |
|     while c=${tmp%"${tmp#?}"}; do
 | |
|         case $c in
 | |
|             '')          return ;;
 | |
|             [[:cntrl:]]) safe=$safe\? ;;
 | |
|             *)           safe=$safe$c ;;
 | |
|         esac
 | |
| 
 | |
|         tmp=${tmp#?}
 | |
|     done
 | |
| }
 | |
| 
 | |
| hist_search() {
 | |
|     hist=0 j=1
 | |
| 
 | |
|     for file do
 | |
|         case ${PWD%%/}/$file in
 | |
|             "$old_pwd") y=$j y2=$((j > bottom ? mid : j)) cur=$file
 | |
|         esac
 | |
| 
 | |
|         j=$((j + 1))
 | |
|     done
 | |
| }
 | |
| 
 | |
| list_print() {
 | |
|     esc ED2
 | |
|     esc CUP
 | |
| 
 | |
|     i=1
 | |
|     end=$((bottom + 1))
 | |
|     mid=$((bottom / 4 < 5 ? 1 : bottom / 4))
 | |
| 
 | |
|     case $# in
 | |
|         1) [ -e "$1" ] || set -- empty
 | |
|     esac
 | |
| 
 | |
|     case $hist in
 | |
|         2) # redraw after cmd run
 | |
|             shift "$((y > y2 ? y - y2 : 0))"
 | |
|         ;;
 | |
| 
 | |
|         1) # redraw after go-to-parent
 | |
|             hist_search "$@"
 | |
|             shift "$((y >= bottom ? y - mid : 0))"
 | |
|         ;;
 | |
| 
 | |
|         *) # everything else
 | |
|             shift "$((y >= bottom ? y - bottom : 0))"
 | |
|         ;;
 | |
|     esac
 | |
| 
 | |
|     for file do
 | |
|         case $i in
 | |
|             "$y2") esc SGR 0 7
 | |
|         esac
 | |
| 
 | |
|         case $((i - end)) in
 | |
|             -*)
 | |
|                 line_format "$file"
 | |
|                 esc CUD
 | |
|             ;;
 | |
|         esac
 | |
| 
 | |
|         i=$((i + 1))
 | |
|     done
 | |
| 
 | |
|     esc CUP "$((y > y2 ? y2 : y))"
 | |
| }
 | |
| 
 | |
| redraw() {
 | |
|     list_print "$@"
 | |
|     status_line "$#"
 | |
| }
 | |
| 
 | |
| status_line() {
 | |
|     esc DECSC
 | |
|     esc CUP "$LINES"
 | |
| 
 | |
|     case $USER in
 | |
|         root) esc SGR 31 7 ;;
 | |
|            *) esc SGR 34 7 ;;
 | |
|     esac
 | |
| 
 | |
|     printf '%*s\r%s ' "$COLUMNS" "" "($y/$1)"
 | |
| 
 | |
|     case $ltype in
 | |
|         '') printf %s "$PWD" ;;
 | |
|          *) printf %s "$ltype"
 | |
|     esac
 | |
| 
 | |
|     esc SGR 0 0
 | |
|     esc DECRC
 | |
| }
 | |
| 
 | |
| prompt() {
 | |
|     esc DECSC
 | |
|     esc CUP "$LINES"
 | |
|     printf %s "$1"
 | |
|     esc DECTCEM h
 | |
|     esc EL0
 | |
| 
 | |
|     case $2 in
 | |
|         r)
 | |
|             stty icanon echo
 | |
|             read -r ans ||:
 | |
|             stty -icanon -echo
 | |
|         ;;
 | |
|     esac
 | |
| 
 | |
|     esc DECRC
 | |
|     esc DECTCEM l
 | |
|     status_line "($y/$#) $PWD"
 | |
| }
 | |
| 
 | |
| line_print() {
 | |
|     offset=$1
 | |
| 
 | |
|     case $offset in
 | |
|         "$y") esc SGR 0 7
 | |
|     esac
 | |
| 
 | |
|     shift "$offset"
 | |
| 
 | |
|     case $offset in
 | |
|         "$y") cur=$1
 | |
|     esac
 | |
| 
 | |
|     line_format "$1"
 | |
| }
 | |
| 
 | |
| line_format() {
 | |
|     file_escape "$1"
 | |
|     [ -d "$1" ] && esc SGR 1 31
 | |
|     printf %s "$safe"
 | |
|     [ -d "$1" ] && printf /
 | |
|     esc SGR 0 0
 | |
|     esc EL0
 | |
|     printf '\r'
 | |
| }
 | |
| 
 | |
| main() {
 | |
|     set -e
 | |
| 
 | |
|     case $1 in
 | |
|         -h|--help)
 | |
|             printf 'shfm -[hv] <starting dir>\n'
 | |
|             exit 0
 | |
|         ;;
 | |
| 
 | |
|         -v|--version)
 | |
|             printf 'shfm 0.4.2\n'
 | |
|             exit 0
 | |
|         ;;
 | |
| 
 | |
|         *)
 | |
|             cd -- "${1:-"$PWD"}"
 | |
|         ;;
 | |
|     esac
 | |
| 
 | |
|     esc_c=$(printf '\033')
 | |
|     bs_char=$(printf '\177')
 | |
| 
 | |
|     set -- *
 | |
|     cur=$1
 | |
| 
 | |
|     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)
 | |
|                 term_scroll_up "$@"
 | |
|             ;;
 | |
| 
 | |
|             j?|B2)
 | |
|                 term_scroll_down "$@"
 | |
|             ;;
 | |
| 
 | |
|             l?|C2|"$esc") # ARROW RIGHT
 | |
|                 if [ -d "$cur" ] && cd -- "$cur" >/dev/null 2>&1; then
 | |
|                     set -- *
 | |
|                     y=1 y2=1 cur=$1 ltype=
 | |
|                     redraw "$@"
 | |
| 
 | |
|                 elif [ -e "$cur" ]; then
 | |
|                     cmd_run "${SHFM_OPENER:="${EDITOR:=vi}"}" "$cur"
 | |
|                     redraw "$@"
 | |
|                 fi
 | |
|             ;;
 | |
| 
 | |
|             h?|D2|"$bs_char"?) # ARROW LEFT
 | |
|                 old_pwd=$PWD
 | |
| 
 | |
|                 case $ltype in
 | |
|                     '') cd .. || continue ;;
 | |
|                      *) ltype= ;;
 | |
|                 esac
 | |
| 
 | |
|                 set -- *
 | |
|                 y=1 y2=1 cur=$1 hist=1
 | |
|                 redraw "$@"
 | |
|             ;;
 | |
| 
 | |
|             g?)
 | |
|                 case $y in
 | |
|                     1) continue
 | |
|                 esac
 | |
| 
 | |
|                 y=1 y2=1 cur=$1
 | |
|                 redraw "$@"
 | |
|             ;;
 | |
| 
 | |
|             G?)
 | |
|                 y=$#
 | |
|                 y2=$(($# < bottom ? $# : bottom))
 | |
|                 redraw "$@"
 | |
|             ;;
 | |
| 
 | |
|             .?)
 | |
|                 case ${hidden:=1} in
 | |
|                     1) hidden=0; set -- .* ;;
 | |
|                     0) hidden=1; set -- *
 | |
|                 esac
 | |
| 
 | |
|                 y=1 y2=1 cur=$1
 | |
|                 redraw "$@"
 | |
|             ;;
 | |
| 
 | |
|             :?)
 | |
|                 prompt "cd: " r
 | |
| 
 | |
|                 # false positive, behavior intentional
 | |
|                 # shellcheck disable=2088
 | |
|                 case $ans in
 | |
|                     '~')   ans=$HOME ;;
 | |
|                     '~/'*) ans=$HOME/${ans#"~/"}
 | |
|                 esac
 | |
| 
 | |
|                 cd -- "${ans:="$0"}" >/dev/null 2>&1|| continue
 | |
|                 set -- *
 | |
|                 y=1 y2=1 cur=$1
 | |
|                 redraw "$@"
 | |
|             ;;
 | |
| 
 | |
|             /?)
 | |
|                 prompt / r
 | |
| 
 | |
|                 # word splitting and globbing intentional
 | |
|                 # shellcheck disable=2086
 | |
|                 set -- $ans*
 | |
| 
 | |
|                 case $1$# in
 | |
|                     "$ans*1") set -- 'no results'
 | |
|                 esac
 | |
| 
 | |
|                 y=1 y2=1 cur=$1 ltype="search $PWD/$ans*"
 | |
|                 redraw "$@"
 | |
|                 status_line "$#"
 | |
|             ;;
 | |
| 
 | |
|             -?)
 | |
|                 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))
 | |
|                 cmd_run "${SHELL:=/bin/sh}"
 | |
|                 redraw "$@"
 | |
|             ;;
 | |
| 
 | |
|             \??)
 | |
|                 set -- 'j - down' \
 | |
|                        'k - up' \
 | |
|                        'l - open file or directory' \
 | |
|                        'h - go up level' \
 | |
|                        'g - go to top' \
 | |
|                        'G - go to bottom' \
 | |
|                        'q - quit' \
 | |
|                        ': - cd to <input>' \
 | |
|                        '/ - search current directory <input>*' \
 | |
|                        '- - go to last directory' \
 | |
|                        '~ - go home' \
 | |
|                        '! - spawn shell' \
 | |
|                        '. - toggle hidden files' \
 | |
|                        '? - show keybinds'
 | |
| 
 | |
|                 y=1 y2=1 cur=$1 ltype=keybinds
 | |
|                 redraw "$@"
 | |
|                 status_line "$#"
 | |
|             ;;
 | |
| 
 | |
|             q?) exit 0 ;;
 | |
| 
 | |
|             # handle keys which emit escape sequences
 | |
|             "$esc_c"*) esc=1 ;;
 | |
|                  '[1') esc=2 ;;
 | |
|                     *) esc=0 ;;
 | |
|         esac
 | |
|     done
 | |
| }
 | |
| 
 | |
| main "$@" >/dev/tty
 |