#!/bin/bash --noprofile # DO ALMOST ANYTHING PUBLIC LICENSE # Everyone is permitted to copy and distribute verbatim or modified # copies of this code for any purpose as long as any "Credit" # lines are not removed. #Credit: /u/linuxversion # #extra strict flags set -euo pipefail #so I don't accidently forget whats builtin and whats not PATH='' #configuration options declare -i cfg_line_numbers=1 #globals declare -a file_map declare -i file_offset=0 declare -i file_lines=0 declare -i term_height=0 declare -i term_width=0 declare -i textarea_height=0 declare -i textarea_line=0 declare -i command_line=0 #move the cursor to a specific row and colunm function put_cursor() { echo -en "\e[${1};${2}f" } #basically the same as the libncurses function of the same name function mvprintw() { local row="$1"; shift local col="$1"; shift printf "%s%s%s" $'\x1b[' "${row};${col}f" "$@" } #self-explanitory function clear_screen() { echo -en '\e[2J' } #erase text from command line to bottom of screen function clear_command_line() { mvprintw "$command_line" 0 $'\x1b[J' } function init_screen() { #set terminal configuration to default #echo -en '\ec' #get the size of the terminal put_cursor 999 999 echo -en '\e[6n' read -s -r -d'[' read -s -r -d';' term_height read -s -r -d'R' term_width #do some math to position the various graphical elements textarea_line=0 textarea_height=$term_height command_line=$term_height clear_screen put_cursor "$command_line" 0 } #draw text on the screen from memory with offset function render_text() { clear_screen #figure out how many lines we can render local modifier="$1" local lines=$textarea_height local last_screen=$((file_lines - textarea_height)) file_offset=$((file_offset + modifier)) [ $file_offset -gt $last_screen ] && file_offset=$last_screen [ $file_offset -lt 0 ] && file_offset=0 [ $lines -gt $file_lines ] && lines=$file_lines #draw text in the viewing area local fd_offset local term_offset for (( i=0; i 0 )) && [ -f "$1" ] then mapfile file_map <"$1" else echo 'Usage: bash_pager ' return 1 fi file_lines="${#file_map[@]}" init_screen render_text 0 #read keys and perform actions while read -s -r -N1 do case "$REPLY" in ( $'\x1b' ) #ESC pressed, handle sequence read -s -r -N1 case "$REPLY" in ( $'\x1b' ) #second escape, eval user input read -e -r -p ': ' set +eu eval "$REPLY" set -eu ;; ( '[' ) #arrow key or pgup/pgdown read -s -r -N1 case "$REPLY" in ( 'A' ) #arrow up render_text -1 ;; ( 'B' ) #arrow down render_text 1 ;; ( '5' ) #pgup render_text "-$((textarea_height/2))" ;; ( '6' ) #pgdown render_text "$((textarea_height/2))" ;; esac ;; esac ;; ( 'q' ) #quit return 0 ;; esac #input keys have been read display results clear_command_line put_cursor "$command_line" 0 done } main $@