aboutsummaryrefslogtreecommitdiff
path: root/.local/bin
diff options
context:
space:
mode:
Diffstat (limited to '.local/bin')
-rwxr-xr-x.local/bin/,93
-rwxr-xr-x.local/bin/audiorecord5
-rwxr-xr-x.local/bin/bashhistory37
-rwxr-xr-x.local/bin/bookmarks69
-rwxr-xr-x.local/bin/broken-links34
-rwxr-xr-x.local/bin/browser-refresh9
-rwxr-xr-x.local/bin/camera-gstream2
-rwxr-xr-x.local/bin/camera-mplayer28
-rwxr-xr-x.local/bin/clipboard4
-rwxr-xr-x.local/bin/dmenu_run_history51
-rwxr-xr-x.local/bin/dropdown-terminal22
-rwxr-xr-x.local/bin/events-idle3
-rwxr-xr-x.local/bin/events-resume (renamed from .local/bin/scripts/events-resume)0
-rwxr-xr-x.local/bin/events-usb6
-rwxr-xr-x.local/bin/file-search (renamed from .local/bin/scripts/file-search)0
-rwxr-xr-x.local/bin/fzf-doc44
-rwxr-xr-x.local/bin/fzf-file-mark10
-rwxr-xr-x.local/bin/gtk-debug8
-rwxr-xr-x.local/bin/hexmime2
-rwxr-xr-x.local/bin/internet-search2
-rwxr-xr-x.local/bin/latex-compile8
-rwxr-xr-x.local/bin/lockscreen (renamed from .local/bin/scripts/lockscreen)0
-rwxr-xr-x.local/bin/lxc-build83
-rwxr-xr-x.local/bin/manpdf9
-rwxr-xr-x.local/bin/mplayer3
-rwxr-xr-x.local/bin/nix-xorg-conf (renamed from .local/bin/scripts/nix-xorg-conf)0
-rwxr-xr-x.local/bin/nixos-test35
-rwxr-xr-x.local/bin/pass-import-csv14
-rwxr-xr-x.local/bin/pass-menu27
-rwxr-xr-x.local/bin/pdfmted-editor740
-rwxr-xr-x.local/bin/picospeaker11
-rwxr-xr-x.local/bin/plumber181
-rwxr-xr-x.local/bin/plumber-dmenu43
-rwxr-xr-x.local/bin/portmanteau38
-rwxr-xr-x.local/bin/powerdialog12
-rwxr-xr-x.local/bin/rofi-askpass12
-rwxr-xr-x.local/bin/say23
-rwxr-xr-x.local/bin/screenrecord17
-rwxr-xr-x.local/bin/scripts/amixer4
-rwxr-xr-x.local/bin/scripts/app-launcher3
-rwxr-xr-x.local/bin/scripts/app-launcher-priv3
-rwxr-xr-x.local/bin/scripts/app-launcher-terminal2
-rwxr-xr-x.local/bin/scripts/events-idle7
-rwxr-xr-x.local/bin/scripts/events-usb3
-rwxr-xr-x.local/bin/scripts/internet-search2
-rwxr-xr-x.local/bin/scripts/volume-down2
-rwxr-xr-x.local/bin/scripts/volume-mute2
-rwxr-xr-x.local/bin/scripts/volume-up2
-rwxr-xr-x.local/bin/scripts/window-switcher7
-rwxr-xr-x.local/bin/seance132
-rwxr-xr-x.local/bin/sfeed_fzf24
-rwxr-xr-x.local/bin/snipping-tool (renamed from .local/bin/scripts/snipping-tool)0
-rwxr-xr-x.local/bin/sshfs-mount (renamed from .local/bin/scripts/sshfs-mount)0
-rwxr-xr-x.local/bin/switch-monitor (renamed from .local/bin/scripts/switch-monitor)0
-rwxr-xr-x.local/bin/sx57
-rwxr-xr-x.local/bin/tidy-url2
-rwxr-xr-x.local/bin/vnc30
-rwxr-xr-x.local/bin/vnc-exit (renamed from .local/bin/scripts/vnc-exit)0
-rwxr-xr-x.local/bin/vnc-suspend (renamed from .local/bin/scripts/vnc-suspend)0
-rwxr-xr-x.local/bin/volume-control4
-rwxr-xr-x.local/bin/wget2
-rwxr-xr-x.local/bin/window-overview (renamed from .local/bin/scripts/window-overview)0
-rwxr-xr-x.local/bin/window-switcher23
-rwxr-xr-x.local/bin/workout-notify (renamed from .local/bin/scripts/workout-notify)0
-rwxr-xr-x.local/bin/wrappers/adb2
-rwxr-xr-x.local/bin/wrappers/aegisub2
-rwxr-xr-x.local/bin/wrappers/aspell2
-rwxr-xr-x.local/bin/wrappers/audacity (renamed from .local/bin/scripts/clipboard)2
-rwxr-xr-x.local/bin/wrappers/chromium13
-rwxr-xr-x.local/bin/wrappers/claws-mail3
-rwxr-xr-x.local/bin/wrappers/codium2
-rwxr-xr-x.local/bin/wrappers/eslint2
-rwxr-xr-x.local/bin/wrappers/firefox2
-rwxr-xr-x.local/bin/wrappers/ghci2
-rwxr-xr-x.local/bin/wrappers/git12
-rwxr-xr-x.local/bin/wrappers/gnaural2
-rwxr-xr-x.local/bin/wrappers/google-chrome13
-rwxr-xr-x.local/bin/wrappers/gore2
-rwxr-xr-x.local/bin/wrappers/guile2
-rwxr-xr-x.local/bin/wrappers/latexindent8
-rwxr-xr-x.local/bin/wrappers/mix2
-rwxr-xr-x.local/bin/wrappers/mocp2
-rwxr-xr-x.local/bin/wrappers/mplayer3
-rwxr-xr-x.local/bin/wrappers/nix-index16
-rwxr-xr-x.local/bin/wrappers/palemoon2
-rwxr-xr-x.local/bin/wrappers/prettier2
-rwxr-xr-x.local/bin/wrappers/sbcl2
-rwxr-xr-x.local/bin/wrappers/scribus2
-rwxr-xr-x.local/bin/wrappers/stalonetray6
-rwxr-xr-x.local/bin/wrappers/stylelint2
-rwxr-xr-x.local/bin/wrappers/svn2
-rwxr-xr-x.local/bin/wrappers/swc2
-rwxr-xr-x.local/bin/wrappers/tiemu2
-rwxr-xr-x.local/bin/wrappers/tilp2
-rwxr-xr-x.local/bin/wrappers/treesheets2
-rwxr-xr-x.local/bin/wrappers/vale (renamed from .local/bin/vale)2
-rwxr-xr-x.local/bin/wrappers/w3m2
-rwxr-xr-x.local/bin/wrappers/wget2
-rwxr-xr-x.local/bin/wrappers/xournalpp2
-rwxr-xr-x.local/bin/wrappers/xsane2
-rwxr-xr-x.local/bin/xdg-open6
-rwxr-xr-x.local/bin/xrandr-scale3
102 files changed, 1195 insertions, 940 deletions
diff --git a/.local/bin/, b/.local/bin/,
index e1ed37d..2fb22e8 100755
--- a/.local/bin/,
+++ b/.local/bin/,
@@ -4,9 +4,8 @@
program=$(basename "$0")
requires="$(command -V nix-index nix-locate nix-shell fzf | awk '{ print $1, $3 }' | column -t)"
-[ "${1:-}" = "--check" ] && printf '%s\n' "$requires" && exit;
-
-{ [ "${1:-}" = "--help" ] || [ "$#" = 0 ]; } && printf \
+help() {
+printf \
"
Usage: %s [FLAGS]... [ARGUMENT]...
@@ -15,26 +14,90 @@ packages for a file and set up a nix shell for the
program that contains that file. The shell prints
all binaries in the package upon invocation.
+Create and update the file database by running
+the nix-index command. Warning: This command uses
+up a large amount of memory.
+
+nix-index --nixpkgs https://github.com/NixOS/nixpkgs/archive/master.tar.gz
+
Command List:
$program [ARGUMENT]... Search for packages using file name argument.
$program --help Show this help menu.
$program --check Check dependencies.
-" "$program" && exit;
+" "$program"
+}
+
+[ "${1:-}" = "--check" ] && printf '%s\n' "$requires" && exit
+
+{ [ "${1:-}" = "-h" ] || [ "${1:-}" = "--help" ] || [ "$#" = 0 ]; } && help && exit
+
+databasePath=${XDG_DATA_HOME:-~/.cache}/nix-index
+nixLocate='nix-locate --db '"$databasePath"' --no-group --regex -- '"${1:-}"
+attributes=$($nixLocate | awk '{ print $1, $4 }' | sed 's|/nix/store/.[^-]*-||g')
-databasePath=${XDG_DATA_HOME:-~/.local/share}/nix-index
-nixLocate='nix-locate --db '"$databasePath"' --top-level --minimal --whole-name '"${1:-}"
-attributes=$($nixLocate | while read -r attribute; do
- attributeName=${attribute%.*};
- printf '%s\n' "$attributeName";
-done)
+[ -z "$attributes" ] && printf "No files found containing '%s'\n" "${1:-}" && exit
-attribute=$(printf '%s' "$attributes" | fzf)
-nix-shell --packages "$attribute" --command \
+option=$(printf '%s' "$attributes" | column --table | fzf)
+attribute=${option%% *}
+file=${option#*/}
+
+[ -z "$attribute" ] && exit
+
+printf '\nsetting up shell with %s path...\n' "$attribute"
+printf '\n$OUT/%s\n' "$file"
+
+nix-shell --option substituters 'https://cache.nixos.org' --packages "$attribute" fish bat toybox --command \
'
+ home=$TMPDIR/nix-shell-tmp-home.r2np9PHrby
+ program=$(printf "%s" "$buildInputs" | cut --delimiter=" " --fields=1)
+ path=$(IFS=" " && for buildInput in $buildInputs; do printf "%s/bin " "$buildInput"; done | sed "s/ /:/g")
printf "\n";
- ls $buildInputs/bin;
+ { [ -d "$program/bin" ] && ls "$program/bin"; } || printf "%s\n" "$program";
printf "\n";
- tree -L 1 $buildInputs;
- return
+ tree -L 1 "$program";
+ printf "\n";
+
+ /usr/bin/env --ignore-environment /bin/sh -c \
+ "
+ export PATH=$path
+ export DISPLAY=$DISPLAY
+ export XAUTHORITY=$XAUTHORITY
+ export TERM=$TERM
+ export TERMINFO=$TERMINFO
+ export TERMINFO_DIRS=$TERMINFO_DIRS
+ export HOME=$home
+ export OUT=$program
+ export fish_greeting=
+ mkdir --parents $home
+ cd || exit 1
+ fish --init-command=\"
+ function fish_prompt; printf '"'nix-shell@$attribute $ '"'; end
+ set -U fish_color_normal B3B1AD
+ set -U fish_color_command 39BAE6
+ set -U fish_color_quote C2D94C
+ set -U fish_color_redirection FFEE99
+ set -U fish_color_end F29668
+ set -U fish_color_error FF3333
+ set -U fish_color_param 39BAE6
+ set -U fish_color_comment 626A73
+ set -U fish_color_match F07178
+ set -U fish_color_selection E6B450
+ set -U fish_color_search_match E6B450
+ set -U fish_color_history_current --bold
+ set -U fish_color_operator E6B450
+ set -U fish_color_escape 95E6CB
+ set -U fish_color_cwd 59C2FF
+ set -U fish_color_cwd_root red
+ set -U fish_color_valid_path --underline
+ set -U fish_color_autosuggestion aaaaaa
+ set -U fish_color_user brgreen
+ set -U fish_color_host normal
+ set -U fish_color_cancel -r
+ set -U fish_pager_color_completion normal
+ set -U fish_pager_color_description B3A06D yellow
+ set -U fish_pager_color_prefix white --bold --underline
+ set -U fish_pager_color_progress brwhite --background=cyan
+ \"
+ "
';
diff --git a/.local/bin/audiorecord b/.local/bin/audiorecord
new file mode 100755
index 0000000..17f7e46
--- /dev/null
+++ b/.local/bin/audiorecord
@@ -0,0 +1,5 @@
+#!/bin/sh -eu
+directory=$HOME/Desktop/audio-recordings
+file="$(date +%I:%M:%S-%p-%A-%d-%B-%Y).mp3"
+mkdir --parents "$directory"
+ffmpeg -f alsa -i default -f alsa -i default "$directory/$file"
diff --git a/.local/bin/bashhistory b/.local/bin/bashhistory
new file mode 100755
index 0000000..98f1d33
--- /dev/null
+++ b/.local/bin/bashhistory
@@ -0,0 +1,37 @@
+#!/bin/sh -eu
+
+directory="$XDG_DATA_HOME/bash"
+persist="$directory/history"
+default="$HOME/.bash_history"
+current="$HISTFILE"
+lockfile='/tmp/bashhistory_Ri5ki9ei.lock'
+
+_prune() {
+ sed --in-place '/^#/d;/^ /d;/^\t/d;/.........../!d' "$1" && # Remove all timestamps, lines beginning with tabs/spaces, and commands less than 11 characters
+ sort --unique "$1" > "$1.tmp" && # Remove all duplicate entries.
+ mv --force "$1.tmp" "$1" > /dev/null 2>&1
+}
+
+_migrate() {
+ [ -f "$default" ] &&
+ cat "$default" >>"$persist" &&
+ _prune "$persist" &&
+ rm "$default"
+}
+
+_store() {
+ cat "$current" >> "$persist" &&
+ cat "$current" >> "$persist.bak" &&
+ _prune "$persist" &&
+ true > "$current"
+}
+
+[ -f "$lockfile" ] && exit;
+
+mkdir --parents "$directory"
+touch "$current" "$lockfile"
+
+trap 'rm "$lockfile" > /dev/null 2>&1; trap - EXIT; exit' EXIT INT HUP
+
+_migrate || true
+_store
diff --git a/.local/bin/bookmarks b/.local/bin/bookmarks
new file mode 100755
index 0000000..58ad8f5
--- /dev/null
+++ b/.local/bin/bookmarks
@@ -0,0 +1,69 @@
+#!/bin/sh -eu
+
+date=$(date +%s)
+program=$(basename "$0")
+key="QdUEdQBncNzJgIJqTA30"
+hxnormalize="hxnormalize -l 99999999 -x"
+items=/tmp/bookmarks_items_$key
+titles=/tmp/bookmarks_titles_$key
+anchors=/tmp/bookmarks_anchors_$key
+dependencies="$(command -V xmlstarlet hxnormalize paste \
+ hxselect hxincl xdg-open rofi basename \
+ | awk '{ print $1, $3 }' | column -t)"
+base=\
+"<!DOCTYPE NETSCAPE-Bookmark-file-1>
+<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\">
+<title>Bookmarks</title>
+<h1>Bookmarks</h1>
+<dl>
+<!-- include $items --></dl>
+"
+
+bookmarks_help() {
+{ [ "${1:-}" = "-h" ] || [ "${1:-}" = "--help" ] || [ "$#" = 0 ]; } && printf \
+"
+Usage: %s [FLAGS]... [ARGUMENTS]...
+
+The program $program shall execute basic operations
+on Netscape Bookmark HTML files.
+
+ Command List:
+
+ $program compile [FILES]... Combine two or more bookmark.html files.
+ $program show [FILE] Show list of bookmarks.
+ $program check Check dependencies.
+ $program -h --help Show this help menu.
+" "$program" && exit;
+printf "Error: Unknown argument '%s'.\n" "$@" && exit 1;
+}
+
+bookmarks_combine () {
+ for file in "$@"
+ do $hxnormalize "$file" | sed 's/&/&amp;/g' \
+ | xmlstarlet edit -S \
+ --delete '//a/@add_date' \
+ --delete '//a/@icon' \
+ --delete '//a/@icon_uri' \
+ --delete '//a/@last_charset' \
+ --delete '//a/@last_modified' \
+ --delete '//a/@last_modified' \
+ --delete '//a/@tags' \
+ | $hxnormalize | hxselect -i -s '\n' dt;
+ done | sort | awk '!removeDuplicates[$0]++' >> "$items";
+ printf "%s" "$base" | hxincl -f -x > "bookmarks-$date.html";
+ realpath "bookmarks-$date.html";
+}
+
+bookmarks_show () {
+ $hxnormalize "${1:-}" | hxselect -c -i -s '\n' 'a::attr(href)' > "$anchors"
+ $hxnormalize "${1:-}" | hxselect -c -i -s '\n' 'a' > "$titles"
+ xdg-open "$(paste -d' ' "$anchors" "$titles" \
+ | rofi -font "sans 12" -matching regex -padding 20 -dmenu -i -p 'Bookmarks' \
+ | awk '{ print $1 }')";
+}
+
+[ "${1:-}" = "show" ] && shift 1 && bookmarks_show "$@" && exit;
+[ "${1:-}" = "combine" ] && shift 1 && bookmarks_combine "$@" && exit;
+[ "${1:-}" = "check" ] && shift 1 && printf '%s\n' "$dependencies" && exit;
+
+bookmarks_help "$@";
diff --git a/.local/bin/broken-links b/.local/bin/broken-links
index 843f0ff..02db6a0 100755
--- a/.local/bin/broken-links
+++ b/.local/bin/broken-links
@@ -1,3 +1,33 @@
#!/bin/sh -eu
-wget --spider --recursive --level 3 --no-verbose \
- --no-directories --delete-after "$1" 2>&1 | grep -v -E 'URL:|unlink:'
+
+lynx \
+ -nocolor \
+ -dump \
+ -listonly \
+ "${1:-https://example.com}" |
+ grep \
+ --color="never" \
+ "\." |
+ while read -r line; do
+ url=${line#*. }
+ head=$(wget \
+ --user-agent "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.74 Safari/537.36" \
+ --timeout=1 \
+ --wait=1 \
+ --waitretry=1 \
+ --random-wait \
+ --no-cache \
+ --no-dns-cache \
+ --method=HEAD "$url" 2>&1 |
+ grep --color="never" -E 'HTTP')
+ response=$(printf '%s' "${head#*... }" | head --lines=1)
+ printf '%s %s\n' "$url" "$response"
+ printf '%s %s\n' "$url" "$response" >&2
+ done |
+ awk '{ print $1, $2, $3}' |
+ column \
+ --output-width 80 \
+ --table \
+ --table-columns URL,STATUS,MESSAGE \
+ --table-truncate URL |
+ sort --reverse --key=2
diff --git a/.local/bin/browser-refresh b/.local/bin/browser-refresh
index c1410c4..a882f9d 100755
--- a/.local/bin/browser-refresh
+++ b/.local/bin/browser-refresh
@@ -1,8 +1,5 @@
#!/usr/bin/env bash
-# set keyboard
-keyboard=10
-
# set target browser and title
browser=$1
title=$2
@@ -37,9 +34,6 @@ xdotool windowactivate $target_window;
# declare the variable i as an interger
declare -i i=0;
-# disable keyboard at the start of search
-xinput --disable $keyboard;
-
while true; do
# bail out if there are too many searches
@@ -96,7 +90,4 @@ while true; do
done
-# enable keyboard at the end of the search
-xinput --enable $keyboard;
-
exit 0;
diff --git a/.local/bin/camera-gstream b/.local/bin/camera-gstream
new file mode 100755
index 0000000..3b54380
--- /dev/null
+++ b/.local/bin/camera-gstream
@@ -0,0 +1,2 @@
+#!/bin/sh -eu
+gst-launch-1.0 -v v4l2src device=/dev/video0 ! glimagesink
diff --git a/.local/bin/camera-mplayer b/.local/bin/camera-mplayer
new file mode 100755
index 0000000..73f592f
--- /dev/null
+++ b/.local/bin/camera-mplayer
@@ -0,0 +1,28 @@
+#!/bin/sh -eu
+
+program=$(basename "$0")
+option=${1:-0@9}
+real=${option%%@*}
+virtual=${option#*@}
+
+{
+ [ "$option" = "help" ] ||
+ [ "$option" = "-help" ] ||
+ [ "$option" = "--help" ]
+} &&
+ printf '%s 0@9\n# /dev/video0 -> /dev/video9\n' "$program" &&
+ exit
+
+{
+ [ "$option" = "kill" ] ||
+ [ "$option" = "-kill" ] ||
+ [ "$option" = "--kill" ]
+} &&
+ killall mplayer &&
+ killall mplayer &&
+ killall ffmpeg &&
+ exit
+
+ffmpeg -i "/dev/video$real" -f v4l2 -vcodec rawvideo -pix_fmt rgb24 "/dev/video$virtual" &
+sleep 2
+mplayer tv:// -tv "driver=v4l2:device=/dev/video$virtual" -fps 15
diff --git a/.local/bin/clipboard b/.local/bin/clipboard
new file mode 100755
index 0000000..298d1e3
--- /dev/null
+++ b/.local/bin/clipboard
@@ -0,0 +1,4 @@
+#!/bin/sh -eu
+
+pgrep --full "scratchpad.md" && pkill --oldest --full "scratchpad.md" && exit
+$TERMINAL -e vim ~/Documents/notes/scratchpad.md
diff --git a/.local/bin/dmenu_run_history b/.local/bin/dmenu_run_history
index c6a7372..ba9b2af 100755
--- a/.local/bin/dmenu_run_history
+++ b/.local/bin/dmenu_run_history
@@ -1,27 +1,31 @@
#!/bin/sh
-[ "$1" = "privilege" ] && export cmd_prefix='sudo -A ' && export dmenu_args='-p Privilege -sb red' && shift 1;
-[ "$1" = "terminal" ] && export cmd_prefix='urxvt -hold -e ' && export dmenu_args='-p Terminal -sb gray' && shift 1;
-
# https://tools.suckless.org/dmenu/scripts/
+[ "$1" = "privilege" ] &&
+ export cmd_prefix='rofi-askpass ' &&
+ export dmenu_args='-nhf #ff7070 -sf #ff7070 -p ⠀:::⠀privilege⠀:::' &&
+ shift 1
+
+[ "$1" = "terminal" ] &&
+ export cmd_prefix='urxvt -hold -e ' &&
+ export dmenu_args='-nhf #9e9e9e -sf #9e9e9e -p ⠀:::⠀terminal⠀:::' &&
+ shift 1
+
cachedir=${XDG_CACHE_HOME:-"$HOME/.cache"}
-if [ -d "$cachedir" ]; then
- cache=$cachedir/dmenu_run
- historyfile=$XDG_DATA_HOME/dmenu_history
-else
- cache=$HOME/.dmenu_cache
- historyfile=$HOME/.dmenu_history
-fi
-
-if [ "$1" = "update" ] || [ ! -f "$cache" ]; then
- IFS=:
- stest -dqr -n "$cache" $PATH && stest -flx $PATH | sort -u > "$cache";
- unset IFS;
- exit;
-fi
-
-awk -v histfile=$historyfile '
+cache=$cachedir/dmenu_run
+historyfile=$XDG_DATA_HOME/dmenu_history
+mkdir --parents "$cachedir"
+
+update() {
+ IFS=:
+ stest -flx $PATH | sort -u >"$cache"
+ unset IFS
+}
+
+[ ! -f "$cache" ] && update
+
+awk -v histfile="$historyfile" '
BEGIN {
while( (getline < histfile) > 0 ) {
sub("^[0-9]+\t","")
@@ -29,8 +33,8 @@ awk -v histfile=$historyfile '
x[$0]=1
}
} !x[$0]++ ' "$cache" \
- | dmenu -b ${dmenu_args:--p Launch} "$@" \
- | awk -v histfile=$historyfile '
+ | dmenu -i -b ${dmenu_args:--p ⠀:::⠀execute⠀:::} "$@" \
+ | awk -v histfile="$historyfile" '
BEGIN {
FS=OFS="\t"
while ( (getline < histfile) > 0 ) {
@@ -52,5 +56,6 @@ awk -v histfile=$historyfile '
for (f in history)
print history[f],f | "sort -t '\t' -k1rn >" histfile
}
- ' \
- | while read -r cmd; do ${SHELL:-"/bin/sh"} -c "$cmd_prefix $cmd" & done
+ ' | while read -r cmd; do ${SHELL:-"/bin/sh"} -c "$cmd_prefix $cmd" & done
+
+update
diff --git a/.local/bin/dropdown-terminal b/.local/bin/dropdown-terminal
new file mode 100755
index 0000000..a41ad46
--- /dev/null
+++ b/.local/bin/dropdown-terminal
@@ -0,0 +1,22 @@
+#!/bin/sh -eu
+name=dropdown-terminal
+state=/tmp/"$name"_lQ5GnvRpQ6
+terminal="urxvt -geometry 150x20 -title $name"
+
+[ ! -f $state ] && {
+ $terminal && sed --in-place '1s/.*/1/' "$state" &
+ touch $state && exit;
+}
+
+options=$(grep --count . $state || true)
+[ "$options" != "1" ] && { printf '1\n' > $state; }
+
+pid=$(pgrep --full "title $name" | head --lines 1)
+[ -z "$pid" ] && rm $state && "$0" && exit;
+
+window=$(wmctrl -lpGx | awk "/$pid/"'{ print $1 }')
+[ -z "$window" ] && rm "$state" && "$0" && exit;
+
+visible=$(awk 'NR==1 { print; exit }' $state)
+[ "$visible" = 0 ] && wmctrl -i -u -R "$window" && wmctrl -i -u -r "$window" -b add,above && sed --in-place '1s/.*/1/' "$state" && exit;
+[ "$visible" = 1 ] && xdotool mousemove_relative 0 1 && wmctrl -i -u -r "$window" -b add,skip_taskbar,hidden && sed --in-place '1s/.*/0/' "$state" && exit;
diff --git a/.local/bin/events-idle b/.local/bin/events-idle
new file mode 100755
index 0000000..ff489eb
--- /dev/null
+++ b/.local/bin/events-idle
@@ -0,0 +1,3 @@
+#!/bin/sh -eux
+
+file-search update
diff --git a/.local/bin/scripts/events-resume b/.local/bin/events-resume
index 50ffd2c..50ffd2c 100755
--- a/.local/bin/scripts/events-resume
+++ b/.local/bin/events-resume
diff --git a/.local/bin/events-usb b/.local/bin/events-usb
new file mode 100755
index 0000000..32d5823
--- /dev/null
+++ b/.local/bin/events-usb
@@ -0,0 +1,6 @@
+#!/bin/sh -eux
+
+xmodmap "$HOME/.config/X11/Xmodmap"
+xset r rate 200 60
+[ "$(xset -q | awk '/Caps Lock/ { print $4 }')" = "on" ] \
+ && xdotool key Caps_Lock
diff --git a/.local/bin/scripts/file-search b/.local/bin/file-search
index 130b90c..130b90c 100755
--- a/.local/bin/scripts/file-search
+++ b/.local/bin/file-search
diff --git a/.local/bin/fzf-doc b/.local/bin/fzf-doc
deleted file mode 100755
index 6f51c08..0000000
--- a/.local/bin/fzf-doc
+++ /dev/null
@@ -1,44 +0,0 @@
-#!/bin/sh -eu
-
-cache=$HOME/.cache/fzf-doc
-documentation=/etc/documentation
-
-fzf_doc_preview() {
- file=$1
- extension=${file##*.}
- case "$extension" in
- md) mdcat -l "$file" ;;
- html) w3m -dump "$file" ;;
- pdf) pdftotext "$file" - ;;
- *) grep -hi -B 10 -A 10 . "${file}" ;;
- esac
-}
-
-if [ ! -f "$cache" ] || test "$cache" -ot "$documentation"; then
- grep -lRi \
- --include=*.md \
- --include=*.txt \
- --include=*.pdf \
- --include=*.html \
- --include=*.yml \
- --include=*.yaml \
- . /etc/documentation > "$cache";
-fi
-
-[ "${1-}" = "--preview" ] && fzf_doc_preview "${2-}" && exit;
-
-grep -i "${1-.}" "$cache" \
- | fzf --preview "fzf-doc --preview {}" \
- | while read -r file
-
-do
- extension=${file##*.}
- case "$extension" in
- md) mdcat -cl "$file" | vim - ;;
- html) w3m -dump "$file" | vim - ;;
- pdf) pdftotext "$file" - | vim - ;;
- yml) vim "$file" ;;
- yaml) vim "$file" ;;
- *) vim "$file" ;;
- esac
-done
diff --git a/.local/bin/fzf-file-mark b/.local/bin/fzf-file-mark
index 94c2bf8..9f6efad 100755
--- a/.local/bin/fzf-file-mark
+++ b/.local/bin/fzf-file-mark
@@ -1,11 +1,9 @@
-#!/bin/sh
+#!/bin/sh -eu
+
file=$FZF_FILE_MARKS
-temp=/tmp/.fzf-fmarks.tmp
+temp=/tmp/fzf-fmarks-Ei0Ohcah.tmp
realpath "$1" && realpath "$1" >> "$file";
sed -i "s|$HOME|~|g" "$file";
-awk '!visited[$0]++' "$file" > "$temp" \
- && sort "$temp" > "$file";
-
-rm -f "$temp";
+awk '!visited[$0]++' "$file" > "$temp" && sort "$temp" > "$file";
diff --git a/.local/bin/gtk-debug b/.local/bin/gtk-debug
new file mode 100755
index 0000000..0005bcd
--- /dev/null
+++ b/.local/bin/gtk-debug
@@ -0,0 +1,8 @@
+#!/bin/sh -eu
+program=$(basename "$0")
+
+{ [ "${1:-}" = "-h" ] || [ "${1:-}" = "--help" ] || [ "$#" = 0 ]; } &&
+ printf "Usage: %s [COMMAND]...\n" "$program" &&
+ exit
+
+GTK_DEBUG=interactive $1
diff --git a/.local/bin/hexmime b/.local/bin/hexmime
new file mode 100755
index 0000000..ac808fa
--- /dev/null
+++ b/.local/bin/hexmime
@@ -0,0 +1,2 @@
+#!/bin/sh -eu
+mimeo --mimetype "$1" && hexyl --length 196 "$1" && cat
diff --git a/.local/bin/internet-search b/.local/bin/internet-search
new file mode 100755
index 0000000..0a3d0cd
--- /dev/null
+++ b/.local/bin/internet-search
@@ -0,0 +1,2 @@
+#!/bin/sh -eu
+rofi -dmenu -i -font "ubuntu 16" -theme-str 'listview { lines: 0; }' -p " " | xargs -r surfraw duckduckgo
diff --git a/.local/bin/latex-compile b/.local/bin/latex-compile
index 9717db0..25f92b6 100755
--- a/.local/bin/latex-compile
+++ b/.local/bin/latex-compile
@@ -1,8 +1,8 @@
#!/bin/sh -eu
if ! {
- pdflatex -halt-on-error "$1" \
- || xelatex -halt-on-error "$1";
- }
-then cat
+ pdflatex -shell-escape -halt-on-error "$1" ||
+ xelatex -shell-escape -halt-on-error "$1"
+}; then
+ cat
fi
diff --git a/.local/bin/scripts/lockscreen b/.local/bin/lockscreen
index bd456c2..bd456c2 100755
--- a/.local/bin/scripts/lockscreen
+++ b/.local/bin/lockscreen
diff --git a/.local/bin/lxc-build b/.local/bin/lxc-build
new file mode 100755
index 0000000..9e6b5eb
--- /dev/null
+++ b/.local/bin/lxc-build
@@ -0,0 +1,83 @@
+#!/usr/bin/env runhaskell
+
+import System.Console.GetOpt
+import System.Environment
+import System.Exit
+import System.Process
+
+version :: Fractional p => p
+version = 0.01
+
+help :: [Char]
+help = unlines
+ [ ""
+ , "NAME"
+ , ""
+ , " lxc-build"
+ , ""
+ , "SYNOPSIS"
+ , ""
+ , " Replace a container of the same name with the new build"
+ , ""
+ , " lxc-build --replace --name rockylinux rockylinux8.dockerfile"
+ , ""
+ , "DESCRIPTION"
+ , ""
+ , " Builds a lxc container from a Dockerfile"
+ , ""
+ , "COMMANDS"
+ , ""
+ , " -h, -help, --help Shows this help menu"
+ , " -r, -replace, --replace Replace container with new build"
+ , " -v, -version, --version Prints program version"
+ ]
+
+display = putStrLn
+
+main = do
+ arguments <- getArgs
+ case arguments of
+ ["--replace", "--name", name, dockerfile] -> do
+ callCommand ("\\lxc-destroy --force --name " ++ name ++ " |& \\true")
+ callCommand
+ ( "\\lxc-create --name "
+ ++ name
+ ++ " --template=none && \\mkdir ~/.local/share/lxc/"
+ ++ name
+ ++ "/rootfs"
+ )
+ callCommand ("\\docker build --file " ++ dockerfile)
+ callCommand
+ ( "id=$(\\docker run --detach \"$(\\docker build --file "
+ ++ dockerfile
+ ++ " | tail --lines=1)\" /bin/true) && \\docker export \"$id\" | \\tar --extract --directory ~/.local/share/lxc/"
+ ++ name
+ ++ "/rootfs && \\docker container rm \"$id\""
+ )
+ callCommand
+ ( "\\printf 'doas chown --recursive 200000:200000 ~/.local/share/lxc/"
+ ++ name
+ ++ "/rootfs\n'"
+ )
+ callCommand
+ ( "\\doas chown --recursive 200000:200000 ~/.local/share/lxc/"
+ ++ name
+ ++ "/rootfs"
+ )
+ callCommand
+ ( "\\printf 'lxc.uts.name = "
+ ++ name
+ ++ "\n' >> ~/.local/share/lxc/"
+ ++ name
+ ++ "/config"
+ )
+ callCommand
+ ( "\\printf \"lxc.rootfs.path = dir:$HOME/.local/share/lxc/"
+ ++ name
+ ++ "/rootfs\n\" >> ~/.local/share/lxc/"
+ ++ name
+ ++ "/config"
+ )
+ callCommand ("\\lxc-start --name " ++ name)
+ _ -> do
+ die help
diff --git a/.local/bin/manpdf b/.local/bin/manpdf
index 349f9b4..6fefd44 100755
--- a/.local/bin/manpdf
+++ b/.local/bin/manpdf
@@ -1,2 +1,7 @@
-#!/bin/sh
-man -k . | dmenu -b | awk '{ print $1 }' | xargs -r man -Tpdf | zathura -
+#!/bin/sh -eu
+
+man -k . |
+ rofi -font "ubuntu 12" -matching regex -padding 20 -dmenu -i -p 'Manuals' |
+ awk '{ print $1 }' |
+ xargs -r man -Tpdf |
+ zathura -
diff --git a/.local/bin/mplayer b/.local/bin/mplayer
deleted file mode 100755
index 0598484..0000000
--- a/.local/bin/mplayer
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/sh -eu
-export MPLAYER_HOME="$XDG_CONFIG_HOME/mplayer"
-$(which mplayer --all | grep -v "local/bin" | head -n 1) "$@"
diff --git a/.local/bin/scripts/nix-xorg-conf b/.local/bin/nix-xorg-conf
index 7fabd3a..7fabd3a 100755
--- a/.local/bin/scripts/nix-xorg-conf
+++ b/.local/bin/nix-xorg-conf
diff --git a/.local/bin/nixos-test b/.local/bin/nixos-test
new file mode 100755
index 0000000..1fedf89
--- /dev/null
+++ b/.local/bin/nixos-test
@@ -0,0 +1,35 @@
+#!/bin/sh -eu
+
+# nix-shell -i dash -p dash gawk moreutils nixos-rebuild nixfmt
+
+{ [ "${1:-}" = "-h" ] ||
+ [ "${1:-}" = "--help" ] ||
+ [ "$#" = 0 ]; } &&
+ printf "nixos-test [FILE]...\n" &&
+ exit
+
+for configuration in "$@"; do
+
+ [ -f "$configuration" ] || { printf "Error: File '%s' not found\n" "$configuration" && exit; }
+
+ cp "$configuration" "$configuration.bak"
+
+ trap 'for configuration in "$@"; do mv "$configuration.bak" "$configuration"; done; trap - EXIT; exit' EXIT INT HUP
+
+ nixfmt "$configuration"
+
+ awk '!s {s=sub("^{$","{ boot.isContainer = true;")}{ print $0 }' "$configuration" | sponge "$configuration"
+ awk '!s {s=sub("}: {","}: { boot.isContainer = true;")}{ print $0 }' "$configuration" | sponge "$configuration"
+ awk '!s {s=sub("^in {$","in { boot.isContainer = true;")}{ print $0 }' "$configuration" | sponge "$configuration"
+
+ printf '%s ' "$configuration";
+
+ NIXOS_CONFIG=$(realpath "$configuration")
+
+ export NIXOS_CONFIG \
+ NIXPKGS_ALLOW_UNFREE=1 \
+ NIXPKGS_ALLOW_UNSUPPORTED_SYSTEM=1
+
+ nixos-rebuild --fast --option substituters 'https://cache.nixos.org' --option builders '' dry-build
+
+done;
diff --git a/.local/bin/pass-import-csv b/.local/bin/pass-import-csv
new file mode 100755
index 0000000..7682657
--- /dev/null
+++ b/.local/bin/pass-import-csv
@@ -0,0 +1,14 @@
+#!/bin/sh -eu
+
+csv_file="$HOME/.cache/k.csv"
+import_directory="$HOME/.config/pass";
+target_directory="$import_directory/secrets";
+
+{ [ "${1:-}" = "-h" ] || [ "${1:-}" = "--help" ] || [ "$#" = 0 ]; } && printf 'Usage: %s /path/to/keepassxc/database\n' "$(basename "$0")" && exit
+
+keepassxc-cli export --format csv "$1" > "$csv_file"
+rm --recursive --force "${import_directory:?}"/*;
+pass import "$csv_file";
+rsync --verbose --archive "$target_directory/" "$import_directory";
+rm --recursive "$target_directory";
+rm --verbose "$csv_file";
diff --git a/.local/bin/pass-menu b/.local/bin/pass-menu
new file mode 100755
index 0000000..7f0a306
--- /dev/null
+++ b/.local/bin/pass-menu
@@ -0,0 +1,27 @@
+#!/usr/bin/env bash
+# LICENSE: GPLv2+
+# https://git.zx2c4.com/password-store/tree/contrib/dmenu/passmenu
+
+set -eo pipefail
+shopt -s nullglob globstar
+
+printf "\n" | $copy
+
+copy='xsel --input --primary'
+menu='dmenu -f -i -b -nhf #ffeb3b -sf #ffeb3b -p ⠀:::⠀passwords⠀:::'
+_paste () { xdotool type "$(xsel --output --primary)"; }
+
+prefix=${PASSWORD_STORE_DIR-~/.password-store}
+password_files=("$prefix"/**/*.gpg )
+password_files=("${password_files[@]#"$prefix"/}")
+password_files=("${password_files[@]%.gpg}")
+password=$(printf '%s\n' "${password_files[@]}" | $menu)
+
+[ -n "$password" ] || exit
+
+{ pass show "$password" 2>/dev/null | $copy && _paste; } ||
+{ notify-send --urgency=critical --expire-time=5000 "Failed to copy $password to primary clipboard." && exit 1; }
+
+printf "\n" | $copy
+
+notify-send "Copied $password to primary clipboard."
diff --git a/.local/bin/pdfmted-editor b/.local/bin/pdfmted-editor
deleted file mode 100755
index e9274e4..0000000
--- a/.local/bin/pdfmted-editor
+++ /dev/null
@@ -1,740 +0,0 @@
-#!/usr/bin/env bash
-
-# NAME: PDFMtEd – Editor
-# VERSION: 0.1
-# AUTHOR: (c) 2014 Glutanimate
-# DEPENDENCIES: yad exiftool python2.7 (sejda-pdf) (qpdf)
-#
-# DESCRIPTION: View and edit PDF metadata using exiftool.
-#
-# LICENSE: GNU GPLv3 (http://www.gnu.de/documents/gpl-3.0.en.html)
-#
-# NOTICE: THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
-# EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-# PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR
-# IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
-# AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND
-# PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE,
-# YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-#
-# IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY
-# COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS
-# PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL,
-# INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
-# THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED
-# INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE
-# PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER
-# PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
-#
-# USAGE: pdfmted_editor [-r|-u] <file(s) or directory(ies)>
-
-################ GLOBVAR #################
-
-EXECUTABLE="$(readlink -f "$0")"
-PROGDIR="${EXECUTABLE%/*}"
-THUMBNAILER="$PROGDIR/pdfmted-thumbnailer.py"
-TMPDIR="/tmp/${0##*/}"
-
-############### SETTINGS #################
-
-# Supply password for protected PDF files
-PASSWORD=""
-# Rename modified files by default?
-RENAME_OPT="FALSE"
-
-############## DIALOGS #################
-
-# Usage message
-
-USAGE="
-Usage: $(basename "$0") [-r|-u|-h] <PDF Files/Directories>
-
- Title: PDFMtEd – Editor
- Author: (c) 2014 Glutanimate
- Description: View and edit PDF metadata
- Arguments: This script accepts multiple PDF files and
- directories as input.
-
-Available options:
- -r rename files by default
- -u arguments are URIs
- -h display this help message\
-"
-
-# General settings
-
-YAD_TITLE="PDFMtEd – Editor"
-WMCLASS="pdfmtededitor"
-ICON="application-pdf"
-WIDTH="800"
-HEIGHT="650"
-PROGWIDTH="400"
-PROGHEIGHT="100"
-
-# Descriptions and tooltips
-
-TEXT_INFO_DEPERR="Error: Missing dependencies. Please install the \
-following:"
-
-TEXT_MAIN_DESCRP="\
-<b>Important note</b>:
-
-Empty fields will <b>delete</b> the associated metadata. \
-However, modifications performed by exiftool are <b>reversible</b>. \
-To purge the file of all metadata please use PDFMtEd – Inspector
-"
-
-TEXT_CHCK_SAVECH="Save changes, file will be skipped if unchecked"
-TEXT_CHCK_RENMFL="Rename based on tags"
-TEXT_CHCK_DUPLIC="Copy tags over to next/previous file"
-
-TEXT_HOVR_CANCEL="Cancel and exit"
-TEXT_HOVR_FNNISH="Save (if option selected) and exit"
-TEXT_HOVR_PREVIT="Move back to previous document"
-TEXT_HOVR_NEXTIT="Move to next document in line"
-
-TEXT_BTTN_PDFVWR="_Open in PDF viewer"
-TEXT_HOVR_PDFVWR="Open document with default PDF viewer"
-
-TEXT_BTTN_SHWFLD="Show in parent _directory"
-TEXT_HOVR_SHWFLD="Open parent directory with default file manager"
-
-TEXT_BTTN_CLRALL="C_lear all"
-TEXT_HOVR_CLRALL="Clear all fields"
-
-TEXT_INFO_WARNG1="Something went wrong while writing the metadata. Processing the document with \
-sejda (recommended) or linearizing it with qpdf helps in these cases. Want to proceed?"
-TEXT_NOTI_SUCCE1="Metadata succesfully updated."
-TEXT_NOTI_ERROR1="Post-processing failed."
-
-############## FUNCTIONS #################
-
-# dependencies
-
-check_deps() {
- for i in "$@"; do
- type "$i" > /dev/null 2>&1
- if [[ "$?" != "0" ]]; then
- MISSINGDEPS+=" $i"
- fi
- done
-}
-
-gui_check_deps(){
- check_deps yad exiftool python2.7
- if [[ -n "$MISSINGDEPS" ]]; then
- gui_show_error "${TEXT_INFO_DEPERR}
- ${MISSINGDEPS}"
- exit 1
- fi
-}
-
-# cleanup
-
-var_unset(){
- unset -v KEYWORDS SUBJECT AUTHOR TITLE_FN UPDATED_NAME
-}
-
-cleanup(){
- [[ -n "$TMPDIR" && -d "$TMPDIR" ]] && rm -r "$TMPDIR"
-}
-
-# evaluate and check arguments
-
-arg_evaluate_options(){
- # grab options if present
- while getopts "ruh" OPTIONS; do
- case $OPTIONS in
- r ) RENAME_OPT="TRUE"
- ;;
- u ) URI_OPT="TRUE"
- ;;
- h ) echo "$USAGE"
- exit 0
- ;;
- \? ) echo "$USAGE"
- exit 1
- ;;
- esac
- done
-}
-
-arg_check_correct(){
- # check if arguments aside from options given
- if [[ "$#" = "0" ]]
- then
- error_log 1
- fi
-
- # check if arguments are files or folders
- for ITEM in "$@"; do
- if [[ ! -d "$ITEM" && ! -f "$ITEM" ]]
- then
- error_log 3
- fi
- done
-
- # notify user and exit
- if [[ "$ARGERROR" = "1" ]]
- then
- gui_show_error "ERROR: No files/folder selected."
- echo "Exiting..."
- exit 1
- fi
-}
-
-arg_uri_to_path(){
- # handle cases where we have to use "pseudo-uris"
- cnt=0
- FILEARGS=()
- for URI in "$@"; do
- # only handles file:// prefix
- # for other uri-specific substitutions we would have to
- # use python+gio-bindings
- FILEARGS[$cnt]="$(echo "$URI" | sed "s/^file:\/\///g")"
- ((cnt++))
- done
-}
-
-arg_compose_filearray(){
- # recursively add pdf files and folders in given arguments to array
- unset ARGS
- ARGID="1" # start array at 1
- while IFS= read -r -d $'\0' FILE; do
- if [[ ! "$(file -ib "$FILE")" == *application/pdf* ]]
- then
- echo "Error: '$FILE' is not a pdf file. Ignoring."
- continue
- fi
- ARGS[ARGID++]="$FILE"
- done < <(find "$@" -type f -name '*.pdf' -print0 | sort -z --version-sort)
- # numerical-composite (e.g. 1.1<1.2), zero-delimited sorting
- ARGSTOTAL="${#ARGS[@]}"
- ARGID="1"
- if [[ "$ARGSTOTAL" = "0" ]]; then
- gui_show_error "ERROR: No PDF files found."
- echo "Exiting..."
- exit 1
- fi
-}
-
-# Error handling
-
-error_log(){
- if [[ "$1" = "1" ]]; then
- ARGERROR="1"
- echo "ARG ERROR: insufficient arguments given."
- elif [[ "$1" = "2" ]]; then
- ARGERROR="1"
- echo "ARG ERROR: illegal arguments ('$ITEM' is not a file or directory.)"
- elif [[ "$1" = "3" ]]; then
- WRITEERROR="1"
- echo "WRITE ERROR: File not updated. Likely an issue with exiftool"
- elif [[ "$1" = "5" ]]; then
- PSTPRCERROR="1"
- echo "POST PROCESSING ERROR: qpdf/sejda failed."
- fi
-}
-
-# Set up environment
-
-setup_filevars(){
- FILE="$(readlink -f "$1")"
- FILE_ESCAPED="${FILE//%/%%}"
- FILENAME="${FILE##*/}"
- BASENAME="${FILENAME%.*}"
- DIRNAME="${FILE%/*}"
- DIRNAME_ESCAPED="${FILE_ESCAPED%/*}"
- PREV_FILE="${ARGS[$ARGID-1]}"
- NEXT_FILE="${ARGS[$ARGID+1]}"
- PREV_FILENAME="${PREV_FILE##*/}"
- NEXT_FILENAME="${NEXT_FILE##*/}"
-}
-
-# Set up GUI
-
-setup_geometry(){
- GEOMETRYOPTS=("--center" "--height=$HEIGHT" "--width=$WIDTH")
- PROGGEO=("--center" "--height=$PROGHEIGHT" "--width=$PROGWIDTH")
-}
-
-setup_gui(){
- MULTIDOC_TITLE="$YAD_TITLE ($ARGID/$ARGSTOTAL)"
- # we are using arrays to construct and modify YAD dialogs
- # multiple documents - show all elements
- if [[ "$MULTIDOC" = "middle" ]]
- then
- MULTIDOC_FIELDS=(\
- --field="$TEXT_CHCK_DUPLIC":CHK "FALSE" \
- --field="<b>Previous Document</b>:":RO "$PREV_FILENAME" \
- --field="<b>Next Document</b>:":RO "$NEXT_FILENAME")
- MULTIDOC_BUTTONS=(--button="_Previous!go-previous!$TEXT_HOVR_PREVIT:1" \
- --button="_Next!go-next!$TEXT_HOVR_NEXTIT:2")
- # multiple documents, first doc - hide previous
- elif [[ "$MULTIDOC" = "first" ]]
- then
- MULTIDOC_FIELDS=(\
- --field="$TEXT_CHCK_DUPLIC":CHK "FALSE" \
- --field="<b>Next Document</b>:":RO "$NEXT_FILENAME" )
- MULTIDOC_BUTTONS=(--button="_Next!go-next!$TEXT_HOVR_NEXTIT:2")
- # multiple documents, last doc - hide next
- elif [[ "$MULTIDOC" = "last" ]]
- then
- MULTIDOC_FIELDS=(\
- --field="$TEXT_CHCK_DUPLIC":CHK "FALSE" \
- --field="<b>Previous Document</b>:":RO "$PREV_FILENAME")
- MULTIDOC_BUTTONS=(--button="_Previous!go-previous!$TEXT_HOVR_PREVIT:1")
- # single document - hide all elements
- elif [[ "$MULTIDOC" = "single" ]]
- then
- HEIGHT="620"
- MULTIDOC_FIELDS=()
- MULTIDOC_BUTTONS=()
- fi
- setup_geometry
-}
-
-# GUIs
-
-gui_notify(){
- notify-send -i "$NOTIFY_ICON" "$YAD_TITLE" "$1"
-}
-
-gui_progress(){
- # ampersands in gui elements cause issues in gtk/pango markup
- BASENAME_PANGO="$(echo "$BASENAME" | sed 's/\&/\&amp;/g')"
- yad --progress --pulsate --auto-close \
- "${PROGGEO[@]}" \
- --image="$ICON" --window-icon="$ICON" \
- --class="$WMCLASS" \
- --title="$YAD_TITLE" \
- --text="Processing <b>$BASENAME_PANGO</b> ..." \
- --button='_Cancel!gtk-cancel!':1 \
- 2> /dev/null
- PROG_RET="$?"
- if [[ "$PROG_RET" != "0" ]]
- then
- kill -s TERM "$TOP_PID"
- fi
-}
-
-gui_show_error(){
- yad --title="$YAD_TITLE" \
- --center --width="400" --height="100" \
- --image=dialog-error \
- --window-icon=dialog-error \
- --class="$WMCLASS" \
- --text="$1" \
- --button="OK":0 2> /dev/null
- echo "$1"
-}
-
-gui_metadata_entry_multi(){
- NEW_METADATA="$( \
- yad --form --scroll \
- --always-print-result \
- "${GEOMETRYOPTS[@]}" \
- --image="$IMAGE" --window-icon="$ICON" \
- --class="$WMCLASS" \
- --title="$MULTIDOC_TITLE" \
- --buttons-layout=end \
- --button="_Cancel!gtk-cancel!$TEXT_HOVR_CANCEL:33" \
- "${MULTIDOC_BUTTONS[@]}" \
- --button="_Finish!gtk-ok!$TEXT_HOVR_FNNISH:3" \
- --field="<b>Current Document</b>:":RO "$FILENAME"\
- --field="":LBL "" \
- --field="$TEXT_MAIN_DESCRP":LBL "" \
- --field="Author:" "$AUTHOR_ORIGINAL" \
- --field="Title:" "$TITLE_ORIGINAL" \
- --field="Year:":NUM "$YEAR_ORIGINAL[!0..3000[!1]]" \
- --field="Keywords:" "$KEYWORDS_ORIGINAL" \
- --field="Subject:" "$SUBJECT_ORIGINAL" \
- --field "$TEXT_BTTN_CLRALL!gtk-clear!$TEXT_HOVR_CLRALL":FBTN \
- "@bash -c gui_clear_fields" \
- --field="":LBL "" \
- --field="$TEXT_BTTN_PDFVWR!application-pdf!$TEXT_HOVR_PDFVWR:FBTN" \
- "bash -c \"gui_open '$FILE_ESCAPED'\"" \
- --field="$TEXT_BTTN_SHWFLD!folder!$TEXT_HOVR_SHWFLD:FBTN" \
- "bash -c \"gui_open '$DIRNAME_ESCAPED'\"" \
- --field="":LBL "" \
- --field="$TEXT_CHCK_SAVECH":CHK "TRUE" \
- --field="$TEXT_CHCK_RENMFL":CHK "$RENAME_OPT" \
- "${MULTIDOC_FIELDS[@]}" \
- 2> /dev/null)"
- RET_MAIN=$?
- if [[ "$RET_MAIN" = 1 ]]
- then
- PROGRESSION="PREVIOUS"
- elif [[ "$RET_MAIN" = 2 ]]
- then
- PROGRESSION="NEXT"
- elif [[ "$RET_MAIN" = 3 ]]
- then
- PROGRESSION="FINISH"
- else
- echo "Aborted."
- exit 1
- fi
-}
-
-gui_postprocess_pdf(){
- yad --title="$YAD_TITLE" \
- --center --width="400" --height="100" \
- --image=dialog-error \
- --window-icon=dialog-error \
- --class="$WMCLASS" \
- --text="$TEXT_INFO_WARNG1" \
- --button="_Process with Sejda!gtk-ok!$TEXT_HOVR_PSTPRC_SEJ:0" \
- --button="_Linearize!gtk-ok!$TEXT_HOVR_PSTPRC_LIN:2" \
- --button="_Cancel!gtk-cancel!$TEXT_HOVR_PSTPRC_CANCEL:1"
- RET_PSTPRC="$?"
- if [[ "$RET_PSTPRC" = "0" ]]; then
- if ! type sejda-console > /dev/null 2>&1; then
- gui_show_error "Error: Sejda not installed."
- gui_postprocess_pdf
- return
- fi
- sejda_process_pdf | gui_progress
- check_modify_success
- error_recheck_write
- elif [[ "$RET_PSTPRC" = "2" ]]; then
- if ! type qpdf > /dev/null 2>&1; then
- gui_show_error "Error: qpdf not installed."
- gui_postprocess_pdf
- return
- fi
- linearize_pdf | gui_progress
- check_modify_success
- error_recheck_write
- else
- return 1
- fi
-}
-
-
-# GUI extensions
-
-# create thumbnail
-gui_thumbnail_generate() {
- if [[ -f "$THUMBNAILER" ]]; then
- echo "#Generating preview..."
- $THUMBNAILER "$FILE" > /dev/null 2>&1
- fi
-}
-
-# assign thumbnail
-gui_thumbnail_assign(){
-
- PREVIEWIMG="$(python2.7 -c "import gio; import sys; \
- print gio.File(sys.argv[1]).query_info('*').get_attribute_byte_string \
- ('''thumbnail::path''')" "$FILE")"
-
- if [[ "$(file -ib "$FILE" | cut -d';' -f1)" != "application/pdf" || ! -f "$PREVIEWIMG" ]]
- then
- PREVIEWIMG="$ICON"
- fi
-
- IMAGE="$PREVIEWIMG"
- NOTIFY_ICON="$PREVIEWIMG"
-}
-
-# generic yad xdg-open function
-gui_open(){
- PATH_ESCAPED="${1//%/%25}"
- xdg-open "$PATH_ESCAPED" > /dev/null 2>&1 &
-}
-
-# clear yad fields
-gui_clear_fields(){
- for FIELDNR in {4..8}; do
- echo "$FIELDNR:"
- done
-}
-
-# preserve metadata for next document in line
-duplicate_metadata () {
- AUTHOR_ORIGINAL="$AUTHOR"
- TITLE_ORIGINAL="$TITLE"
- YEAR_ORIGINAL="$YEAR"
- SUBJECT_ORIGINAL="$SUBJECT"
- KEYWORDS_ORIGINAL="$KEYWORDS"
-}
-
-
-process_yad_formchoices(){
- echo "$NEW_METADATA"
- AUTHOR="$(echo "$NEW_METADATA" | cut -d '|' -f4)"
- TITLE="$(echo "$NEW_METADATA" | cut -d '|' -f5)"
- YEAR="$(echo "$NEW_METADATA" | cut -d '|' -f6 | cut -d ',' -f1 | cut -d '.' -f1)"
- KEYWORDS="$(echo "$NEW_METADATA" | cut -d '|' -f7)"
- SUBJECT="$(echo "$NEW_METADATA" | cut -d '|' -f8)"
- SAVECHOICE="$(echo "$NEW_METADATA" | cut -d '|' -f14)"
- RENAMECHOICE="$(echo "$NEW_METADATA" | cut -d '|' -f15)"
- DUPLICATECHOICE="$(echo "$NEW_METADATA" | cut -d '|' -f16)"
- MODIFYDATE="$(date +"%Y:%m:%d %H:%M:%S")"
- if [[ "$YEAR" = "0" ]]; then
- CREATEDATE=""
- else
- CREATEDATE="$(printf "%04d" "$YEAR"):01:01 00:00:00"
- fi
-}
-
-# Metadata input
-
-read_metadata() {
- echo "#Reading embedded metadata..."
- exiftool -e -S -sep ";" -PDF:Title -PDF:Author -PDF:Subject \
- -PDF:Keywords -PDF:CreateDate -PDF:ModifyDate \
- "$FILE" > "$PROGPIPE"
-}
-
-print_original_metadata() {
- echo "###Original metadata:"
- echo ""
- echo "Author: $AUTHOR_ORIGINAL"
- echo "Title: $TITLE_ORIGINAL"
- echo "Year: $YEAR_ORIGINAL"
- echo "Creation date: $CREATEDATE_ORIGINAL"
- echo "Modification date: $MODIFYDATE_ORIGINAL"
- echo "Subject: $SUBJECT_ORIGINAL"
- echo "Keywords: $KEYWORDS_ORIGINAL"
-}
-
-evaluate_original_metadata() {
- METADATA_PDF="$( [[ -f "$PROGPIPE" ]] && cat "$PROGPIPE")"
- AUTHOR_ORIGINAL="$(echo "$METADATA_PDF" | sed -n 's/Author: //p')"
- TITLE_ORIGINAL="$(echo "$METADATA_PDF" | sed -n 's/Title: //p')"
- CREATEDATE_ORIGINAL="$(echo "$METADATA_PDF" | sed -n 's/CreateDate: //p')"
- YEAR_ORIGINAL="${CREATEDATE_ORIGINAL:0:4}"
- MODIFYDATE_ORIGINAL="$(echo "$METADATA_PDF" | sed -n 's/ModifyDate: //p')"
- SUBJECT_ORIGINAL="$(echo "$METADATA_PDF" | sed -n 's/Subject: //p')"
- KEYWORDS_ORIGINAL="$(echo "$METADATA_PDF" | sed -n 's/Keywords: //p')"
-}
-
-# Metadata output
-
-delete_metadata(){
- echo "#Deleting existing metadata"
- exiftool -e -overwrite_original -all:all="" "$FILE"
-}
-
-write_metadata(){
- echo "#Writing new metadata"
- exiftool -e -overwrite_original -password "$PASSWORD" -sep ";" \
- -PDF:Title="$TITLE" -PDF:Author="$AUTHOR" \
- -PDF:Subject="$SUBJECT" -PDF:Keywords="$KEYWORDS" \
- -PDF:ModifyDate="$MODIFYDATE" -PDF:CreateDate="$CREATEDATE" \
- -XMP-dc:Subject="$KEYWORDS" -XMP-dc:Description="$SUBJECT" -XMP-dc:Title="$TITLE" \
- -XMP-dc:Creator="$AUTHOR" -XMP-dc:Date="$CREATEDATE" \
- "$FILE"
- echo "$?" > "$ERRORPIPE1"
-}
-
-update_metadata(){
- delete_metadata; write_metadata
- check_modify_success
- error_check_write
-}
-
-print_updated_metadata() {
- echo "###Updated metadata:"
- echo ""
- echo "Author: $AUTHOR"
- echo "Title: $TITLE"
- echo "Year: $YEAR"
- echo "Creation date: $CREATEDATE"
- echo "Modificaiton date: $MODIFYDATE"
- echo "Subject: $SUBJECT"
- echo "Keywords: $KEYWORDS"
-}
-
-update_filename(){
- TARGETFOLDER="$DIRNAME"
- # replace characters in title that might cause issues on some file systems
- TITLE_FN="$(echo "$TITLE" | sed -e 's/\:/\;/g' -e 's/\&/and/g')"
- # Modify the following lines to change the naming scheme:
- # (default naming scheme: ${AUTHOR} - ${TITLE_FN} - ${YEAR})
- if [[ -n "$AUTHOR" ]]; then
- UPDATED_NAME="$AUTHOR"
- fi
- if [[ -n "$TITLE" ]]; then
- if [[ -n "$UPDATED_NAME" ]]; then
- UPDATED_NAME+=" - $TITLE_FN"
- else
- UPDATED_NAME="$TITLE"
- fi
- fi
- if [[ -n "$YEAR" && "$YEAR" != "0" ]]; then
- if [[ -n "$UPDATED_NAME" ]]; then
- UPDATED_NAME+=" - $YEAR"
- else
- UPDATED_NAME="$YEAR"
- fi
- fi
- echo "Updating file name..."
- mv "$FILE" "$TARGETFOLDER/$UPDATED_NAME.pdf"
- ARGS[$ARGID]="$TARGETFOLDER/$UPDATED_NAME.pdf" # make sure to update file array with
- # new location
-}
-
-# Error checks and workarounds
-
-# check if modification was successful
-check_modify_success(){
- # if the PDF ModifyDate hasn't been altered we can assume
- # that the exiftool tagging failed
- MODDATE_CHECK="$(exiftool -e -S -sep ";" -PDF:ModifyDate "$FILE"\
- | sed -n 's/ModifyDate: //p')"
- if [[ "$MODDATE_CHECK" != "$MODIFYDATE" ]]
- then
- error_log 3
- fi
-}
-
-error_check_write(){
- WRITE_RETURNCODE="$(cat "$ERRORPIPE1")"
- if [[ "$WRITE_RETURNCODE" != "0" || "$WRITEERROR" = "1" ]]
- then
- WRITEERROR="0"
- echo "$TEXT_INFO_WARNG1"
- gui_postprocess_pdf
- else
- gui_notify "$TEXT_NOTI_SUCCE1"
- echo "Success."
- fi
-}
-
-error_recheck_write(){
- PSTPRC_RETURNCODE="$(cat "$ERRORPIPE2")"
- if [[ "$PSTPRC_RETURNCODE" != "0" || "$WRITEERROR" = "1" ]]
- then
- error_log 4
- echo "$TEXT_NOTI_ERROR1"
- gui_notify "$TEXT_NOTI_ERROR1"
- else
- gui_notify "$TEXT_NOTI_SUCCE1"
- echo "Success."
- fi
-}
-
-sejda_process_pdf(){
- # Sejda does not preserve any document metadata
- # so we have to perform the exiftool actions again;
- # we use delete_metadata() in order to remove sejda-related metadata
- echo "#Running Sejda on $FILENAME..."
- TEMPFILE="$DIRNAME/${BASENAME}_sejda.pdf"
- sejda-console merge --compressed -v 7 -f "$FILE" -o "$TEMPFILE"
- RET_POSTPROC="$?"
- if [[ "$RET_POSTPROC" = "0" ]]; then
- mv "$TEMPFILE" "$DIRNAME/${BASENAME}.pdf"
- delete_metadata
- write_metadata
- fi
- echo "$RET_POSTPROC" > "$ERRORPIPE2"
-}
-
-linearize_pdf(){
- # qpdf only preserves metadata that is not marked as
- # obsolete by exiftool; to purge all existing (and potentially
- # corrupted metadata entries) we first delete all metadata,
- # linearize with qpdf, and then rewrite the metadata
- echo "#Linearizing $FILENAME..."
- delete_metadata
- TEMPFILE="$DIRNAME/${BASENAME}_linearized.pdf"
- qpdf --linearize "$FILE" "$TEMPFILE"
- RET_QPDF="$?"
- if [[ "$RET_QPDF" = "0" ]]; then
- mv "$TEMPFILE" "$DIRNAME/${BASENAME}.pdf"
- write_metadata
- fi
- echo "$RET_QPDF" > "$ERRORPIPE2"
-}
-
-# Main
-
-main_check_argid(){
- echo "Processing $ARGID of $ARGSTOTAL"
- if [[ "$ARGSTOTAL" = "1" ]]
- then
- MULTIDOC="single"
- elif [[ "$ARGID" = "1" ]]
- then
- MULTIDOC="first"
- elif [[ "$ARGID" = "$ARGSTOTAL" ]]
- then
- MULTIDOC="last"
- else
- MULTIDOC="middle"
- fi
-}
-
-main_iteration(){
- var_unset
- setup_filevars "$1"
- setup_gui
- gui_thumbnail_generate; read_metadata
- gui_thumbnail_assign
- evaluate_original_metadata
- [[ "$DUPLICATECHOICE" = "TRUE" ]] && duplicate_metadata
- print_original_metadata
- gui_metadata_entry_multi
- process_yad_formchoices
- print_updated_metadata
- [[ "$SAVECHOICE" = "TRUE" ]] && update_metadata
- [[ "$SAVECHOICE" = "TRUE" && "$RENAMECHOICE" = "TRUE" ]] && update_filename
-}
-
-main_check_progression(){
- if [[ "$PROGRESSION" = "NEXT" ]]
- then
- ARGID="$((ARGID+1))"
- main
- elif [[ "$PROGRESSION" = "PREVIOUS" ]]
- then
- ARGID="$((ARGID-1))"
- main
- elif [[ "$PROGRESSION" = "FINISH" ]]
- then
- echo "Finished."
- exit 0
- fi
-}
-
-main(){
- main_check_argid
- main_iteration "${ARGS[$ARGID]}"
- main_check_progression
-}
-
-############## FCT EXPORT ################
-
-# functions assigned to yad buttons need to be exported
-
-export -f gui_clear_fields
-export -f gui_open
-
-############### CLEANUP ##################
-
-trap "cleanup; exit" EXIT
-
-############## PREPWORK ###################
-
-TOP_PID="$$"
-mkdir -p "$TMPDIR"
-PROGPIPE="$(mktemp -u --tmpdir="$TMPDIR" XXXXXXXX)"
-ERRORPIPE1="$(mktemp -u --tmpdir="$TMPDIR" XXXXXXXX)"
-ERRORPIPE2="$(mktemp -u --tmpdir="$TMPDIR" XXXXXXXX)"
-
-############## USGCHECKS #################
-
-gui_check_deps
-arg_evaluate_options "$@"
-shift $((OPTIND-1))
-FILEARGS=("$@")
-[[ "$URI_OPT" = "TRUE" ]] && arg_uri_to_path "${FILEARGS[@]}"
-arg_check_correct "${FILEARGS[@]}"
-arg_compose_filearray "${FILEARGS[@]}"
-
-################ MAIN ####################
-
-main
diff --git a/.local/bin/picospeaker b/.local/bin/picospeaker
deleted file mode 100755
index 22b0210..0000000
--- a/.local/bin/picospeaker
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/bin/sh -eu
-audio=$(mktemp --suffix -picospeaker.wav)
-text=${1:-The text argument is absent.}
-
-rm -f /tmp/*-picospeaker.wav;
-
-[ "${1-}" = "echo" ] && picospeaker "${2-}" "${1-}" && exit;
-
-pico2wave -w "$audio" "$text";
-[ "${2-}" = "echo" ] && ffmpeg -y -i "$audio" -map 0 -c:v copy -af aecho=1:1:50:0.5 "$audio";
-mplayer "$audio";
diff --git a/.local/bin/plumber b/.local/bin/plumber
index b791adc..88aa80c 100755
--- a/.local/bin/plumber
+++ b/.local/bin/plumber
@@ -1,39 +1,131 @@
#! /usr/bin/env elixir
+defmodule Settings do
+ def terminal do
+ System.get_env("TERMINAL")
+ end
+end
+
defmodule ArgParser do
def parse do
{opts, _} =
System.argv()
|> OptionParser.parse!(strict: [option: :string, text: :string])
+ options = [
+ camelize: "text->camelize",
+ case_lower: "case->lower",
+ case_title: "case->title",
+ case_titleize: "case->titleize",
+ case_upper: "case->upper",
+ date8601: "text->date8601",
+ dictionary: "word->dictionary",
+ jumbleize: "text->jumbleize",
+ kjv: "verse->kjv",
+ letterize: "text->letterize",
+ lorem_paragraph: "lorem->paragraph",
+ lorem_title: "lorem->title",
+ reverse_letters: "reverse->letters",
+ reverse_words: "reverse->words",
+ singleline: "text->singleline",
+ slugize: "text->slugize",
+ urlize: "text->urlize",
+ ]
+
cond do
- opts[:option] == "First letter of each word in sentence" ->
- TextPlumber.firstLetterOfWordsIn(opts[:text]) |> IO.binwrite()
+ opts[:option] == options[:letterize] ->
+ TextPlumber.firstLetterOfWordsIn(opts[:text]) |> IO.puts()
+
+ opts[:option] == options[:urlize] ->
+ URI.encode(opts[:text]) |> IO.puts()
+
+ opts[:option] == options[:slugize] ->
+ opts[:text]
+ |> String.normalize(:nfd)
+ |> String.replace(~r/[[:space:]]+/, " ")
+ |> String.replace(~r/[[:punct:]]+/, " ")
+ |> Macro.underscore()
+ |> String.replace(~r/[[:space:]]+/, "-")
+ |> String.replace(~r/[[:punct:]]+/, "-")
+ |> String.trim("-")
+ |> IO.puts()
+
+ opts[:option] == options[:camelize] ->
+ opts[:text]
+ |> String.normalize(:nfd)
+ |> String.replace(~r/[[:space:]]+/, "_")
+ |> String.replace(~r/[[:punct:]]+/, "_")
+ |> Macro.camelize()
+ |> String.replace(~r/[[:space:]]+/, "")
+ |> String.replace(~r/[[:punct:]]+/, "")
+ |> IO.puts()
+
+ opts[:option] == options[:singleline] ->
+ TextPlumber.singleLineOf(opts[:text]) |> IO.puts()
+
+ opts[:option] == options[:jumbleize] ->
+ String.split(opts[:text] |> String.replace(~r/[[:punct:]]+/, ""))
+ |> Enum.map(&String.codepoints/1)
+ |> Enum.map(&TextPlumber.jumble/1)
+ |> Enum.map(&Enum.join/1)
+ |> Enum.join(" ")
+ |> IO.puts()
+
+ opts[:option] == options[:reverse_words] ->
+ TextPlumber.reverse(opts[:text]) |> IO.puts()
+
+ opts[:option] == options[:reverse_letters] ->
+ String.split(opts[:text])
+ |> Enum.map(&String.codepoints/1)
+ |> Enum.map(&Enum.reverse/1)
+ |> Enum.join(" ")
+ |> IO.puts()
+
+ opts[:option] == options[:dictionary] ->
+ TextPlumber.dictionOfFirstWordIn(opts[:text])
+ TextPlumber.firstWordOf(opts[:text]) |> IO.puts()
+
+ opts[:option] == options[:case_title] ->
+ opts[:text] |> to_string |> TextPlumber.titleCaseOf() |> IO.puts()
+
+ opts[:option] == options[:case_titleize] ->
+ String.downcase(opts[:text]) |> TextPlumber.titleCaseOf() |> IO.puts()
+
+ opts[:option] == options[:case_lower] ->
+ String.downcase(opts[:text]) |> IO.puts()
+
+ opts[:option] == options[:case_upper] ->
+ String.upcase(opts[:text]) |> IO.puts()
+
+ opts[:option] == options[:lorem_title] ->
+ TextPlumber.loremTitle()
- opts[:option] == "Single line of text" ->
- TextPlumber.singleLineOf(opts[:text]) |> IO.binwrite()
+ opts[:option] == options[:lorem_paragraph] ->
+ TextPlumber.loremParagraph()
- opts[:option] == "Thesaurus" ->
- TextPlumber.synonymOfFirstWordIn(opts[:text])
- TextPlumber.firstWordOf(opts[:text]) |> IO.binwrite()
+ opts[:option] == options[:date8601] ->
+ TextPlumber.date8601()
- opts[:option] == "KJV Verse Lookup" ->
- System.cmd("urxvt", ["-e", "sh", "-c", "kjv #{TextPlumber.singleLineOf(opts[:text])}"])
- TextPlumber.singleLineOf(opts[:text]) |> IO.binwrite()
+ opts[:option] == options[:kjv] ->
+ System.cmd(Settings.terminal(), [
+ "-e",
+ "sh",
+ "-c",
+ "kjv #{TextPlumber.singleLineOf(opts[:text])}"
+ ])
- opts[:option] == "Title Case" ->
- TextPlumber.titleCaseOf(opts[:text]) |> IO.binwrite()
+ TextPlumber.singleLineOf(opts[:text]) |> IO.puts()
true ->
- "No plumber #{opts[:option] || "specified"}." |> IO.puts()
+ Enum.each(options, fn {_, value} -> IO.puts(value) end)
end
end
end
defmodule TextPlumber do
def firstLetterOfWordsIn(text) do
- String.replace(text, ~r/(\w)\w*/, "\\1", global: true)
- |> String.replace(~r/\s\s+/, " ", global: true)
+ String.replace(text, ~r/(\w)\w*/u, "\\1", global: true)
+ |> String.replace(~r/\s\s+/u, " ", global: true)
end
def singleLineOf(text) do
@@ -45,12 +137,67 @@ defmodule TextPlumber do
String.split(text) |> List.first()
end
+ def reverse(text) do
+ String.split(text) |> Enum.reverse |> Enum.join(" ")
+ end
+
def titleCaseOf(text) do
text |> String.split() |> Enum.map(fn word -> :string.titlecase(word) end) |> Enum.join(" ")
end
- def synonymOfFirstWordIn(text) do
- System.cmd("urxvt", ["-e", "sh", "-c", "dict #{TextPlumber.firstWordOf(text)} | vim -"])
+ def loremParagraph() do
+ {string, _return} =
+ System.cmd("sh", [
+ "-c",
+ "perl -e 'use Text::Lorem; use Text::Wrap; $Text::Wrap::columns = 80; print wrap(\"\", \"\", Text::Lorem->new()->sentences(5));'"
+ ])
+
+ IO.puts(string)
+ end
+
+ def loremTitle() do
+ {string, _return} =
+ System.cmd("sh", [
+ "-c",
+ "perl -e 'use Text::Lorem; print Text::Lorem->new()->words(4)';"
+ ])
+
+ IO.puts(string)
+ end
+
+ def dictionOfFirstWordIn(text) do
+ System.cmd(Settings.terminal(), [
+ "-e",
+ "sh",
+ "-c",
+ "dict -h localhost #{TextPlumber.firstWordOf(text)} 2>&1 | vim -"
+ ])
+ end
+
+ def jumble(list) do
+ if length(list) == 1 do
+ list
+ else
+ head = Enum.take(list, 1)
+ tail = Enum.take(list, -1)
+ list = list |> Enum.drop(-1) |> Enum.drop(1)
+
+ if length(list) == 2 do
+ head ++ (list |> Enum.reverse()) ++ tail
+ else
+ head ++ (list |> Enum.shuffle()) ++ tail
+ end
+ end
+ end
+
+ def date8601() do
+ {string, _return} =
+ System.cmd("date", [
+ "--universal",
+ "--iso-8601=seconds"
+ ])
+
+ IO.puts(string)
end
end
diff --git a/.local/bin/plumber-dmenu b/.local/bin/plumber-dmenu
index bdfe28e..ea141c2 100755
--- a/.local/bin/plumber-dmenu
+++ b/.local/bin/plumber-dmenu
@@ -1,15 +1,32 @@
#!/bin/sh -eu
-options="First letter of each word in sentence
-Single line of text
-Thesaurus
-KJV Verse Lookup
-Title Case
+
+options="\
+case->lower
+case->title
+case->titleize
+case->upper
+lorem->paragraph
+lorem->title
+reverse->letters
+reverse->words
+text->camelize
+text->date8601
+text->jumbleize
+text->letterize
+text->singleline
+text->slugize
+text->urlize
+verse->kjv
+word->dictionary
"
-printf "%s" "$options" \
- | dmenu -i -b -p Plumb \
- | while read -r option
- do
- text=$(plumber --option "$option" --text "$(xsel -o)")
- { notify-send "$text" && printf "%s" "$text" | xsel -ib; } \
- || notify-send "Plumber: Clipboard selection is empty"
- done
+
+selection=$(
+ printf "%s" "$options" | dmenu -i -b -p ⠀:::⠀plumber⠀::: ||
+ { [ "$?" = 127 ] && kill -15 "$$" && "$0"; }
+)
+
+printf "%s\n" "$selection" | while read -r option; do
+ text=$(plumber --option "$option" --text "$(xsel -o)")
+ { notify-send "$text" && printf "%s" "$text" | xsel -ib; } ||
+ notify-send "Plumber: Clipboard selection is empty"
+done
diff --git a/.local/bin/portmanteau b/.local/bin/portmanteau
new file mode 100755
index 0000000..9ce9dc3
--- /dev/null
+++ b/.local/bin/portmanteau
@@ -0,0 +1,38 @@
+#!/usr/bin/env bash
+set -eu
+
+minimum=4
+words=$(diceware --no-caps --num 2 --delimiter " ")
+first=${words%??? *}
+second=${words#* ???}
+
+[ ${#first} -lt $minimum ] && "$0" && exit
+[ ${#second} -lt $minimum ] && "$0" && exit
+
+vowels="a e i o u"
+sounds="h r w y"
+consonants="b c d f g j k l m n p q s t v x z"
+suffix=${first: -1:1}
+prefix=${second: 0:1}
+digraph="$suffix$prefix"
+compressed="${first: 0:-1}${second: 1}"
+
+printf 'words: %s\n' "$words"
+printf 'digraph: %s\n' "$digraph"
+printf 'merge: %s%s\n' "$first" "$second"
+printf 'compressed: %s\n\n' "$compressed"
+
+Grammar() {
+ for left in $consonants; do
+ [ "$suffix" = "$left" ] &&
+ {
+ for right in $consonants; do
+ [ "$prefix" = "$right" ] &&
+ printf '%s\n' "$compressed" &&
+ exit
+ done
+ }
+ done || printf '%s%s\n' "$first" "$second"
+}
+
+Grammar
diff --git a/.local/bin/powerdialog b/.local/bin/powerdialog
index 43c2250..52e3330 100755
--- a/.local/bin/powerdialog
+++ b/.local/bin/powerdialog
@@ -1,16 +1,16 @@
#!/bin/sh -eu
-ACTION=$(zenity --width=90 \
+ACTION=$(yad --width=90 \
--height=210 --list --radiolist --text="Select Action" \
--title="Logout" --column "Choice" --column "Action" \
FALSE Shutdown FALSE Reboot TRUE Suspend FALSE Lock FALSE Blank)
if [ -n "${ACTION}" ]; then
case $ACTION in
- Shutdown) zenity --question --text "Are you sure you want to halt?" && sudo -A 'systemctl poweroff' ;;
- Reboot) zenity --question --text "Are you sure you want to reboot?" && sudo -A 'systemctl reboot' ;;
- Suspend) systemctl suspend ;;
- Lock) i3lock-fancy ;;
- Blank) sleep 1; xset dpms force off ;;
+ 'TRUE|Shutdown|') yad --question --text "Are you sure you want to halt?" && sudo -A 'systemctl poweroff' ;;
+ 'TRUE|Reboot|') yad --question --text "Are you sure you want to reboot?" && sudo -A 'systemctl reboot' ;;
+ 'TRUE|Suspend|') systemctl suspend ;;
+ 'TRUE|Lock|') i3lock-fancy ;;
+ 'TRUE|Blank|') sleep 1; xset dpms force off ;;
esac
fi
diff --git a/.local/bin/rofi-askpass b/.local/bin/rofi-askpass
index f19a68c..612a819 100755
--- a/.local/bin/rofi-askpass
+++ b/.local/bin/rofi-askpass
@@ -1,2 +1,12 @@
#!/bin/sh -eu
-rofi -dmenu -password -i -no-fixed-num-lines -padding 15 -p "Password";
+
+program=doas
+password=$(rofi -dmenu -password -i -no-fixed-num-lines -padding 15 -p "Password";)
+
+expect <<EOF
+ set timeout -1
+ spawn "$program" "$@"
+ expect "assword:"
+ send -- "$password\r"
+ expect eof
+EOF
diff --git a/.local/bin/say b/.local/bin/say
new file mode 100755
index 0000000..4537669
--- /dev/null
+++ b/.local/bin/say
@@ -0,0 +1,23 @@
+#!/bin/sh -eu
+
+audio=/tmp/speak-jfgOUcZdWu.wav
+text=${1:-Nothing to say.}
+
+[ "${1-}" = "echo" ] && $0 "${2-}" "${1-}" && exit;
+
+printf '%s' "$text" |
+ piper \
+ --model "$HOME/.local/share/piper/voices/en_GB-jenny_dioco-medium.onnx" \
+ --output_file $audio
+
+[ "${2-}" = "echo" ] &&
+ ffmpeg \
+ -y \
+ -i "$audio" \
+ -map 0 \
+ -c:v copy \
+ -af aecho=1:1:50:0.5,atempo=0.85 "$audio.mp3" &&
+ mplayer -really-quiet "$audio.mp3" &&
+ exit;
+
+mplayer -really-quiet "$audio";
diff --git a/.local/bin/screenrecord b/.local/bin/screenrecord
new file mode 100755
index 0000000..7702243
--- /dev/null
+++ b/.local/bin/screenrecord
@@ -0,0 +1,17 @@
+#!/bin/sh -eu
+
+process=x11grab
+directory=$HOME/Desktop/screen-recordings
+default=$(xrandr | awk '/*/ { print $1 }' | head -n1)
+file="$(date +%I:%M:%S-%p-%A-%d-%B-%Y).mp4"
+resolution=${1:-$default}
+
+[ "${1:-}" = "stop" ] && kill -15 "$(ps -aux | awk "/$process/"' { print $2 }' | head -n 1)"
+[ "${1:-}" = "stop" ] && exit
+
+[ "$(ps -aux | awk "/$process/"' { print $2 }' | wc -l)" != 1 ] && printf 'Screen Already Recording!\n' && exit
+
+mkdir --parents "$directory"
+notify-send --expire-time=2000 "Screen Recording Started ($resolution)" "$directory/$file" && sleep 2
+ffmpeg -f alsa -i default -f alsa -i default -f x11grab -s "$resolution" -i "$DISPLAY" -r 24 -c:v libx264rgb -crf 0 -preset ultrafast "$directory/$file" || true
+notify-send "Screen Recording Ended ($resolution)" "$directory/$file"
diff --git a/.local/bin/scripts/amixer b/.local/bin/scripts/amixer
deleted file mode 100755
index 9b9b679..0000000
--- a/.local/bin/scripts/amixer
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/bin/sh -eu
-[ "$1" = "up" ] && amixer set Master 1%+
-[ "$1" = "down" ] && amixer set Master 1%-
-[ "$1" = "mute" ] && amixer sset Master toggle
diff --git a/.local/bin/scripts/app-launcher b/.local/bin/scripts/app-launcher
deleted file mode 100755
index 60e507a..0000000
--- a/.local/bin/scripts/app-launcher
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/sh -eu
-# rofi -cache-dir "$HOME/.local/share" -fullscreen -show run -display-run '$' -font 'ubuntu 12' -padding 250;
-dmenu_run_history;
diff --git a/.local/bin/scripts/app-launcher-priv b/.local/bin/scripts/app-launcher-priv
deleted file mode 100755
index 8552f21..0000000
--- a/.local/bin/scripts/app-launcher-priv
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/sh -eu
-# rofi -cache-dir "$HOME/.local/share" -fullscreen -show run -display-run '#' -run-command 'sudo -A {cmd}' -font 'ubuntu 12' -padding 250;
-dmenu_run_history privilege;
diff --git a/.local/bin/scripts/app-launcher-terminal b/.local/bin/scripts/app-launcher-terminal
deleted file mode 100755
index c96f919..0000000
--- a/.local/bin/scripts/app-launcher-terminal
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/sh -eu
-dmenu_run_history terminal;
diff --git a/.local/bin/scripts/events-idle b/.local/bin/scripts/events-idle
deleted file mode 100755
index 1ec1e10..0000000
--- a/.local/bin/scripts/events-idle
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/bin/sh -eux
-
-# update file search cache
-"$HOME"/.local/bin/scripts/file-search update;
-
-# update dmenu_run_history
-"$HOME"/.local/bin/dmenu_run_history update;
diff --git a/.local/bin/scripts/events-usb b/.local/bin/scripts/events-usb
deleted file mode 100755
index 2978a84..0000000
--- a/.local/bin/scripts/events-usb
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/sh -eux
-xmodmap "$HOME/.config/X11/Xmodmap";
-xset r rate 200 60;
diff --git a/.local/bin/scripts/internet-search b/.local/bin/scripts/internet-search
deleted file mode 100755
index 096c4ee..0000000
--- a/.local/bin/scripts/internet-search
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/sh -eu
-rofi -dmenu -show run -font "ubuntu 16" -padding 10 -lines 0 -p " " | xargs -r surfraw duckduckgo
diff --git a/.local/bin/scripts/volume-down b/.local/bin/scripts/volume-down
deleted file mode 100755
index 774ee0b..0000000
--- a/.local/bin/scripts/volume-down
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/sh -eu
-"$HOME"/.local/bin/scripts/amixer down
diff --git a/.local/bin/scripts/volume-mute b/.local/bin/scripts/volume-mute
deleted file mode 100755
index e3aded4..0000000
--- a/.local/bin/scripts/volume-mute
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/sh -eu
-"$HOME"/.local/bin/scripts/amixer mute
diff --git a/.local/bin/scripts/volume-up b/.local/bin/scripts/volume-up
deleted file mode 100755
index fbbbb0b..0000000
--- a/.local/bin/scripts/volume-up
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/sh -eu
-"$HOME"/.local/bin/scripts/amixer up
diff --git a/.local/bin/scripts/window-switcher b/.local/bin/scripts/window-switcher
deleted file mode 100755
index 39483a2..0000000
--- a/.local/bin/scripts/window-switcher
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/bin/sh -eu
-
-# Copyright 2013 Tom Vincent <http://tlvince.com/contact/>
-wmctrl -l | cut -d' ' -f 1,5- | dmenu -f -i -b -p Switch | cut -d' ' -f 1 | xargs wmctrl -ia
-
-# Rofi
-#rofi -no-disable-history -show window -theme-str '#prompt { enabled: false; }' -window-format {t} -font "ubuntu 12" -padding 15 -lines 1
diff --git a/.local/bin/seance b/.local/bin/seance
new file mode 100755
index 0000000..5b9160e
--- /dev/null
+++ b/.local/bin/seance
@@ -0,0 +1,132 @@
+#!/bin/sh -eu
+
+program=$(basename "$0")
+directory=$HOME/.config/seance
+session=$directory/session
+spirits=$directory/spirits
+
+Help() {
+printf \
+"
+Usage: %s [FLAGS]... [ARGUMENT]...
+
+The program $program shall save and restore
+running programs in a desktop session according
+to a specified configuration file.
+
+Add a program command, one per line, in
+$spirits
+to save to current session.
+
+Session: $session
+Config: $spirits
+
+ Command List:
+
+ $program commit Saves programs in config to session.
+ $program list List session commands.
+ $program config View programs to be saved to session.
+ $program windows List running programs
+ $program search Search for a running program.
+ $program start Restore previous session.
+ $program edit session Edit session commands.
+ $program edit config Edit programs in config.
+ $program -h --help Show this help menu.
+
+" "$program";
+}
+
+Commit() {
+
+windows=$(wmctrl -Glp)
+date=$(date --utc '+%a-%b-%d-%H:%M:%S-%Y')
+
+IFS='
+'
+
+mv "$1" "$1-$date"
+
+true > "$1"
+
+for window in $windows; do
+
+pid=$(printf "%s" "$window" | awk '{ print $3 }')
+desktop=$(printf "%s" "$window" | awk '{ print $2 }')
+title=$(printf "%s" "$window" | tr -s ' ' | cut -d ' ' -f 9-)
+dimensions=$(printf "%s" "$window" | awk '{ print $4, ",", $5, ",", $6, ",", $7 }' | tr -d ' ')
+[ "$pid" = "0" ] && continue;
+process=$(ps -ww -p "$pid" -o command | tail -n 1)
+
+while read -r spirit; do
+ case "$process" in
+ *$spirit*) process=$spirit ;;
+ esac
+done < "$spirits"
+
+commands=$(printf "%s" "$title" | cut -d ' ' -f 3- | sed "s|'|'\\\\\\\''|g")
+
+[ -z "$commands" ] && commands="true"
+
+mime="$(file --mime-type "$title" | awk '{ print $2 }')"
+directory=$(printf "%s" "$title" | cut -d ' ' -f 2)
+
+case "$mime" in
+application/pdf) process="zathura $title" ;;
+esac
+
+case "$title" in
+*term:*) process="\$TERMINAL -e sh -c 'cd $directory && $commands; \$SHELL'" ;;
+esac
+
+case "$title" in
+*vim:*) process="\$TERMINAL -e sh -c '\$EDITOR $directory; \$SHELL'" ;;
+esac
+
+case "$title" in
+*\[Scratch\]*) continue ;;
+esac
+
+case "$commands" in
+*$program*) continue ;;
+esac
+
+grep "$process" "$1" > /dev/null 2>&1 && continue
+
+printf "%s\n" "$process"
+
+printf "\
+$process > /dev/null 2>&1 & disown
+i=0; until wmctrl -Glp | grep -i \"\$!\"; do i=\$((i+1)); [ \$i -gt 150 ] && break; done
+wmctrl -i -r \"\$(wmctrl -Glp | awk -v pid=\"\$!\" '\$0 ~ pid { print \$1 }')\" -t $desktop
+wmctrl -i -r \"\$(wmctrl -Glp | awk -v pid=\"\$!\" '\$0 ~ pid { print \$1 }')\" -e '0,$dimensions'
+
+" >> "$1"
+done
+}
+
+{ [ "${1:-}" = "-h" ] || [ "${1:-}" = "--help" ] || [ "$#" = 0 ]; } && Help && exit;
+
+mkdir --parents "$directory"
+
+touch "$spirits"
+
+[ "${1:-}" = "commit" ] \
+ && { Commit "$session" || printf "Warning empty or failed session file!\n"; } \
+ && printf '\nSession %s canonized.\n\n' "$session" \
+ && exit
+
+[ "${1:-}" = "list" ] && cat "$session" && exit;
+
+[ "${1:-}" = "config" ] && cat "$spirits" && exit;
+
+[ "${1:-}" = "windows" ] && wmctrl -Glp && exit;
+
+[ "${1:-}" = "search" ] && wmctrl -Glp | grep --ignore-case -- "$2" && exit;
+
+[ "${1:-}" = "start" ] && sh "$session" && exit;
+
+[ "${1:-}" = "edit" ] && [ "${2:-}" = "session" ] && $EDITOR "$session" && exit;
+
+[ "${1:-}" = "edit" ] && [ "${2:-}" = "config" ] && $EDITOR "$spirits" && exit;
+
+Help && printf "Error: Unknown argument '%s'.\n\n" "$@" && exit 1;
diff --git a/.local/bin/sfeed_fzf b/.local/bin/sfeed_fzf
new file mode 100755
index 0000000..5c432b8
--- /dev/null
+++ b/.local/bin/sfeed_fzf
@@ -0,0 +1,24 @@
+#!/bin/sh -eu
+
+config=$XDG_CONFIG_HOME/sfeed/sfeedrc
+unread=$XDG_CONFIG_HOME/sfeed/unread
+read=$XDG_CONFIG_HOME/sfeed/read
+feeds=$XDG_CONFIG_HOME/sfeed/feeds
+
+touch "$read"
+
+sfeed_update "$config" || true
+
+sfeed_plain_function() {
+ sfeed_plain "$feeds"/* |
+ sed 's/^[N ]\+//g' |
+ sort --reverse |
+ grep --invert-match --fixed-strings --file "$read" > "$unread"
+}
+
+sfeed_plain_function
+fzf < "$unread" \
+ --multi \
+ --info hidden \
+ --bind "enter:execute(firefox \$(echo {} | awk '{ print \$NF }'))" \
+ --bind "ctrl-d:reload(echo {} >> $read && { sfeed_plain $feeds/* | sed 's/^[N ]\+//g' | sort --reverse | grep --invert-match --fixed-strings --file $read > $unread && cat $unread; })"
diff --git a/.local/bin/scripts/snipping-tool b/.local/bin/snipping-tool
index 4347bfe..4347bfe 100755
--- a/.local/bin/scripts/snipping-tool
+++ b/.local/bin/snipping-tool
diff --git a/.local/bin/scripts/sshfs-mount b/.local/bin/sshfs-mount
index 0e2352c..0e2352c 100755
--- a/.local/bin/scripts/sshfs-mount
+++ b/.local/bin/sshfs-mount
diff --git a/.local/bin/scripts/switch-monitor b/.local/bin/switch-monitor
index 80d7191..80d7191 100755
--- a/.local/bin/scripts/switch-monitor
+++ b/.local/bin/switch-monitor
diff --git a/.local/bin/sx b/.local/bin/sx
new file mode 100755
index 0000000..bda1ba0
--- /dev/null
+++ b/.local/bin/sx
@@ -0,0 +1,57 @@
+#!/bin/sh --
+# LICENCE: MIT
+# https://github.com/Earnestly/sx
+
+stty=$(stty -g)
+tty=$(tty)
+tty=${tty#/dev/tty}
+
+cfgdir=${XDG_CONFIG_HOME:-$HOME/.config}/X11
+datadir=${XDG_CONFIG_HOME:-$HOME/.config}/X11
+
+cleanup() {
+ if [ "$pid" ] && kill -0 "$pid" 2> /dev/null; then
+ kill "$pid"
+ wait "$pid"
+ xorg=$?
+ fi
+
+ if ! stty "$stty"; then
+ stty sane
+ fi
+
+ xauth remove :"$tty"
+
+ if [ "$1" = exit ]; then
+ exit "${xorg:-0}"
+ fi
+}
+
+
+mkdir --parents -- "$cfgdir" "$datadir"
+export XAUTHORITY="${XAUTHORITY:-$datadir/Xauthority}"
+touch -- "$XAUTHORITY"
+export XDG_SESSION_TYPE=X11
+
+xauth add :"$tty" MIT-MAGIC-COOKIE-1 "$(od -An -N16 -tx /dev/urandom | tr -d ' ')"
+
+trap 'cleanup; trap - INT; kill -INT "$$"' INT
+trap 'cleanup exit' EXIT HUP TERM QUIT
+
+# Xorg will check whether it inherited a USR1 with a disposition of SIG_IGN and
+# use this state to reply back to the parent process with its own USR1.
+# This is done to indicate that the server is ready to accept connections.
+# Taking advantage of this feature allows launching the client directly from a
+# USR1 signal trap which obviates the need to poll for server readiness.
+
+trap 'DISPLAY=:$tty exec "${@:-$cfgdir/xinitrc}" & wait "$!"' USR1
+
+(trap '' USR1 && exec Xorg :"$tty" \
+ -keeptty vt"$tty" \
+ -noreset \
+ -auth "$XAUTHORITY" \
+ -configdir "$cfgdir/xorg.conf.d" \
+ -logfile "$HOME/.cache/xorg.log" \
+) & pid=$!
+
+wait "$pid"
diff --git a/.local/bin/tidy-url b/.local/bin/tidy-url
new file mode 100755
index 0000000..2aa400b
--- /dev/null
+++ b/.local/bin/tidy-url
@@ -0,0 +1,2 @@
+#!/bin/sh -eu
+curl --silent "$1" | tidy -config "$HOME/.config/tidy/url.conf"
diff --git a/.local/bin/vnc b/.local/bin/vnc
new file mode 100755
index 0000000..1af953f
--- /dev/null
+++ b/.local/bin/vnc
@@ -0,0 +1,30 @@
+#!/bin/sh -eu
+
+host="$1"
+address="$host.internal"
+
+. "$HOME/.vnc/keys/macs"
+
+[ "$host" = 'hound' ] && wol "$hound";
+[ "$host" = 'tiger' ] && wol "$tiger";
+
+notify-send -t 2000 Connecting...;
+
+i=0;
+until ping -c1 "$address" > /dev/null 2>&1;
+do notify-send -t 2000 'Waiting for response...';
+ i=$((i+1)); [ "$i" -gt 5 ] && notify-send -u critical 'Unable to negotiate connection.' && exit;
+done;
+
+notify-send -t 4000 Connected.;
+
+vncviewer -passwd "$HOME/.vnc/keys/passwd-$host" \
+ AlertOnFatalError=0 \
+ AutoSelect=0 \
+ CompressLevel=0 \
+ DotWhenNoCursor=1 \
+ Fullscreen=1 \
+ PreferredEncoding=Hextile \
+ QualityLevel=6 \
+ Shared=1 \
+ "$address:5901";
diff --git a/.local/bin/scripts/vnc-exit b/.local/bin/vnc-exit
index afc4833..afc4833 100755
--- a/.local/bin/scripts/vnc-exit
+++ b/.local/bin/vnc-exit
diff --git a/.local/bin/scripts/vnc-suspend b/.local/bin/vnc-suspend
index 589a7f2..589a7f2 100755
--- a/.local/bin/scripts/vnc-suspend
+++ b/.local/bin/vnc-suspend
diff --git a/.local/bin/volume-control b/.local/bin/volume-control
new file mode 100755
index 0000000..95454a3
--- /dev/null
+++ b/.local/bin/volume-control
@@ -0,0 +1,4 @@
+#!/bin/sh -eu
+[ "$1" = "up" ] && amixer set Master 1%+
+[ "$1" = "down" ] && amixer set Master 1%-
+[ "$1" = "mute" ] && amixer sset Master toggle
diff --git a/.local/bin/wget b/.local/bin/wget
deleted file mode 100755
index ca229b3..0000000
--- a/.local/bin/wget
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/sh -eu
-$(which wget --all | grep -v "local/bin" | head -n 1) --hsts-file "$HOME/.cache/wget.history" "$@";
diff --git a/.local/bin/scripts/window-overview b/.local/bin/window-overview
index 62b50d9..62b50d9 100755
--- a/.local/bin/scripts/window-overview
+++ b/.local/bin/window-overview
diff --git a/.local/bin/window-switcher b/.local/bin/window-switcher
new file mode 100755
index 0000000..a184baa
--- /dev/null
+++ b/.local/bin/window-switcher
@@ -0,0 +1,23 @@
+#!/bin/sh -u
+# https://git.suckless.org/sites/file/tools.suckless.org/dmenu/scripts/switch.html
+
+windows=$(wmctrl -xl |
+ tr --squeeze-repeats '[:blank:]' |
+ tr '[:upper:]' '[:lower:]' |
+ cut --delimiter ' ' --fields 3-3,5- |
+ sed 's/^[a-zA-Z0-9-]*\.//' |
+ sort |
+ uniq)
+
+windows=$(printf "%s" "$windows" |
+ awk --assign list="$windows" \
+ '{cur=length($1); printf $1; for(i=0; i < list - cur + 1; i++) printf " "; $1 = ""; printf "%s\n", $0}' 2> /dev/null)
+
+selection=$(
+ printf "%s" "$windows" | dmenu -nhf '#cf71e0' -sf '#cf71e0' -f -i -b -p ⠀:::⠀windows⠀:::
+ [ "$?" = 127 ] && kill -15 "$$" && "$0"
+)
+
+target=$(printf "%s" "$selection" | tr --squeeze-repeats '[:blank:]' | cut --delimiter ' ' --fields 2-)
+
+[ -n "$target" ] && wmctrl -a "$target"
diff --git a/.local/bin/scripts/workout-notify b/.local/bin/workout-notify
index 6934a45..6934a45 100755
--- a/.local/bin/scripts/workout-notify
+++ b/.local/bin/workout-notify
diff --git a/.local/bin/wrappers/adb b/.local/bin/wrappers/adb
new file mode 100755
index 0000000..cfe91cf
--- /dev/null
+++ b/.local/bin/wrappers/adb
@@ -0,0 +1,2 @@
+#!/bin/sh -eu
+HOME=$HOME/.config && $(which adb --all | grep --invert-match "local/bin" | head -n 1) "$@";
diff --git a/.local/bin/wrappers/aegisub b/.local/bin/wrappers/aegisub
new file mode 100755
index 0000000..9ade37a
--- /dev/null
+++ b/.local/bin/wrappers/aegisub
@@ -0,0 +1,2 @@
+#!/bin/sh -eu
+HOME=$HOME/.config && $(which aegisub --all | grep --invert-match "local/bin" | head -n 1) "$@";
diff --git a/.local/bin/wrappers/aspell b/.local/bin/wrappers/aspell
new file mode 100755
index 0000000..78fddd0
--- /dev/null
+++ b/.local/bin/wrappers/aspell
@@ -0,0 +1,2 @@
+#!/bin/sh -eu
+$(which aspell --all | grep --invert-match "local/bin" | head -n 1) --conf "$HOME/.config/aspell/aspell.conf" "$@";
diff --git a/.local/bin/scripts/clipboard b/.local/bin/wrappers/audacity
index e776c70..fead7fd 100755
--- a/.local/bin/scripts/clipboard
+++ b/.local/bin/wrappers/audacity
@@ -1,2 +1,2 @@
#!/bin/sh -eu
-copyq toggle;
+tenacity "$@"
diff --git a/.local/bin/wrappers/chromium b/.local/bin/wrappers/chromium
new file mode 100755
index 0000000..d0e9a9f
--- /dev/null
+++ b/.local/bin/wrappers/chromium
@@ -0,0 +1,13 @@
+#!/bin/sh -eu
+
+$(which chromium --all | grep --invert-match "local/bin" | head -n 1) \
+ --disable-smooth-scrolling \
+ --disable-sync-preferences \
+ --process-per-site \
+ "$@";
+
+# --incognito
+# --disable-gpu-compositing
+# --disk-cache-dir=/dev/null
+# --enable-native-gpu-memory-buffers
+# --proxy-server="socks5://localhost:2871"
diff --git a/.local/bin/wrappers/claws-mail b/.local/bin/wrappers/claws-mail
new file mode 100755
index 0000000..b19aa55
--- /dev/null
+++ b/.local/bin/wrappers/claws-mail
@@ -0,0 +1,3 @@
+#!/bin/sh -eu
+$(which claws-mail --all | grep --invert-match "local/bin" | head -n 1) \
+ --alternate-config-dir "${XDG_CONFIG_HOME:-~/.config}"/claws-mail "$@";
diff --git a/.local/bin/wrappers/codium b/.local/bin/wrappers/codium
new file mode 100755
index 0000000..87e93e5
--- /dev/null
+++ b/.local/bin/wrappers/codium
@@ -0,0 +1,2 @@
+#!/bin/sh -eu
+HOME=$HOME/.config && $(which codium --all | grep --invert-match "local/bin" | head -n 1) --extensions-dir "$XDG_DATA_HOME/codium" "$@"
diff --git a/.local/bin/wrappers/eslint b/.local/bin/wrappers/eslint
new file mode 100755
index 0000000..a122f62
--- /dev/null
+++ b/.local/bin/wrappers/eslint
@@ -0,0 +1,2 @@
+#!/bin/sh -eu
+$(which eslint --all | grep --invert-match "local/bin" | head -n 1) --no-ignore --config "$HOME/.config/eslint/config.yaml" "$@";
diff --git a/.local/bin/wrappers/firefox b/.local/bin/wrappers/firefox
new file mode 100755
index 0000000..ab8c72e
--- /dev/null
+++ b/.local/bin/wrappers/firefox
@@ -0,0 +1,2 @@
+#!/bin/sh -eu
+HOME=$HOME/.config && $(which firefox --all | grep --invert-match "local/bin" | head -n 1) "$@";
diff --git a/.local/bin/wrappers/ghci b/.local/bin/wrappers/ghci
new file mode 100755
index 0000000..75f3577
--- /dev/null
+++ b/.local/bin/wrappers/ghci
@@ -0,0 +1,2 @@
+#!/bin/sh -eu
+HOME=$HOME/.config && $(which ghci --all | grep --invert-match "local/bin" | head -n 1) "$@";
diff --git a/.local/bin/wrappers/git b/.local/bin/wrappers/git
new file mode 100755
index 0000000..d321469
--- /dev/null
+++ b/.local/bin/wrappers/git
@@ -0,0 +1,12 @@
+#!/bin/sh -eu
+
+GIT=$(which git --all | grep --invert-match "local/bin" | head --lines 1)
+GIT_COMMITTER_DATE="$(date --utc --date '0' '+%a %b %d %H:%M:%S %Y %z')"
+
+export GIT_COMMITTER_DATE
+
+[ "${1:-}" = "commit" ] && export DATE=1 && $GIT "$@" --date="$GIT_COMMITTER_DATE"
+
+[ "${DATE:-}" = 1 ] && exit
+
+$GIT "$@"
diff --git a/.local/bin/wrappers/gnaural b/.local/bin/wrappers/gnaural
new file mode 100755
index 0000000..cb63d08
--- /dev/null
+++ b/.local/bin/wrappers/gnaural
@@ -0,0 +1,2 @@
+#!/bin/sh -eu
+HOME=$HOME/.config && $(which gnaural --all | grep --invert-match "local/bin" | head -n 1) "$@";
diff --git a/.local/bin/wrappers/google-chrome b/.local/bin/wrappers/google-chrome
new file mode 100755
index 0000000..b9c406f
--- /dev/null
+++ b/.local/bin/wrappers/google-chrome
@@ -0,0 +1,13 @@
+#!/bin/sh -eu
+
+$(which google-chrome-stable --all | grep --invert-match "local/bin" | head -n 1) \
+ --disable-smooth-scrolling \
+ --disable-sync-preferences \
+ --process-per-site \
+ "$@";
+
+# --incognito
+# --disable-gpu-compositing
+# --disk-cache-dir=/dev/null
+# --enable-native-gpu-memory-buffers
+# --proxy-server="socks5://localhost:2871"
diff --git a/.local/bin/wrappers/gore b/.local/bin/wrappers/gore
new file mode 100755
index 0000000..af19cab
--- /dev/null
+++ b/.local/bin/wrappers/gore
@@ -0,0 +1,2 @@
+#!/bin/sh -eu
+HOME=$HOME/.config && $(which gore --all | grep --invert-match "local/bin" | head -n 1) "$@";
diff --git a/.local/bin/wrappers/guile b/.local/bin/wrappers/guile
new file mode 100755
index 0000000..1a5b4d8
--- /dev/null
+++ b/.local/bin/wrappers/guile
@@ -0,0 +1,2 @@
+#!/bin/sh -eu
+HOME=$HOME/.config && $(which guile --all | grep --invert-match "local/bin" | head --lines 1) "$@";
diff --git a/.local/bin/wrappers/latexindent b/.local/bin/wrappers/latexindent
new file mode 100755
index 0000000..44e7459
--- /dev/null
+++ b/.local/bin/wrappers/latexindent
@@ -0,0 +1,8 @@
+#!/bin/sh -eu
+$(which latexindent --all | grep --invert-match "local/bin" | head -n 1) \
+ --modifylinebreaks \
+ --overwrite \
+ --silent \
+ --cruft=/tmp \
+ --local="$HOME/.config/latexindent/settings.yaml" \
+ "$@";
diff --git a/.local/bin/wrappers/mix b/.local/bin/wrappers/mix
new file mode 100755
index 0000000..c687a2d
--- /dev/null
+++ b/.local/bin/wrappers/mix
@@ -0,0 +1,2 @@
+#!/bin/sh -eu
+HOME=$HOME/.config && $(which mix --all | grep --invert-match "local/bin" | head -n 1) "$@";
diff --git a/.local/bin/wrappers/mocp b/.local/bin/wrappers/mocp
new file mode 100755
index 0000000..8828b25
--- /dev/null
+++ b/.local/bin/wrappers/mocp
@@ -0,0 +1,2 @@
+#!/bin/sh -eu
+$(which mocp --all | grep --invert-match "local/bin" | head --lines 1) -M "$HOME/.config/moc" "$@"
diff --git a/.local/bin/wrappers/mplayer b/.local/bin/wrappers/mplayer
new file mode 100755
index 0000000..8554a81
--- /dev/null
+++ b/.local/bin/wrappers/mplayer
@@ -0,0 +1,3 @@
+#!/bin/sh -eu
+export MPLAYER_HOME="$XDG_CONFIG_HOME/mplayer"
+$(which mplayer --all | grep --invert-match "local/bin" | head -n 1) "$@"
diff --git a/.local/bin/wrappers/nix-index b/.local/bin/wrappers/nix-index
new file mode 100755
index 0000000..96c3990
--- /dev/null
+++ b/.local/bin/wrappers/nix-index
@@ -0,0 +1,16 @@
+#!/bin/sh -eu
+
+# https://github.com/nix-community/nix-index-database?tab=readme-ov-file#ad-hoc-download
+
+Update() {
+ directory=~/.local/share/nix-index
+ file="index-$(uname -m | sed 's/^arm64$/aarch64/')-$(uname | tr '[:lower:]' '[:upper:]')"
+ mkdir --parents $directory && cd $directory
+ wget --quiet --timestamping "https://github.com/Mic92/nix-index-database/releases/latest/download/$file"
+ printf "\nUpdating database %s\n\n" "$file"
+ ln --symbolic --force "$file" files
+}
+
+Update
+
+$(which nix-index --all | grep --invert-match "local/bin" | head --lines 1) "$@"
diff --git a/.local/bin/wrappers/palemoon b/.local/bin/wrappers/palemoon
new file mode 100755
index 0000000..caef463
--- /dev/null
+++ b/.local/bin/wrappers/palemoon
@@ -0,0 +1,2 @@
+#!/bin/sh -eu
+HOME=$HOME/.config && $(which palemoon --all | grep --invert-match "local/bin" | head -n 1) "$@";
diff --git a/.local/bin/wrappers/prettier b/.local/bin/wrappers/prettier
new file mode 100755
index 0000000..94fd412
--- /dev/null
+++ b/.local/bin/wrappers/prettier
@@ -0,0 +1,2 @@
+#!/bin/sh -eu
+$(which prettier --all | grep --invert-match "local/bin" | head -n 1) --config "$HOME/.config/prettier/config.yaml" "$@";
diff --git a/.local/bin/wrappers/sbcl b/.local/bin/wrappers/sbcl
new file mode 100755
index 0000000..b5ba6ea
--- /dev/null
+++ b/.local/bin/wrappers/sbcl
@@ -0,0 +1,2 @@
+#!/bin/sh -eu
+HOME=$HOME/.config && $(which sbcl --all | grep --invert-match "local/bin" | head -n 1) "$@";
diff --git a/.local/bin/wrappers/scribus b/.local/bin/wrappers/scribus
new file mode 100755
index 0000000..c77ac6b
--- /dev/null
+++ b/.local/bin/wrappers/scribus
@@ -0,0 +1,2 @@
+#!/bin/sh -eu
+HOME=$HOME/.config && $(which scribus --all | grep --invert-match "local/bin" | head -n 1) "$@";
diff --git a/.local/bin/wrappers/stalonetray b/.local/bin/wrappers/stalonetray
new file mode 100755
index 0000000..bcdf87c
--- /dev/null
+++ b/.local/bin/wrappers/stalonetray
@@ -0,0 +1,6 @@
+#!/bin/sh -eu
+$(which stalonetray --all | grep --invert-match "local/bin" | head -n 1) \
+ --background '#000000' \
+ --window-type normal \
+ --window-strut none \
+ "$@";
diff --git a/.local/bin/wrappers/stylelint b/.local/bin/wrappers/stylelint
new file mode 100755
index 0000000..d0efb27
--- /dev/null
+++ b/.local/bin/wrappers/stylelint
@@ -0,0 +1,2 @@
+#!/bin/sh -eu
+$(which stylelint --all | grep --invert-match "local/bin" | head -n 1) --config "$HOME/.config/stylelint/config.js" "$@";
diff --git a/.local/bin/wrappers/svn b/.local/bin/wrappers/svn
new file mode 100755
index 0000000..77fdbdb
--- /dev/null
+++ b/.local/bin/wrappers/svn
@@ -0,0 +1,2 @@
+#!/bin/sh -eu
+$(which svn --all | grep --invert-match "local/bin" | head -n 1) --config-dir "$XDG_CONFIG_HOME"/subversion "$@";
diff --git a/.local/bin/wrappers/swc b/.local/bin/wrappers/swc
new file mode 100755
index 0000000..c352781
--- /dev/null
+++ b/.local/bin/wrappers/swc
@@ -0,0 +1,2 @@
+#!/bin/sh -eu
+$(which swc --all | grep --invert-match "local/bin" | head --lines 1) "$@" --config-file "$HOME/.config/swc/swc.json"
diff --git a/.local/bin/wrappers/tiemu b/.local/bin/wrappers/tiemu
new file mode 100755
index 0000000..310f7dc
--- /dev/null
+++ b/.local/bin/wrappers/tiemu
@@ -0,0 +1,2 @@
+#!/bin/sh -eu
+HOME=$HOME/.config && $(which tiemu --all | grep --invert-match "local/bin" | head -n 1) "$@";
diff --git a/.local/bin/wrappers/tilp b/.local/bin/wrappers/tilp
new file mode 100755
index 0000000..4f07917
--- /dev/null
+++ b/.local/bin/wrappers/tilp
@@ -0,0 +1,2 @@
+#!/bin/sh -eu
+HOME=$HOME/.config && $(which tilp --all | grep --invert-match "local/bin" | head -n 1) "$@";
diff --git a/.local/bin/wrappers/treesheets b/.local/bin/wrappers/treesheets
new file mode 100755
index 0000000..956277b
--- /dev/null
+++ b/.local/bin/wrappers/treesheets
@@ -0,0 +1,2 @@
+#!/bin/sh -eu
+HOME=$HOME/.config && $(which treesheets --all | grep --invert-match "local/bin" | head -n 1) "$@";
diff --git a/.local/bin/vale b/.local/bin/wrappers/vale
index fb86fde..f5863f2 100755
--- a/.local/bin/vale
+++ b/.local/bin/wrappers/vale
@@ -13,4 +13,4 @@ if [ "${1:-}" = "--update" ]; then
exit;
fi
-$(which vale --all | grep -v "local/bin" | head -n 1) --config "$directory/vale.ini" "$@";
+$(which vale --all | grep --invert-match "local/bin" | head -n 1) --config "$directory/vale.ini" "$@";
diff --git a/.local/bin/wrappers/w3m b/.local/bin/wrappers/w3m
new file mode 100755
index 0000000..f2c62b4
--- /dev/null
+++ b/.local/bin/wrappers/w3m
@@ -0,0 +1,2 @@
+#!/bin/sh -eu
+HOME=$HOME/.config && $(which w3m --all | grep --invert-match "local/bin" | head -n 1) "$@";
diff --git a/.local/bin/wrappers/wget b/.local/bin/wrappers/wget
new file mode 100755
index 0000000..9f06fce
--- /dev/null
+++ b/.local/bin/wrappers/wget
@@ -0,0 +1,2 @@
+#!/bin/sh -eu
+$(which wget --all | grep --invert-match "local/bin" | head -n 1) --hsts-file "$HOME/.cache/wget.history" "$@";
diff --git a/.local/bin/wrappers/xournalpp b/.local/bin/wrappers/xournalpp
new file mode 100755
index 0000000..3601bbf
--- /dev/null
+++ b/.local/bin/wrappers/xournalpp
@@ -0,0 +1,2 @@
+#!/bin/sh -eu
+HOME=$HOME/.config && $(which xournalpp --all | grep --invert-match "local/bin" | head -n 1) "$@";
diff --git a/.local/bin/wrappers/xsane b/.local/bin/wrappers/xsane
new file mode 100755
index 0000000..2edfe09
--- /dev/null
+++ b/.local/bin/wrappers/xsane
@@ -0,0 +1,2 @@
+#!/bin/sh -eu
+HOME=$HOME/.config && $(which xsane --all | grep --invert-match "local/bin" | head -n 1) "$@";
diff --git a/.local/bin/xdg-open b/.local/bin/xdg-open
index 5278183..cdb4269 100755
--- a/.local/bin/xdg-open
+++ b/.local/bin/xdg-open
@@ -1,2 +1,4 @@
-#!/bin/sh
-mimeo --term "urxvt -e %s" --deprecated "$@";
+#!/bin/sh -eu
+
+term="$TERMINAL -e %s"
+mimeo --term "$term" --deprecated "$@"
diff --git a/.local/bin/xrandr-scale b/.local/bin/xrandr-scale
index f5d3c2e..bdb92bd 100755
--- a/.local/bin/xrandr-scale
+++ b/.local/bin/xrandr-scale
@@ -1,2 +1,3 @@
-#!/bin/sh
+#!/bin/sh -eu
+# TODO: Output can change default $1 to first known monitor.
xrandr --output "$1" --scale "$2"x"$2"