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 read -r LINES COLUMNS < <(stty -F /dev/tty size)
79
80 # Write slide number at bottom left.
81 printf '\e[H'
82 printf '\e[%sB%s/%s' "$LINES" "$(($3+1))" "$4"
83
84 # Custom calculations to center text.
85 height=$(lines "$2")
86 width=$(longest_line "$2")
87
88 # Rough estimates for the true center.
89 ((l=LINES/2 - height/2))
90 ((c=COLUMNS/2 - width/2))
91
92 printf '\e[%s;%sH' "$l" "$c"
93
94 while IFS= read -r line; do
95 reduce=0
96 # Print the contents of the slide file,
97 # line by line.
98 l=$(colorify "$line")
99 printf '%s' "$l"
100 case $line in
101 "" | "\n")
102 ((++reduce));;
103 esac
104 # Move down and back after each print.
105 l=$(ansi_filter "$l")
106 printf '\e[%sD\e[B' "$((${#l} - reduce))"
107 done <<< "$slide_contents"
108
109}
110
111die() {
112 printf '\e[2J'
113 printf '\e[?25h'
114 exit 0
115}
116
117display_end() {
118 ((l=LINES/2))
119 ((c=COLUMNS/2 - 8))
120 printf '\e[2J'
121 printf '\e[0;%sH' "$c"
122 printf 'END. Press q to quit.'
123}
124
125main() {
126
127 slides_dir="${1:-./}"
128 slides=("$slides_dir"/[0-9]*.txt)
129 total="${#slides[@]}"
130 i=0
131 while :; do
132 # Clear the screen.
133 printf '\e[2J'
134
135 # Capture Ctrl+C.
136 trap 'die' INT
137
138 # Don't go below 0.
139 [[ "$i" -lt 0 ]] && i=0
140
141 # Display END reached prompt, and then exit.
142 if [[ "$i" -eq "$total" ]]; then
143 display_end
144 else
145 display "$(<"${slides[$i]}")" "${slides[$i]}" "$i" "$total"
146 fi
147
148 # Navigation
149 read -rsn1 input
150 case "$input" in
151 "j"|"n"|""|";")
152 [[ "$i" -eq "$total" ]] && die
153 ((++i))
154 ;;
155 "k"|"p"|""|",")
156 ((--i))
157 ;;
158 "0")
159 ((i=0))
160 ;;
161 "G")
162 ((i=total-1))
163 ;;
164 "q")
165 # Return the cursor on exit.
166 die
167 ;;
168 esac
169 done
170
171 # Return the cursor.
172 printf '\e[?25h'
173
174}
175
176main "$@"