shlide (view raw)
1#!/usr/bin/env bash
2#
3# Usage: shlide path/to/slides/
4# Each slide is a textfile under path/to/slides
5
6# Color definitions
7
8BLK="\e[38;5;30m"
9RED="\e[38;5;31m"
10GRN="\e[38;5;32m"
11YLW="\e[38;5;33m"
12BLU="\e[38;5;34m"
13PUR="\e[38;5;35m"
14CYN="\e[38;5;36m"
15RST="\e[0m"
16
17lines() {
18 mapfile -tn 0 lines < "$1"
19 printf '%s\n' "${#lines[@]}"
20}
21
22longest_line() {
23 max=0
24 local IFS=
25 while read -r line; do
26 l=$(ansi_filter $(colorify "$line"))
27 if [ "${#l}" -gt "$max" ]; then max="${#l}"; fi
28 done < "$1"
29 printf '%s\n' "$max"
30}
31
32colorify() {
33 # 'eval' hack to achieve substitution for colors.
34 eval "declare dummy=\"$1\""
35 printf '%b' "$dummy"
36}
37
38# Filter out color sequences.
39shopt -s extglob
40ansi_filter() {
41 local IFS=
42 echo "${1//$'\e'[\[(]*([0-9;])[@-n]/}"
43 #" A little fix to prevent vim syntax highlighting from breaking.
44}
45
46
47display() {
48 # 1 - slide contents
49 # 2 - slide name
50 # 3 - current slide nr.
51 # 4 - total nr. of slides
52
53 slide_contents="$1"
54
55 # Hides the cursor.
56 printf '\e[?25l'
57
58 # Clear the screen.
59 printf '\e[2J'
60
61 # Get screen size
62 shopt -s checkwinsize; (:;:)
63
64 # Write slide number at bottom left
65 printf '\e[H'
66 printf '\e[%sB%s/%s' "$LINES" "$(($3+1))" "$4"
67
68 # Custom calculations to center text
69 height=$(lines "$2")
70 width=$(longest_line "$2")
71
72 # Rough estimates for the true center.
73 ((l=$LINES/2 - $height/2))
74 ((c=$COLUMNS/2 - $width/2))
75
76 printf '\e[%s;%sH' "$l" "$c"
77
78 while IFS= read -r line; do
79 reduce=0
80 # Print the contents of the slide file,
81 # line by line.
82 l=$(colorify "$line")
83 printf '%s' "$l"
84 case $line in
85 "" | *"\n"*)
86 ((++reduce));;
87 esac
88 # Move down and back after each print.
89 l=$(ansi_filter "$l")
90 printf '\e[%sD\e[B' "$((${#l} - $reduce))"
91 done <<< "$slide_contents"
92
93}
94
95die() {
96 printf '\e[2J'
97 printf '\e[?25h'
98 exit 0
99}
100
101display_end() {
102 read -r LINES COLUMNS < <(stty -F /dev/tty size)
103 ((l=$LINES/2))
104 ((c=$COLUMNS/2 - 8))
105 printf '\e[2J'
106 printf '\e[0;%sH' "$c"
107 printf 'END. Press q to quit.'
108}
109
110main() {
111
112 slides_dir="${1:-./}"
113 slides=("$slides_dir"/[0-9]*.txt)
114 i=0
115 while true; do
116 # Clear the screen.
117 printf '\e[2J'
118
119 # Capture Ctrl+C.
120 trap 'die' INT
121
122 # Display END reached prompt, and then exit
123 [[ "$i" -eq "${#slides[@]}" ]] && {
124 display_end
125 read -rsn1 input
126 case "$input" in
127 "j"|"n"|"q")
128 die
129 ;;
130 *)
131 ((--i))
132 ;;
133 esac
134 }
135
136 # Don't go below 0.
137 [[ "$i" -lt 0 ]] && i=0
138
139 # Navigate on j/k/n/p and quit on q.
140 display "$(<${slides[$i]})" "${slides[$i]}" "$i" "${#slides[@]}"
141 read -rsn1 input
142 case "$input" in
143 "j"|"n")
144 ((++i))
145 ;;
146 "k"|"p")
147 ((--i))
148 ;;
149 "q")
150 # Return the cursor on exit.
151 die
152 ;;
153 esac
154 done
155
156 # Return the cursor.
157 printf '\e[?25h'
158
159}
160
161main "$@"