#!/usr/bin/env bash # # Usage: shlide path/to/slides/ # Each slide is a textfile under path/to/slides # Color definitions BLK="\e[38;5;30m" RED="\e[38;5;31m" GRN="\e[38;5;32m" YLW="\e[38;5;33m" BLU="\e[38;5;34m" PUR="\e[38;5;35m" CYN="\e[38;5;36m" RST="\e[0m" lines() { mapfile -tn 0 lines < "$1" printf '%s\n' "${#lines[@]}" } longest_line() { max=0 local IFS= while read -r line; do l=$(ansi_filter $(colorify "$line")) if [ "${#l}" -gt "$max" ]; then max="${#l}"; fi done < "$1" printf '%s\n' "$max" } colorify() { # 'eval' hack to achieve substitution for colors. eval "declare dummy=\"$1\"" printf '%b' "$dummy" } # Filter out color sequences. shopt -s extglob ansi_filter() { local IFS= echo "${1//$'\e'[\[(]*([0-9;])[@-n]/}" #" A little fix to prevent vim syntax highlighting from breaking. } display() { # 1 - slide contents # 2 - slide name # 3 - current slide nr. # 4 - total nr. of slides slide_contents="$1" # Hides the cursor. printf '\e[?25l' # Clear the screen. printf '\e[2J' # Get screen size shopt -s checkwinsize; (:;:) # Write slide number at bottom left printf '\e[H' printf '\e[%sB%s/%s' "$LINES" "$(($3+1))" "$4" # Custom calculations to center text height=$(lines "$2") width=$(longest_line "$2") # Rough estimates for the true center. ((l=$LINES/2 - $height/2)) ((c=$COLUMNS/2 - $width/2)) printf '\e[%s;%sH' "$l" "$c" while IFS= read -r line; do reduce=0 # Print the contents of the slide file, # line by line. l=$(colorify "$line") printf '%s' "$l" case $line in "" | *"\n"*) ((++reduce));; esac # Move down and back after each print. l=$(ansi_filter "$l") printf '\e[%sD\e[B' "$((${#l} - $reduce))" done <<< "$slide_contents" } die() { printf '\e[2J' printf '\e[?25h' exit 0 } display_end() { read -r LINES COLUMNS < <(stty -F /dev/tty size) ((l=$LINES/2)) ((c=$COLUMNS/2 - 8)) printf '\e[2J' printf '\e[0;%sH' "$c" printf 'END. Press q to quit.' } main() { slides_dir="${1:-./}" slides=("$slides_dir"/[0-9]*.txt) i=0 while true; do # Clear the screen. printf '\e[2J' # Capture Ctrl+C. trap 'die' INT # Display END reached prompt, and then exit [[ "$i" -eq "${#slides[@]}" ]] && { display_end read -rsn1 input case "$input" in "j"|"n"|"q") die ;; *) ((--i)) ;; esac } # Don't go below 0. [[ "$i" -lt 0 ]] && i=0 # Navigate on j/k/n/p and quit on q. display "$(<${slides[$i]})" "${slides[$i]}" "$i" "${#slides[@]}" read -rsn1 input case "$input" in "j"|"n") ((++i)) ;; "k"|"p") ((--i)) ;; "q") # Return the cursor on exit. die ;; esac done # Return the cursor. printf '\e[?25h' } main "$@"