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