summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLibravatar Martin Michalec <martin@michalec.dev>2026-02-11 02:47:33 +0000
committerLibravatar Martin Michalec <martin@michalec.dev>2026-02-11 02:47:33 +0000
commit2c485ce2b43bd810a88278215b771136a2a17881 (patch)
tree3fb74338b87553d898af7b1795de7322cbc5af63
parentadd xdg (diff)
downloaddotfiles-2c485ce2b43bd810a88278215b771136a2a17881.tar.gz
add scripts
-rw-r--r--private_dot_local/bin/executable_emacs-dired3
-rw-r--r--private_dot_local/bin/executable_emacs-message3
-rw-r--r--private_dot_local/bin/executable_emacs-telega3
-rw-r--r--private_dot_local/bin/executable_emacs-transmission3
-rw-r--r--private_dot_local/bin/executable_hibernate3
-rw-r--r--private_dot_local/bin/executable_lock4
-rw-r--r--private_dot_local/bin/executable_menu3
-rw-r--r--private_dot_local/bin/executable_menu-drun23
-rw-r--r--private_dot_local/bin/executable_menu-network34
-rw-r--r--private_dot_local/bin/executable_menu-run3
-rw-r--r--private_dot_local/bin/executable_passmenu42
-rw-r--r--private_dot_local/bin/executable_pinentry-menu33
-rw-r--r--private_dot_local/bin/executable_powermenu28
-rw-r--r--private_dot_local/bin/executable_suspend3
-rw-r--r--private_dot_local/bin/executable_sway-shot-output5
-rw-r--r--private_dot_local/bin/executable_sway-shot-window-or-selection5
-rw-r--r--private_dot_local/bin/executable_sway-swappy-clipboard3
-rw-r--r--private_dot_local/bin/executable_sync-mail5
-rw-r--r--private_dot_local/bin/executable_toggle-screen-capture39
-rw-r--r--private_dot_local/bin/executable_toggle-vpn9
-rw-r--r--private_dot_local/bin/executable_tspreed441
-rw-r--r--private_dot_local/bin/executable_waybar-inbox5
-rw-r--r--private_dot_local/bin/executable_waybar-screen-recorder9
-rw-r--r--private_dot_local/bin/executable_waybar-sunset64
-rw-r--r--private_dot_local/bin/executable_waybar-vpn7
-rw-r--r--private_dot_local/bin/executable_wine-run-with-cd6
26 files changed, 786 insertions, 0 deletions
diff --git a/private_dot_local/bin/executable_emacs-dired b/private_dot_local/bin/executable_emacs-dired
new file mode 100644
index 0000000..a0b8442
--- /dev/null
+++ b/private_dot_local/bin/executable_emacs-dired
@@ -0,0 +1,3 @@
1#!/bin/sh
2
3exec /usr/bin/emacsclient --no-wait --quiet --alternate-editor= --create-frame --eval '(progn (set-frame-name "Dired - Emacs Client") (dired (pop server-eval-args-left)))' "$@"
diff --git a/private_dot_local/bin/executable_emacs-message b/private_dot_local/bin/executable_emacs-message
new file mode 100644
index 0000000..0f17496
--- /dev/null
+++ b/private_dot_local/bin/executable_emacs-message
@@ -0,0 +1,3 @@
1#!/bin/sh
2
3exec /usr/bin/emacsclient --no-wait --quiet --alternate-editor= --create-frame --eval '(progn (set-frame-name "Send Email - Emacs Client") (browse-url-mail (pop server-eval-args-left)))' "$@"
diff --git a/private_dot_local/bin/executable_emacs-telega b/private_dot_local/bin/executable_emacs-telega
new file mode 100644
index 0000000..854fccf
--- /dev/null
+++ b/private_dot_local/bin/executable_emacs-telega
@@ -0,0 +1,3 @@
1#!/bin/sh
2
3exec /usr/bin/emacsclient --no-wait --quiet --alternate-editor= --create-frame --eval "(progn (set-frame-name \"Telega - Emacs Client\") (if (and (boundp 'telega--status) (equal telega--status \"Ready\")) (telega-browse-url (pop server-eval-args-left)) (telega) (add-hook 'telega-ready-hook (lambda () (telega-browse-url (pop server-eval-args-left))))))" "$@"
diff --git a/private_dot_local/bin/executable_emacs-transmission b/private_dot_local/bin/executable_emacs-transmission
new file mode 100644
index 0000000..1b0f665
--- /dev/null
+++ b/private_dot_local/bin/executable_emacs-transmission
@@ -0,0 +1,3 @@
1#!/bin/sh
2
3exec /usr/bin/emacsclient --no-wait --quiet --alternate-editor= --eval "(let* ((torrent (pop server-eval-args-left))) (require 'notifications) (condition-case nil (progn (transmission-add torrent) (notifications-notify :title \"Transmission\" :body (format \"Torrent probably added: %s\" torrent) :timeout 2000)) (error (notifications-notify :title \"Transmission\" :body \"Something went wrong, check if transmission daemon is running.\") nil)))" "$@"
diff --git a/private_dot_local/bin/executable_hibernate b/private_dot_local/bin/executable_hibernate
new file mode 100644
index 0000000..199d5c6
--- /dev/null
+++ b/private_dot_local/bin/executable_hibernate
@@ -0,0 +1,3 @@
1#!/bin/sh
2
3swaylock && doas ZZZ
diff --git a/private_dot_local/bin/executable_lock b/private_dot_local/bin/executable_lock
new file mode 100644
index 0000000..37a30b5
--- /dev/null
+++ b/private_dot_local/bin/executable_lock
@@ -0,0 +1,4 @@
1#!/bin/sh
2
3gpg-connect-agent reloadagent /bye
4swaylock \ No newline at end of file
diff --git a/private_dot_local/bin/executable_menu b/private_dot_local/bin/executable_menu
new file mode 100644
index 0000000..6d47fb1
--- /dev/null
+++ b/private_dot_local/bin/executable_menu
@@ -0,0 +1,3 @@
1#!/bin/sh
2
3wmenu -f "$HOME/.local/share/fonts/TTF/aporetic-serif-mono-normalregularupright.ttf 17" "$@"
diff --git a/private_dot_local/bin/executable_menu-drun b/private_dot_local/bin/executable_menu-drun
new file mode 100644
index 0000000..e655672
--- /dev/null
+++ b/private_dot_local/bin/executable_menu-drun
@@ -0,0 +1,23 @@
1#!/bin/sh
2
3SEARCH_PATHS=$(echo $XDG_DATA_HOME:$XDG_DATA_DIRS | tr ':' '\n' | awk '{print $1 "/applications"}')
4
5LIST=$(find -L $SEARCH_PATHS -maxdepth 1 -name "*.desktop" -print0 2>/dev/null | xargs -0 awk -F'=' '
6 BEGINFILE { name=""; section="" }
7 /^\[Desktop Entry\]/ { section="main" }
8 /^\[Desktop Action / { section=substr($0, 17, length($0)-17) }
9 /^Name=/ && section=="main" { name=$2 }
10 ENDFILE {
11 if (name != "") {
12 printf "%s:%s\n", FILENAME, name
13 }
14 }
15')
16
17CHOICE=$(echo "$LIST" | cut -d: -f2 | sort -u | $MENU "$@")
18
19[ -z "$CHOICE" ] && exit
20
21FILE=$(echo "$LIST" | grep -F ":$CHOICE" | head -n 1 | cut -d: -f1)
22
23gtk4-launch $(basename $FILE)
diff --git a/private_dot_local/bin/executable_menu-network b/private_dot_local/bin/executable_menu-network
new file mode 100644
index 0000000..b3a31a9
--- /dev/null
+++ b/private_dot_local/bin/executable_menu-network
@@ -0,0 +1,34 @@
1#!/bin/sh
2
3set -xe
4
5wpa_cli scan
6
7REFRESH="-- REFRESH --"
8
9SELECTION=$REFRESH
10while [ "$SELECTION" = "$REFRESH" ]; do
11 NETWORKS=$(wpa_cli scan_results | awk 'NR > 2 { $1=$2=$3=$4=""; print $0 }' | sed 's/^[ \t]*//' | sort -u)
12 SELECTION=$(echo "$REFRESH$NETWORKS" | menu -l 10 -p "Connect to:")
13 [ -z "$SELECTION" ] && exit 0
14done
15
16ID=$(wpa_cli list_networks | grep "$SELECTION" | awk '{print $1}')
17
18if [ -z "$ID" ]; then
19 # New connection: Prompt for password
20 PASS=$(echo -n | menu -Pp "Password:")
21
22 ID=$(wpa_cli add_network | tail -n -1)
23 wpa_cli set_network "$ID" ssid "\"$SELECTION\""
24
25 if [ -z "$PASS" ]; then
26 wpa_cli set_network "$ID" key_mgmt NONE
27 else
28 wpa_cli set_network "$ID" psk "\"$PASS\""
29 fi
30 wpa_cli save_config
31fi
32
33wpa_cli select_network "$ID"
34wpa_cli enable_network "$ID"
diff --git a/private_dot_local/bin/executable_menu-run b/private_dot_local/bin/executable_menu-run
new file mode 100644
index 0000000..a588245
--- /dev/null
+++ b/private_dot_local/bin/executable_menu-run
@@ -0,0 +1,3 @@
1#!/bin/sh
2
3wmenu-run -f "$HOME/.local/share/fonts/TTF/aporetic-serif-mono-normalregularupright.ttf 17" $@
diff --git a/private_dot_local/bin/executable_passmenu b/private_dot_local/bin/executable_passmenu
new file mode 100644
index 0000000..1aa1158
--- /dev/null
+++ b/private_dot_local/bin/executable_passmenu
@@ -0,0 +1,42 @@
1#!/bin/sh
2
3typeit=0
4nameit=0
5while true; do
6 case $1 in
7 "--type")
8 typeit=1
9 shift
10 ;;
11 "--name")
12 nameit=1
13 shift
14 ;;
15 *)
16 break
17 ;;
18 esac
19done
20
21prefix=${PASSWORD_STORE_DIR-~/.password-store}
22password=$(find $prefix -name '*.gpg' | sed "s@$prefix/\(.*\)\.gpg@\1@" | $MENU "$@")
23
24[ -n "$password" ] || exit
25
26if [ $nameit = 0 ]; then
27 what=$(pass show "$password" | head -n 1)
28 [ -n "$what" ] || exit
29else
30 what=$(basename $password)
31fi
32
33if [ $typeit = 0 ]; then
34 printf "$what" | wl-copy
35 if [ $nameit = 0 ]; then
36 notify-send "Coppied password for:" "$password"
37 else
38 notify-send "Coppied password name:" "$password"
39 fi
40else
41 printf "$what" | wtype - -k Tab
42fi
diff --git a/private_dot_local/bin/executable_pinentry-menu b/private_dot_local/bin/executable_pinentry-menu
new file mode 100644
index 0000000..5f42c0c
--- /dev/null
+++ b/private_dot_local/bin/executable_pinentry-menu
@@ -0,0 +1,33 @@
1#!/bin/sh
2
3echo "OK Pleased to meet you"
4
5while read line; do
6 echo "GPG sent: $line" >> /tmp/pinentry-trace.log
7 # Ignore empty lines
8 [ -z "$line" ] && continue
9
10 case "$line" in
11 *GETPIN*)
12 # Run menu and capture output
13 # We use /dev/tty for input if needed, but wmenu usually handles its own window
14 PIN=$(echo -n | menu -p "Passphrase: " -P)
15
16 if [ $? -ne 0 ] || [ -z "$PIN" ]; then
17 echo "CAN"
18 else
19 echo "D $PIN"
20 echo "OK"
21 fi
22 ;;
23 *BYE*)
24 echo "OK"
25 exit 0
26 ;;
27 *)
28 # For everything else (SETDESC, SETPROMPT, OPTION, etc.)
29 # We MUST say OK or the agent thinks we crashed
30 echo "OK"
31 ;;
32 esac
33done
diff --git a/private_dot_local/bin/executable_powermenu b/private_dot_local/bin/executable_powermenu
new file mode 100644
index 0000000..ae168cd
--- /dev/null
+++ b/private_dot_local/bin/executable_powermenu
@@ -0,0 +1,28 @@
1#!/bin/sh
2
3selection=$(cat <<EOF | $MENU "$@"
4suspend
5hibernate
6shutdown
7reboot
8exit sway
9EOF
10)
11
12case $selection in
13 "suspend")
14 suspend
15 ;;
16 "hibernate")
17 hibernate
18 ;;
19 "shutdown")
20 doas shutdown now
21 ;;
22 "reboot")
23 doas shutdown -r now
24 ;;
25 "exit sway")
26 swaymsg exit
27 ;;
28esac
diff --git a/private_dot_local/bin/executable_suspend b/private_dot_local/bin/executable_suspend
new file mode 100644
index 0000000..7c7841a
--- /dev/null
+++ b/private_dot_local/bin/executable_suspend
@@ -0,0 +1,3 @@
1#!/bin/sh
2
3swaylock && doas zzz
diff --git a/private_dot_local/bin/executable_sway-shot-output b/private_dot_local/bin/executable_sway-shot-output
new file mode 100644
index 0000000..79ddd05
--- /dev/null
+++ b/private_dot_local/bin/executable_sway-shot-output
@@ -0,0 +1,5 @@
1#!/bin/sh
2
3output=$(swaymsg -t get_outputs | jq -r '.[] | select(.focused) | .name')
4file=$(date "+$HOME/multimedia/screenshots/%Y%m%d-%H%M%S.png")
5grim -o $output - | tee $file | wl-copy
diff --git a/private_dot_local/bin/executable_sway-shot-window-or-selection b/private_dot_local/bin/executable_sway-shot-window-or-selection
new file mode 100644
index 0000000..404764e
--- /dev/null
+++ b/private_dot_local/bin/executable_sway-shot-window-or-selection
@@ -0,0 +1,5 @@
1#!/bin/sh
2
3geom=$(swaymsg -t get_tree | jq -r '.. | select(.pid? and .visible?) | .rect | "\(.x),\(.y) \(.width)x\(.height)"' | slurp -b 303030AA -B 303030AA)
4file=$(date "+$HOME/multimedia/screenshots/%Y%m%d-%H%M%S.png")
5grim -g "$geom" - | tee $file | wl-copy
diff --git a/private_dot_local/bin/executable_sway-swappy-clipboard b/private_dot_local/bin/executable_sway-swappy-clipboard
new file mode 100644
index 0000000..7f6582c
--- /dev/null
+++ b/private_dot_local/bin/executable_sway-swappy-clipboard
@@ -0,0 +1,3 @@
1#!/bin/sh
2
3wl-paste | swappy -f -
diff --git a/private_dot_local/bin/executable_sync-mail b/private_dot_local/bin/executable_sync-mail
new file mode 100644
index 0000000..d20fbfe
--- /dev/null
+++ b/private_dot_local/bin/executable_sync-mail
@@ -0,0 +1,5 @@
1#!/bin/sh
2
3mbsync -a
4l2md
5notmuch new
diff --git a/private_dot_local/bin/executable_toggle-screen-capture b/private_dot_local/bin/executable_toggle-screen-capture
new file mode 100644
index 0000000..10dff96
--- /dev/null
+++ b/private_dot_local/bin/executable_toggle-screen-capture
@@ -0,0 +1,39 @@
1#!/bin/sh
2
3PID=`pgrep wf-recorder`
4FILE="$HOME/multimedia/screencasts/`date '+%Y%m%d-%H%M%S'`.mkv"
5
6if [ "$PID" ]; then
7 kill -INT $PID
8 for module in `pactl list short modules | grep wf-recorder | cut -f1`; do
9 pactl unload-module $module
10 done
11 while `pgrep wf-recorder`; do sleep 0.01; done
12 pkill -SIGRTMIN+8 waybar
13 sleep 0.01
14 pkill -SIGRTMIN+8 waybar
15else
16 TYPE=${1:-output}
17 case $TYPE in
18 output)
19 GEOMETRY=`slurp -o -b "303030AA" -B "303030AA"`
20 ;;
21 window)
22 GEOMETRY=`swaymsg -t get_tree | jq -r '.. | select(.pid? and .visible?) | "\(.rect.x+.window_rect.x),\(.rect.y+.window_rect.y) \(.window_rect.width)x\(.window_rect.height)"' | slurp -b "303030AA" -B "303030AA"`
23 ;;
24 *)
25 echo "Usage: $0 [output|window]"
26 exit 1
27 ;;
28 esac
29 if [ -z "$GEOMETRY" ]; then exit; fi
30 pactl load-module module-null-sink sink_name=wf-recorder
31 pactl load-module module-loopback sink=wf-recorder source=alsa_output.pci-0000_00_1b.0.analog-stereo.monitor
32 pactl load-module module-loopback sink=wf-recorder source=alsa_input.pci-0000_00_1b.0.analog-stereo
33 wf-recorder --audio=wf-recorder.monitor \
34 --geometry="$GEOMETRY" \
35 --pixel-format=yuv420p \
36 --file="$FILE" &
37 disown $!
38 pkill -SIGRTMIN+8 waybar
39fi
diff --git a/private_dot_local/bin/executable_toggle-vpn b/private_dot_local/bin/executable_toggle-vpn
new file mode 100644
index 0000000..3441e64
--- /dev/null
+++ b/private_dot_local/bin/executable_toggle-vpn
@@ -0,0 +1,9 @@
1#!/bin/sh
2
3if ip address | grep wg0; then
4 sudo herd stop wireguard-wg0
5else
6 sudo herd start wireguard-wg0
7fi
8
9pkill -SIGRTMIN+9 waybar
diff --git a/private_dot_local/bin/executable_tspreed b/private_dot_local/bin/executable_tspreed
new file mode 100644
index 0000000..214c367
--- /dev/null
+++ b/private_dot_local/bin/executable_tspreed
@@ -0,0 +1,441 @@
1#!/bin/sh
2
3# Copyright (c) 2020-2024 Nicholas Ivkovic.
4# Licensed under the GNU General Public License version 3 or later. See ./LICENSE, or <https://gnu.org/licenses/gpl.html> if more recent, for details.
5# This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law.
6
7# Notes about disabled ShellChecks:
8# SC1090 -- Config files do not need to/cannot be checked as they are user-written. Default config is checked separately
9# SC2015 -- Disabled where behaviour resembling an if-then-else is not intended
10# SC3045 -- Disabled where support for non-POSIX options are tested for and handled
11
12# Exit from caught signals
13exit_catch() {
14 [ "$term_presenting" = true ] && end_term 8
15 ! [ "$quietexit" = true ] && printf "%s/%s\n" "$word_num" "$input_words"
16 exit 8
17}
18
19# Exit from error
20# $1 return value
21# $2 error message
22exit_err() {
23 [ "$term_presenting" = true ] && end_term "$1"
24 [ "$1" -eq 3 ] && printf "Terminal does not support capability '%s'\n" "$2" >&2 || printf "%s\n" "$2" >&2
25 [ "$1" -eq 1 ] && printf "Usage: tspreed [-lqhikfbv] [-w wpm] [-n num] [-p style] [-c color] [-K path]\n" >&2
26 printf "See 'man tspreed'\n" >&2
27 exit "$1"
28}
29
30# Move cursor to position
31# $1 row
32# $2 column
33term_move() {
34 tput cup "$1" "$2" 2>/dev/null || printf "%b[%s;%sH" "\033" "$1" "$2"
35}
36
37# Set foreground color
38# $1 color
39term_color() {
40 tput setaf "$1" 2>/dev/null || {
41 # shellcheck disable=SC2015
42 [ "$1" -le 7 ] && printf "%b[3%sm" "\033" "$1" || exit_err 3 "setaf"
43 }
44}
45
46# Move to top row and clear
47term_init_top() {
48 printf "%s%s" "${term_home}" "${term_clear_line}"
49}
50
51# Move to bottom row and clear
52term_init_bottom() {
53 term_move "$term_height" 0 && printf "%s" "${term_clear_line}"
54}
55
56# Initialise output
57init_presentation() {
58 printf "%s" "$term_clear"
59 [ -n "$focuspointer" ] && [ "$focus" = true ] && {
60 term_move $((term_y_center - 1)) "$term_x_center" && printf "%s" "$focus_pointer_1"
61 term_move $((term_y_center + 1)) "$term_x_center" && printf "%s" "$focus_pointer_2"
62 }
63}
64
65# Initialise terminal output
66init_term() {
67 term_height="$(tput lines)" || {
68 [ -n "$LINES" ] && [ "$LINES" -gt 0 ] 2>/dev/null && term_height="$LINES" || term_height=24
69 }
70 term_width="$(tput cols)" || {
71 [ -n "$COLUMNS" ] && [ "$COLUMNS" -gt 0 ] 2>/dev/null && term_width="$COLUMNS" || term_width=80
72 }
73 term_x_center=$((term_width / 2))
74 term_y_center=$((term_height / 2))
75 init_presentation
76}
77
78# Finish terminal output
79# $1 return value of exit function
80end_term() {
81 term_presenting=false
82 if [ "$term_session" = true ]; then
83 tput rmcup 2>/dev/null || exit_err 3 "rmcup"
84 else
85 if [ "$1" -eq 8 ]; then
86 term_move $((term_height - 1)) 0
87 else
88 term_move "$term_height" 0
89 fi
90 fi
91 printf "%s" "$term_reset"
92 [ "$hidecursor" = true ] && {
93 tput cnorm 2>/dev/null || exit_err 3 "cnorm"
94 }
95}
96
97# Get current epoch timestamp in milliseconds
98get_date_ms() {
99 # Epoch timestamp without '%s' taken from https://www.etalabs.net/sh_tricks.html
100 [ "$non_posix_date_s" = true ] && curr_epoch_sec="$(date -u "+%s")" || curr_epoch_sec="$(($(date -u "+((%Y-1600)*365+(%Y-1600)/4-(%Y-1600)/100+(%Y-1600)/400+1%j-1000-135140)*86400+(1%H-100)*3600+(1%M-100)*60+(1%S-100)")))"
101 echo "$(($(date -u "+${curr_epoch_sec}%N / 1000000")))"
102}
103
104# Get substring
105# $1 string
106# $2 index (from 1) to get from
107# $3 number of characters to get (all if not provided)
108get_substr() {
109 if [ "$use_cut" = true ]; then
110 if [ -n "$3" ]; then
111 printf "%s" "$1" | cut -c "$2"-$(($2 - 1 + $3))
112 else
113 printf "%s" "$1" | cut -c "$2"-
114 fi
115 else
116 if [ -n "$3" ]; then
117 printf "%s" "$1" | awk -v pos="$2" -v len="$3" '{ printf("%s", substr($0, pos, len)) }'
118 else
119 printf "%s" "$1" | awk -v pos="$2" '{ printf("%s", substr($0, pos)) }'
120 fi
121 fi
122}
123
124# Perform floating point calculation
125# $1 calculation to perform
126calc_float() {
127 if [ "$use_bc" = true ]; then
128 # No floating point calculation in script should return a negative result, so no handling of negative results implemented
129 printf "scale=3; %s\n" "$1" | bc | sed 's/^\./0./'
130 else
131 awk "BEGIN { print ${1} }"
132 fi
133}
134
135# $1 Word number
136# $2 Total number of words
137print_presentation_info() {
138 printf "%s%b%s" "${1}/${2}" "\t" "$((($1 * 100) / $2))%"
139}
140
141# Import configs
142config_global="/etc/tspreed/tspreed.rc"
143config_local="${XDG_CONFIG_HOME:-$HOME/.config}/tspreed/tspreed.rc"
144# shellcheck disable=SC1090
145[ -f "$config_global" ] && . "$config_global"
146# shellcheck disable=SC1090
147[ -f "$config_local" ] && . "$config_local"
148
149# Init
150input=
151term_presenting=false
152word_first=true
153word_num=0
154word_paused=false
155word_len_average=5 # Based on average English word length of 5.1 letters
156focus_pointer_1=
157focus_pointer_2=
158prev_word_len_exceed=false
159
160# Catch signals
161trap "exit_catch" 2 # SIGINT
162trap "exit_catch" 3 # SIGQUIT
163trap "exit_catch" 6 # SIGABRT
164trap "exit_catch" 14 # SIGALRM
165trap "exit_catch" 15 # SIGTERM
166trap "init_term" WINCH # Terminal emulator resize
167
168# Convert long options to short options
169for arg in "$@"; do
170 shift
171 case "$arg" in
172 "--wpm") set -- "$@" "-w" ;;
173 "--num-start") set -- "$@" "-n" ;;
174 "--separators") set -- "$@" "-s" ;;
175 "--length-vary") set -- "$@" "-l" ;;
176 "--quiet-exit") set -- "$@" "-q" ;;
177 "--hide-cursor") set -- "$@" "-h" ;;
178 "--progress-info") set -- "$@" "-i" ;;
179 "--key-controls") set -- "$@" "-k" ;;
180 "--focus") set -- "$@" "-f" ;;
181 "--focus-pointer") set -- "$@" "-p" ;;
182 "--focus-bold") set -- "$@" "-b" ;;
183 "--focus-color") set -- "$@" "-c" ;;
184 "--dev-key-input") set -- "$@" "-K" ;;
185 "--version") set -- "$@" "-v" ;;
186 *) set -- "$@" "$arg" ;;
187 esac
188done
189OPTIND=1
190
191# Parse options
192while getopts ":w:n:s:qhiklfp:bc:K:vV" opt; do
193 case "$opt" in
194 w) wpm=$OPTARG ;;
195 n) numstart="$OPTARG" ;;
196 s) separators="$OPTARG" ;;
197 l) lengthvary=true ;;
198 q) quietexit=true ;;
199 h) hidecursor=true ;;
200 i) proginfo=true ;;
201 k) keycontrols=true ;;
202 f) focus=true ;;
203 p) focuspointer="$OPTARG" ;;
204 b) focusbold=true ;;
205 c) focuscolor="$OPTARG" ;;
206 K) devkeyinput="$OPTARG" ;;
207 v|V) printf "tspreed 2.6.2\n" && exit 0 ;;
208 \?) exit_err 1 "Invalid option '-${OPTARG}'" ;;
209 :) exit_err 1 "Option -${OPTARG} requires an argument." ;;
210 esac
211done
212
213# Validate and set keyboard input device/path
214[ -z "$devkeyinput" ] && devkeyinput='/dev/tty'
215[ -e "$devkeyinput" ] || exit_err 1 "Invalid keyboard input path '${devkeyinput}'"
216
217# Validate word speed
218[ -z "$wpm" ] && exit_err 1 "WPM not set"
219! { [ "$wpm" -ge 1 ] && [ "$wpm" -le 60000 ]; } 2>/dev/null && exit_err 1 "Invalid WPM '${wpm}'"
220
221# Validate and set nth word as starting word
222[ -n "$numstart" ] && ! [ "$numstart" -ge 1 ] 2>/dev/null && exit_err 1 "Invalid starting word position '${numstart}'"
223[ -z "$numstart" ] && numstart=1
224
225# Validate focus letter options
226[ "$focus" = true ] && {
227 # Validate and set focus letter pointers
228 [ -n "$focuspointer" ] && [ "$focuspointer" != "none" ] && {
229 case "$focuspointer" in
230 line) focus_pointer_1="|" && focus_pointer_2="|" ;;
231 point) focus_pointer_1="v" && focus_pointer_2="^" ;;
232 *) exit_err 1 "Invalid focus letter pointer '${focuspointer}'" ;;
233 esac
234 }
235 # Validate focus letter color
236 [ -n "$focuscolor" ] && ! { [ "$focuscolor" -ge 0 ] && [ "$focuscolor" -le 255 ]; } 2>/dev/null && exit_err 1 "Invalid focus letter color '${focuscolor}'"
237}
238
239# Set IFS
240IFS="$(printf "%s%b" "$IFS" "$separators")"
241
242# Determine non-POSIX capabilities
243# shellcheck disable=SC3045
244read -rs -n 0 -t 0.0 2>/dev/null && non_posix_read=true || non_posix_read=false
245sleep 0e-3 2>/dev/null && non_posix_sleep_enotation=true || non_posix_sleep_enotation=false
246sleep 0.0 2>/dev/null && non_posix_sleep_fractional=true || non_posix_sleep_fractional=false
247[ -n "$(command -v usleep)" ] && non_posix_usleep=true || non_posix_usleep=false
248[ "$(date "+%N")" -ge 0 ] 2>/dev/null && non_posix_date_n=true || non_posix_date_n=false
249[ "$(date "+%s")" -ge 0 ] 2>/dev/null && non_posix_date_s=true || non_posix_date_s=false
250
251# Validate required non-POSIX capabilities
252if [ "$keycontrols" = true ]; then
253 [ "$non_posix_read" = false ] && exit_err 2 "System or shell does not support non-POSIX read(1)"
254 [ "$non_posix_date_n" = false ] && exit_err 2 "System or shell does not support non-POSIX date(1) '%N' format"
255else
256 [ "$non_posix_sleep_enotation" = false ] && [ "$non_posix_sleep_fractional" = false ] && [ "$non_posix_usleep" = false ] && [ "$non_posix_date_n" = false ] && exit_err 2 "System or shell does not support at least one of the required non-POSIX features or commands"
257fi
258
259# Determine terminal capabilities
260term_reset="$(tput sgr0 2>/dev/null || printf "%b[m" "\033")"
261term_bold="$(tput bold 2>/dev/null || printf "%b[1m" "\033")"
262term_home="$(tput home 2>/dev/null || term_move 0 0)"
263term_clear_line="$(tput el 2>/dev/null || printf "%b[K" "\033")"
264[ -n "$(tput smcup 2>/dev/null)" ] && [ -n "$(tput rmcup 2>/dev/null)" ] && term_session=true || term_session=false
265[ "$term_session" = false ] && term_clear="$(printf "%s%s" "$term_home" "$(tput ed 2 2>/dev/null || printf "%b[2J" "\033")")" || term_clear="$(tput clear)" 2>/dev/null
266
267# Determine wide character capabilities
268wide_char="$(printf "%b" "\0316\0251")"
269[ "${#wide_char}" -eq 1 ] && wide_param_expansion=true || wide_param_expansion=false
270[ "$(printf "%s" "$wide_char" | cut -c 1)" = "$wide_char" ] && wide_cut=true || wide_cut=false
271
272# Get input
273while read -r inp; do
274 input="${input}${inp} "
275done
276
277# Get input info
278input_info="$(printf "%s" "$input" | wc -wmc)"
279input_words="$(echo "$input_info" | awk '{ print $1 }')"
280[ "$(echo "$input_info" | awk '{ print $3 - $2 }')" -gt 0 ] && wide_input=true || wide_input=false
281
282# Determine command usage
283{ [ "$wide_input" = false ] || [ "$wide_param_expansion" = true ]; } && use_param_expansion=true || use_param_expansion=false
284{ [ "$wide_input" = false ] || [ "$wide_cut" = true ]; } && use_cut=true || use_cut=false
285[ -n "$(command -v bc)" ] && use_bc=true || use_bc=false
286
287# Init presentation
288if [ "$term_session" = true ]; then
289 tput smcup 2>/dev/null || exit_err 3 "smcup"
290else
291 printf "%s" "$term_clear"
292fi
293term_presenting=true
294[ "$hidecursor" = true ] && {
295 tput civis 2>/dev/null || exit_err 3 "civis"
296}
297init_term
298
299# Present
300for word in $input; do
301
302 # Init word
303 [ "$use_param_expansion" = true ] && word_len=${#word} || word_len="$(printf "%s" "$word" | wc -m)"
304 [ "$word_len" -le 0 ] && continue
305 word_num=$((word_num + 1))
306 [ "$word_num" -lt "$numstart" ] && continue
307 word_x=0
308
309 # Clear word
310 if [ "$prev_word_len_exceed" = true ]; then
311 init_presentation
312 else
313 term_move "$term_y_center" 0
314 printf "%s" "$term_clear_line"
315 fi
316
317 [ "$non_posix_date_n" = true ] && word_start_date="$(get_date_ms)"
318
319 # Highlighted focus letter
320 if [ "$focus" = true ]; then
321
322 # Set focus letter
323 case "$word_len" in
324 1|2) word_focus_pos=1 ;;
325 3|4|5) word_focus_pos=2 ;;
326 6|7|8|9) word_focus_pos=3 ;;
327 10|11|12|13) word_focus_pos=4 ;;
328 *) word_focus_pos=5 ;;
329 esac
330 # Set horizontal position of word
331 word_x=$((term_x_center - word_focus_pos + 1))
332 term_move "$term_y_center" "$word_x"
333
334 # Formatted focus letter
335 if [ "$focusbold" = true ] || [ -n "$focuscolor" ]; then
336
337 # Print start of word
338 [ "$word_focus_pos" -gt 1 ] && printf "%s" "$(get_substr "$word" 1 $((word_focus_pos - 1)))"
339
340 # Print focus letter
341 [ "$focusbold" = true ] && printf "%s" "$term_bold"
342 [ -n "$focuscolor" ] && term_color "$focuscolor"
343 printf "%s" "$(get_substr "$word" "$word_focus_pos" 1)"
344 printf "%s" "$term_reset"
345
346 # Print end of word
347 printf "%s" "$(get_substr "$word" $((word_focus_pos + 1)))"
348
349 # No formatting
350 else
351 printf "%s" "$word"
352 fi
353
354 # No focus letter highlighting
355 else
356 # Set horizontal position of word
357 [ $((word_x + word_len)) -le "$term_width" ] && word_x=$((term_x_center - (word_len / 2)))
358 term_move "$term_y_center" "$word_x"
359 # Print
360 printf "%s" "$word"
361 fi
362
363 # Print presentation information
364 [ "$proginfo" = true ] && term_init_top && print_presentation_info "$word_num" "$input_words"
365
366 # End word
367 term_move "$term_height" 0
368 [ $((word_x + word_len)) -gt "$term_width" ] && prev_word_len_exceed=true || prev_word_len_exceed=false
369
370 # Calculate sleep time
371 # No sleep time calculation should return a negative result, so no handling of negative sleep times implemented
372 sleep_ms_float=$(calc_float "1000 / (${wpm} / 60)")
373 [ "$lengthvary" = true ] && sleep_ms_float="$(calc_float "${sleep_ms_float} * ($([ "$word_len" -gt "$word_len_average" ] && echo "$word_len" || echo $((word_len_average - 1))) / ${word_len_average})")"
374 # Account for word processing time if possible
375 [ "$non_posix_date_n" = true ] && sleep_ms_float=$(calc_float "${sleep_ms_float} + ${word_start_date} - $(get_date_ms)")
376
377 # Convert sleep time to int
378 sleep_ms="${sleep_ms_float%.*}"
379
380 # Sleep first word for minimum 1 second
381 [ "$word_first" = true ] && {
382 word_first=false
383 [ "$sleep_ms" -lt 1000 ] && sleep_ms=1000
384 }
385
386 # Sleep with keyboard controls
387 if [ "$keycontrols" = true ]; then
388 sleep_date=$(($(get_date_ms) + sleep_ms))
389 while [ "$(get_date_ms)" -lt "$sleep_date" ] || [ "$word_paused" = true ]; do
390 # shellcheck disable=SC3045
391 read -rs -n 1 -t 0.001 input_key < "$devkeyinput"
392 case "$input_key" in
393 i)
394 if [ "$proginfo" = true ]; then
395 proginfo=false
396 term_init_top
397 else
398 proginfo=true
399 term_init_top && print_presentation_info "$word_num" "$input_words"
400 fi
401 ;;
402 p)
403 if [ "$word_paused" = true ]; then
404 word_paused=false
405 term_init_bottom
406 # Sleep after unpause for minimum 0.5 seconds
407 [ "$sleep_ms" -lt 500 ] && sleep_ms=500
408 sleep_date=$(($(get_date_ms) + sleep_ms))
409 else
410 word_paused=true
411 term_init_bottom && printf "[ Paused ]"
412 fi
413 ;;
414 q)
415 exit_catch
416 ;;
417 esac
418 done
419 term_init_bottom
420 # Sleep only
421 elif [ "$sleep_ms" -gt 0 ]; then
422 if [ "$non_posix_sleep_enotation" = true ]; then
423 sleep "${sleep_ms}e-3"
424 elif [ "$non_posix_usleep" = true ]; then
425 usleep $((sleep_ms * 1000))
426 elif [ "$non_posix_sleep_fractional" = true ]; then
427 sleep "$(calc_float "${sleep_ms} / 1000")"
428 elif [ "$non_posix_date_n" = true ]; then
429 sleep_date=$(($(get_date_ms) + sleep_ms))
430 while [ "$(get_date_ms)" -lt "$sleep_date" ]; do
431 :
432 done
433 else
434 exit_err 2 "System or shell does not support at least one of the required non-POSIX features or commands"
435 fi
436 fi
437
438done
439
440sleep 1 && end_term 0
441exit 0
diff --git a/private_dot_local/bin/executable_waybar-inbox b/private_dot_local/bin/executable_waybar-inbox
new file mode 100644
index 0000000..2ac6378
--- /dev/null
+++ b/private_dot_local/bin/executable_waybar-inbox
@@ -0,0 +1,5 @@
1#!/bin/sh
2
3COUNT=$(notmuch count tag:inbox)
4
5printf '{"alt":"%s","tooltip":"%s"}\n' "$alt" "$tooltip"
diff --git a/private_dot_local/bin/executable_waybar-screen-recorder b/private_dot_local/bin/executable_waybar-screen-recorder
new file mode 100644
index 0000000..23cdc6f
--- /dev/null
+++ b/private_dot_local/bin/executable_waybar-screen-recorder
@@ -0,0 +1,9 @@
1#!/bin/sh
2
3PID=`pgrep wf-recorder`
4
5if [ "$PID" ]; then
6 echo "{ \"text\": \"⬤\", \"tooltip\": \"Kill recording\" }"
7else
8 echo "{ \"text\": \"\" }"
9fi
diff --git a/private_dot_local/bin/executable_waybar-sunset b/private_dot_local/bin/executable_waybar-sunset
new file mode 100644
index 0000000..88c98f0
--- /dev/null
+++ b/private_dot_local/bin/executable_waybar-sunset
@@ -0,0 +1,64 @@
1#!/bin/sh
2
3start ()
4{
5 wlsunset -l "59.8" -L "30.2" -t "3000" -T "6500" &
6}
7
8stop ()
9{
10 pkill -x wlsunset
11}
12
13rotate ()
14{
15 pkill -x -SIGUSR1 wlsunset
16}
17
18update_waybar ()
19{
20 pkill -x -SIGRTMIN+10 waybar
21}
22
23is_active ()
24{
25 pkill -x -0 wlsunset
26}
27
28has_wlsunset ()
29{
30 command -v wlsunset >/dev/null
31}
32
33case "$1" in
34 'start')
35 start
36 update_waybar
37 ;;
38 'stop')
39 stop
40 update_waybar
41 ;;
42 'toggle')
43 is_active && stop || start
44 update_waybar
45 ;;
46 'rotate')
47 rotate
48 update_waybar
49 ;;
50 'check')
51 has_wlsunset
52 exit $?
53 ;;
54esac
55
56if is_active; then
57 alt="on"
58 tooltip="Stop/rotate wlsunset"
59else
60 alt="off"
61 tooltip="Start wlsunset"
62fi
63
64printf '{"alt":"%s","tooltip":"%s"}\n' "$alt" "$tooltip"
diff --git a/private_dot_local/bin/executable_waybar-vpn b/private_dot_local/bin/executable_waybar-vpn
new file mode 100644
index 0000000..02f1ec9
--- /dev/null
+++ b/private_dot_local/bin/executable_waybar-vpn
@@ -0,0 +1,7 @@
1#!/bin/sh
2
3if ip address | grep wg0 >/dev/null; then
4 echo "{ \"text\": \"🔒\", \"tooltip\": \"Stop vpn\" }"
5else
6 echo "{ \"text\": \"🔓\", \"tooltip\": \"Start vpn\" }"
7fi
diff --git a/private_dot_local/bin/executable_wine-run-with-cd b/private_dot_local/bin/executable_wine-run-with-cd
new file mode 100644
index 0000000..6bb6d49
--- /dev/null
+++ b/private_dot_local/bin/executable_wine-run-with-cd
@@ -0,0 +1,6 @@
1#!/bin/sh
2
3DIRNAME=$(dirname "$1")
4BASENAME=$(basename "$1")
5
6cd "$DIRNAME" && exec wine "$BASENAME"