summaryrefslogtreecommitdiff
path: root/mut/bin
diff options
context:
space:
mode:
Diffstat (limited to 'mut/bin')
-rw-r--r--mut/bin/checkout69
-rwxr-xr-xmut/bin/compile40
-rwxr-xr-xmut/bin/filter-ansi2
-rwxr-xr-xmut/bin/get-sshables7
-rwxr-xr-xmut/bin/kakup100
-rw-r--r--mut/bin/kubeconfig-merge3
-rw-r--r--mut/bin/lfub24
-rwxr-xr-xmut/bin/linkhandler26
-rw-r--r--mut/bin/mailsync112
-rw-r--r--mut/bin/maimpick18
-rwxr-xr-xmut/bin/news5
-rwxr-xr-xmut/bin/nixup94
-rw-r--r--mut/bin/notmuch-hook17
-rw-r--r--mut/bin/openfile10
-rwxr-xr-xmut/bin/pass-ansible-vault-client17
-rw-r--r--mut/bin/sb-battery37
-rw-r--r--mut/bin/sb-clock29
-rw-r--r--mut/bin/sb-internet26
-rw-r--r--mut/bin/sb-mailbox20
-rw-r--r--mut/bin/sb-nettraf29
-rw-r--r--mut/bin/sb-news17
-rw-r--r--mut/bin/set-bg15
-rw-r--r--mut/bin/spectrwmbar59
-rwxr-xr-xmut/bin/sysact21
-rwxr-xr-xmut/bin/terragrunt94
-rw-r--r--mut/bin/tmux-normal-mode28
-rw-r--r--mut/bin/transadd9
27 files changed, 928 insertions, 0 deletions
diff --git a/mut/bin/checkout b/mut/bin/checkout
new file mode 100644
index 0000000..95f28c8
--- /dev/null
+++ b/mut/bin/checkout
@@ -0,0 +1,69 @@
+#!@bash@/bin/bash
+error () {
+ echo "$1"
+ exit 1
+}
+
+. <(pass show work/env)
+DEST_DIR=""
+case "${@}" in
+ az|"az "*)
+ shift
+ LIST_PROJECTS="/_apis/projects?api-version=7.1-preview.4"
+ AUTH_HEADER="Authorization: Basic $(echo -n ":$GIT_PASS" | base64)"
+ LIST_REPOSITORIES="/_apis/git/repositories?api-version=7.1-preview.1"
+ GIT_DIR="$HOME/projects/"
+ if [ ! -d $GIT_DIR ]; then
+ mkdir -p $GIT_DIR
+ fi
+ MAX_REPOS=20
+
+ echo "curl -s -H \"$AUTH_HEADER\" $WORK_AZDO_GIT_ORG_URL$LIST_PROJECTS"
+ PROJECT=$(curl -s -H "$AUTH_HEADER" $WORK_AZDO_GIT_ORG_URL$LIST_PROJECTS \
+ | jq '
+ .value[].name
+ ' \
+ | xargs -I{} bash -c "
+ curl -s -H '$AUTH_HEADER' $WORK_AZDO_GIT_ORG_URL/{}$LIST_REPOSITORIES \
+ | jq '
+ .value[].name
+ ' \
+ | awk '{ gsub(/\"/, \"\", \$1); printf \"{}/_git/%s\\n\", \$1 }'
+ " \
+ | fzf)
+
+ DEST_DIR="$GIT_DIR/$(echo $PROJECT | cut -d '/' -f3)"
+ if [ ! -d $DEST_DIR ]
+ then
+ git clone --bare $WORK_AZDO_GIT_ORG_URL/$PROJECT $DEST_DIR
+ fi
+ ;;
+ gh|"gh "*)
+ shift
+ repo=$(gh repo list --json owner,name -q '.[] | "\(.owner.login)/\(.name)"' | fzf --print-query -1)
+ GIT_DIR="$HOME/projects"
+ if [ ! -d $GIT_DIR ]; then
+ mkdir -p $GIT_DIR
+ fi
+
+ if [[ "$(echo "$repo" | wc -l)" -ne 1 ]]; then
+ echo "Fetching my repo"
+ repo="$(echo "$repo" | tail -n1)"
+ fi
+
+ DEST_DIR="$GIT_DIR/$(echo $repo | cut -d '/' -f2)"
+ if [ ! -d $DEST_DIR ]
+ then
+ gh repo clone $repo $DEST_DIR -- --bare
+ fi
+ ;;
+ *)
+ error "Don't know how to fetch this"
+ ;;
+esac
+
+if ! [[ -z "$DEST_DIR" ]]; then
+ cd $DEST_DIR
+ git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*"
+ $EDITOR "$DEST_DIR"
+fi
diff --git a/mut/bin/compile b/mut/bin/compile
new file mode 100755
index 0000000..04c0586
--- /dev/null
+++ b/mut/bin/compile
@@ -0,0 +1,40 @@
+#!@bash@/bin/bash
+echo " Compiliiing ${@}"
+
+error () {
+ echo "$1"
+ exit 1
+}
+
+case "${@}" in
+ racket*)
+ shift
+ echo " \-> racket -l errortrace -t ${@}"
+ racket -l errortrace -t ${@}
+ ;;
+ ansible-lint*)
+ shift
+ echo " \-> ansible-lint --profile production --write=all -qq --nocolor"
+ ansible-lint --profile production --write=all -qq --nocolor ${@}
+ ;;
+ ansible-playbook*)
+ shift
+ echo " \-> ansible-playbook -e@<(pass)"
+ ansible-playbook -b -e "{\"ansible_become_pass\":\"$PASSWORD\"}" ${@}
+ ;;
+ awx*)
+ echo " \-> awx"
+ shift
+ awx "$@" | filter-ansi
+ ;;
+ helm\ lint*)
+ shift
+ shift
+ echo " \-> helm lint --set cluster=debug-cluster --strict --quiet --with-subcharts ${@}"
+ helm lint --set cluster=debug-cluster --strict --quiet --with-subcharts ${@} | sed -u -E -e "s@$(basename ${PWD})/|error during tpl function execution for \".*\"@@g"
+ ;;
+ *)
+ echo " \-> ${@}"
+ ${@}
+ ;;
+esac
diff --git a/mut/bin/filter-ansi b/mut/bin/filter-ansi
new file mode 100755
index 0000000..369f9fd
--- /dev/null
+++ b/mut/bin/filter-ansi
@@ -0,0 +1,2 @@
+# #!@bash@/bin/bash
+cat -u - | sed -u -E -e 's/\x1b\[[0-9;]*[mGKHF]|\r//g'
diff --git a/mut/bin/get-sshables b/mut/bin/get-sshables
new file mode 100755
index 0000000..f67c23c
--- /dev/null
+++ b/mut/bin/get-sshables
@@ -0,0 +1,7 @@
+#!/bin/bash
+set -euxo pipefail
+[[ -d ~/sshables ]] || mkdir -p ~/sshables
+
+for cluster in $(kubectl config get-clusters | tail -n +2); do
+ [[ -f ~/sshables/$cluster ]] || { echo $cluster; kubectl --context $cluster get nodes -oname > ~/sshables/$cluster; }
+done
diff --git a/mut/bin/kakup b/mut/bin/kakup
new file mode 100755
index 0000000..af1a520
--- /dev/null
+++ b/mut/bin/kakup
@@ -0,0 +1,100 @@
+#!@bash@/bin/bash
+session-or-client() {
+ {
+ project="$(cat -)"
+ if [[ -z $project ]]; then
+ return
+ fi
+ pushd $project
+ name=${PWD#$HOME/}
+ name=${name//\//-}
+ name=${name#-}
+ server=kaks@$name
+ client=kakc@$name
+ TMUX_ENV="-e KAK_SERVER=$server -e KAK_CLIENT=$client"
+
+ tmux has-session -t $server || {
+ tmux new $TMUX_ENV -d -s $server -n $server bash -c '[[ -f .envrc ]] && eval "$(direnv export bash)"; { kak -s '$name' -d & }; tmux wait -S '$name'; wait'
+ tmux wait "$name"
+ }
+ if [[ -z $TMUX ]] || [ $SWITCH_TO_SESSION -eq 1 ]; then
+ tmux has-session -t $client || tmux new $TMUX_ENV -d -s $client -n $client kak -c $name
+ fi
+ popd
+ } </dev/stdin >debug 2>&1
+ echo $client
+}
+
+search() {
+ if tty -s
+ then
+ project="$(fd -d1 "." -t d $HOME $HOME/projects | fzf -1)"
+ else
+ output=$(mktemp -d /tmp/kakup.XXXXXXXX)/fifo
+ mkfifo ${output}
+ st -e bash -c "fd -d1 '.' -t d $HOME $HOME/projects | fzf -1 | tee ${output} >/dev/null 2>&1" &
+ project="$(cat ${output})"
+ rm -r $(dirname ${output})
+ fi
+
+ pushd $project >/dev/null 2>&1
+ if grep 'bare = true' config >/dev/null 2>&1 ; then
+ if tty -s
+ then
+ branch="$(git branch -a --format '%(refname)' | fzf -1)"
+ else
+ output=$(mktemp -d /tmp/kakup.XXXXXXXX)/fifo
+ mkfifo ${output}
+ st -e bash -c "git branch -a --format '%(refname)' | fzf -1 >${output}" &
+ branch="$(cat ${output})"
+ rm -r $(dirname ${output})
+ fi
+ echo "$branch" >debug 2>&1
+ if [[ "$branch" == "refs/remotes/"* ]]; then
+ git branch ${branch#refs/remotes/*/} -t $branch >debug 2>&1
+ git worktree add ${branch#refs/remotes/*/} ${branch#refs/remotes/*/} >debug 2>&1
+ branch="${branch#refs/remotes/*/}"
+ elif [[ "$branch" == "refs/heads/"* ]]; then
+ branch="${branch#refs/heads/}"
+ git worktree add $branch $branch >debug 2>&1
+ fi
+ echo "$project/$branch"
+ else
+ echo "$project"
+ fi
+ popd >/dev/null 2>&1
+}
+
+NEW_TERM=0
+SWITCH_TO_SESSION=0
+while getopts "tfF" opt; do
+ case "$opt" in
+ h|\?) exit 0 ;;
+ t) NEW_TERM=1 ;;
+ f) client="$(search | session-or-client)" ;;
+ F) SWITCH_TO_SESSION=1; client="$(search | session-or-client)" ;;
+ esac
+done
+
+shift $((OPTIND - 1))
+
+[ -z "$client" ] && {
+ case "${@}" in
+ "") client="$(pwd | session-or-client)" ;;
+ *) client="$(echo "${@}" | session-or-client)" ;;
+ esac
+}
+
+[[ ! -z "$client" ]] && {
+ if [ $NEW_TERM -eq 1 ]; then
+ st -e tmux attach -t "$client"
+ elif [[ -z $TMUX ]]; then
+ tmux attach -t "$client"
+ else
+ if [ $SWITCH_TO_SESSION -eq 0 ]; then
+ tmux new-window -n $client kak -c ${client##kakc@}
+ else
+ tmux switch -t $client
+ fi
+ fi
+}
diff --git a/mut/bin/kubeconfig-merge b/mut/bin/kubeconfig-merge
new file mode 100644
index 0000000..73d3ac1
--- /dev/null
+++ b/mut/bin/kubeconfig-merge
@@ -0,0 +1,3 @@
+#!@bash@/bin/bash
+cp $HOME/.kube/config /tmp/.kube_config
+KUBECONFIG=$1:/tmp/.kube_config kubectl config view --flatten > $HOME/.kube/config
diff --git a/mut/bin/lfub b/mut/bin/lfub
new file mode 100644
index 0000000..9012f50
--- /dev/null
+++ b/mut/bin/lfub
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+# This is a wrapper script for lb that allows it to create image previews with
+# ueberzug. This works in concert with the lf configuration file and the
+# lf-cleaner script.
+
+set -e
+
+cleanup() {
+ exec 3>&-
+ rm "$FIFO_UEBERZUG"
+}
+
+if [ -n "$SSH_CLIENT" ] || [ -n "$SSH_TTY" ]; then
+ lf "$@"
+else
+ [ ! -d "$HOME/.cache/lf" ] && mkdir -p "$HOME/.cache/lf"
+ export FIFO_UEBERZUG="$HOME/.cache/lf/ueberzug-$$"
+ mkfifo "$FIFO_UEBERZUG"
+ ueberzug layer -s <"$FIFO_UEBERZUG" -p json &
+ exec 3>"$FIFO_UEBERZUG"
+ trap cleanup HUP INT QUIT TERM PWR EXIT
+ lf "$@" 3>&-
+fi
diff --git a/mut/bin/linkhandler b/mut/bin/linkhandler
new file mode 100755
index 0000000..f62b581
--- /dev/null
+++ b/mut/bin/linkhandler
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+# Feed script a url or file location.
+# If an image, it will view in sxiv,
+# if a video or gif, it will view in mpv
+# if a music file or pdf, it will download,
+# otherwise it opens link in browser.
+
+if [ -z "$1" ]; then
+ url="$(xclip -o)"
+else
+ url="$1"
+fi
+
+case "$url" in
+ *mkv|*webm|*mp4|*youtube.com/watch*|*youtube.com/playlist*|*youtube.com/shorts*|*youtu.be*|*hooktube.com*|*bitchute.com*|*videos.lukesmith.xyz*|*odysee.com*)
+ setsid -f mpv -quiet "$url" >/dev/null 2>&1 ;;
+ *png|*jpg|*jpe|*jpeg|*gif)
+ curl -sL "$url" > "/tmp/$(echo "$url" | sed "s/.*\///;s/%20/ /g")" && sxiv -a "/tmp/$(echo "$url" | sed "s/.*\///;s/%20/ /g")" >/dev/null 2>&1 & ;;
+ *pdf|*cbz|*cbr)
+ curl -sL "$url" > "/tmp/$(echo "$url" | sed "s/.*\///;s/%20/ /g")" && zathura "/tmp/$(echo "$url" | sed "s/.*\///;s/%20/ /g")" >/dev/null 2>&1 & ;;
+ *mp3|*flac|*opus|*mp3?source*)
+ qndl "$url" 'curl -LO' >/dev/null 2>&1 ;;
+ *)
+ [ -f "$url" ] && setsid -f "$TERMINAL" -e "$EDITOR" "$url" >/dev/null 2>&1 || setsid -f "$BROWSER" "$url" >/dev/null 2>&1
+esac
diff --git a/mut/bin/mailsync b/mut/bin/mailsync
new file mode 100644
index 0000000..426e5b7
--- /dev/null
+++ b/mut/bin/mailsync
@@ -0,0 +1,112 @@
+#!/bin/sh
+
+# - Syncs mail for all accounts, or a single account given as an argument.
+# - Displays a notification showing the number of new mails.
+# - Displays a notification for each new mail with its subject displayed.
+# - Runs notmuch to index new mail.
+# - This script can be set up as a cron job for automated mail syncing.
+
+# There are many arbitrary and ugly features in this script because it is
+# inherently difficult to pass environmental variables to cronjobs and other
+# issues. It also should at least be compatible with Linux (and maybe BSD) with
+# Xorg and MacOS as well.
+
+# Run only if not already running in other instance
+pgrep mbsync >/dev/null && { echo "mbsync is already running."; exit ;}
+
+# First, we have to get the right variables for the mbsync file, the pass
+# archive, notmuch and the GPG home. This is done by searching common profile
+# files for variable assignments. This is ugly, but there are few options that
+# will work on the maximum number of machines.
+eval "$(grep -h -- \
+ "^\s*\(export \)\?\(MBSYNCRC\|MPOPRC\|PASSWORD_STORE_DIR\|PASSWORD_STORE_GPG_OPTS\|NOTMUCH_CONFIG\|GNUPGHOME\|MAILSYNC_MUTE\|XDG_CONFIG_HOME\|XDG_DATA_HOME\)=" \
+ "$HOME/.profile" "$HOME/.bash_profile" "$HOME/.zprofile" "$HOME/.config/zsh/.zprofile" "$HOME/.zshenv" \
+ "$HOME/.config/zsh/.zshenv" "$HOME/.bashrc" "$HOME/.zshrc" "$HOME/.config/zsh/.zshrc" \
+ "$HOME/.pam_environment" 2>/dev/null)"
+
+export GPG_TTY="$(tty)"
+
+[ -n "$MBSYNCRC" ] && alias mbsync="mbsync -c $MBSYNCRC" || MBSYNCRC="$HOME/.mbsyncrc"
+[ -n "$MPOPRC" ] || MPOPRC="$HOME/.config/mpop/config"
+
+lastrun="${XDG_CONFIG_HOME:-$HOME/.config}/neomutt/.mailsynclastrun"
+
+# Settings are different for MacOS (Darwin) systems.
+case "$(uname)" in
+ Darwin) notify() { osascript -e "display notification \"$2\" with title \"$1\"" ;} ;;
+ *)
+ case "$(readlink -f /sbin/init)" in
+ *systemd*|*openrc*) export DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$(id -u)/bus ;;
+ esac
+ # remember if a display server is running since `ps` doesn't always contain a display
+ pgrepoutput="$(pgrep -ax X\(\|org\|wayland\))"
+ displays="$(echo "$pgrepoutput" | grep -wo "[0-9]*:[0-9]\+" | sort -u)"
+ [ -z "$displays" ] && [ -d /tmp/.X11-unix ] && displays=$(cd /tmp/.X11-unix && for x in X*; do echo ":${x#X}"; done)
+
+ notify() { [ -n "$pgrepoutput" ] && for x in ${displays:-:0}; do
+ export DISPLAY="$x"
+ notify-send --app-name="mutt-wizard" "$1" "$2"
+ done ;}
+ ;;
+esac
+
+# Check account for new mail. Notify if there is new content.
+syncandnotify() {
+ case "$1" in
+ imap) mbsync -q "$2" ;;
+ pop) mpop -q "$2" ;;
+ esac
+ new=$(find\
+ "$HOME/.local/share/mail/${2%%-*}/"[Ii][Nn][Bb][Oo][Xx]/new/ \
+ "$HOME/.local/share/mail/${2%%-*}/"[Ii][Nn][Bb][Oo][Xx]/cur/ \
+ -type f -newer "$lastrun" 2> /dev/null)
+ newcount=$(echo "$new" | sed '/^\s*$/d' | wc -l)
+ case 1 in
+ $((newcount > 5)) )
+ echo "$newcount new mail for $2."
+ [ -z "$MAILSYNC_MUTE" ] && notify "New Mail!" "📬 $newcount new mail(s) in \`$2\` account."
+ ;;
+ $((newcount > 0)) )
+ echo "$newcount new mail for $2."
+ [ -z "$MAILSYNC_MUTE" ] &&
+ for file in $new; do
+ # Extract and decode subject and sender from mail.
+ subject="$(sed -n "/^Subject:/ s|Subject: *|| p" "$file" |
+ perl -CS -MEncode -ne 'print decode("MIME-Header", $_)')"
+ from="$(sed -n "/^From:/ s|From: *|| p" "$file" |
+ perl -CS -MEncode -ne 'print decode("MIME-Header", $_)')"
+ from="${from% *}" ; from="${from%\"}" ; from="${from#\"}"
+ notify "📧$from:" "$subject"
+ done
+ ;;
+ *) echo "No new mail for $2." ;;
+esac
+}
+
+allgroups="$(grep -hs "Group" "$MBSYNCRC" "$MPOPRC" | sort -u)"
+
+# Get accounts to sync. All if no argument. Prefix with `error` if non-existent.
+IFS='
+'
+if [ -z "$1" ]; then
+ tosync="$allgroups"
+else
+ tosync="$(for arg in "$@"; do for grp in $allgroups; do
+ [ "$arg" = "${grp##* }" ] && echo "$grp" && break
+ done || echo "error $arg"; done)"
+fi
+
+for grp in $tosync; do
+ case $grp in
+ Group*) syncandnotify imap "${grp##* }" & ;;
+ account*) syncandnotify pop "${grp##* }" & ;;
+ error*) echo "ERROR: Account ${channelt##* } not found." ;;
+ esac
+done
+
+wait
+
+notmuch-hook
+
+#Create a touch file that indicates the time of the last run of mailsync
+touch "$lastrun"
diff --git a/mut/bin/maimpick b/mut/bin/maimpick
new file mode 100644
index 0000000..5de26c1
--- /dev/null
+++ b/mut/bin/maimpick
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+# This is bound to Shift+PrintScreen by default, requires maim. It lets you
+# choose the kind of screenshot to take, including copying the image or even
+# highlighting an area to copy. scrotcucks on suicidewatch right now.
+
+# variables
+output="$(date '+%y%m%d-%H%M-%S').png"
+xclip_cmd="xclip -sel clip -t image/png"
+
+case "$(printf "a selected area\\ncurrent window\\nfull screen\\na selected area (copy)\\ncurrent window (copy)\\nfull screen (copy)" | dmenu -l 6 -i -p "Screenshot which area?")" in
+ "a selected area") maim -u -s pic-selected-"${output}" ;;
+ "current window") maim -q -d 0.2 -i "$(xdotool getactivewindow)" pic-window-"${output}" ;;
+ "full screen") maim -q -d 0.2 pic-full-"${output}" ;;
+ "a selected area (copy)") maim -u -s | ${xclip_cmd} ;;
+ "current window (copy)") maim -q -d 0.2 -i "$(xdotool getactivewindow)" | ${xclip_cmd} ;;
+ "full screen (copy)") maim -q -d 0.2 | ${xclip_cmd} ;;
+esac
diff --git a/mut/bin/news b/mut/bin/news
new file mode 100755
index 0000000..097582b
--- /dev/null
+++ b/mut/bin/news
@@ -0,0 +1,5 @@
+#!@bash@/bin/bash
+cat <(cat ~/.config/newsboat/urls) <(for url in $(env | grep NEWSBOAT_URL_); do
+ printf '%s\n' ${url#NEWSBOAT_URL_*=}
+done) > ~/.newsboat-urls
+newsboat -u ~/.newsboat-urls
diff --git a/mut/bin/nixup b/mut/bin/nixup
new file mode 100755
index 0000000..afbe4b1
--- /dev/null
+++ b/mut/bin/nixup
@@ -0,0 +1,94 @@
+#!@bash@/bin/bash
+case "${@}" in
+ bootstrap-store)
+ [[ -d ${HOME}/nix ]] || {
+ docker create --name nix-data-${USER} nixos/nix sh >/dev/null 2>&1
+ sudo docker cp nix-data-${USER}:/nix ~
+ docker rm nix-data-${USER}
+ }
+ docker create -v ${HOME}/nix:/nix --name nix-data-${USER} nixos/nix sh
+ ;;
+ nuke)
+ docker rm nix-data-${USER}
+ docker rm nixos-${USER}
+ ;;
+ "")
+ if ! docker image ls | grep nixos-${USER}; then
+ cat > /tmp/docker-build-${USER} <<EOF
+FROM alpine
+
+# Enable HTTPS support in wget and set nsswitch.conf to make resolution work within containers
+RUN apk add --no-cache --update openssl \
+ && echo hosts: files dns > /etc/nsswitch.conf
+
+# Download Nix and install it into the system.
+ARG NIX_VERSION=2.3.14
+RUN wget https://nixos.org/releases/nix/nix-\${NIX_VERSION}/nix-\${NIX_VERSION}-\$(uname -m)-linux.tar.xz \
+ && tar xf nix-\${NIX_VERSION}-\$(uname -m)-linux.tar.xz \
+ && addgroup -g 30000 -S nixbld \
+ && for i in \$(seq 1 30); do adduser -S -D -h /var/empty -g "Nix build user \$i" -u \$((30000 + i)) -G nixbld nixbld\$i ; done \
+ && mkdir -m 0755 /etc/nix \
+ && echo 'sandbox = false' > /etc/nix/nix.conf \
+ && mkdir -m 0755 /nix && USER=root sh nix-\${NIX_VERSION}-\$(uname -m)-linux/install \
+ && ln -s /nix/var/nix/profiles/default/etc/profile.d/nix.sh /etc/profile.d/ \
+ && rm -r /nix-\${NIX_VERSION}-\$(uname -m)-linux* \
+ && /nix/var/nix/profiles/default/bin/nix-collect-garbage --delete-old \
+ && /nix/var/nix/profiles/default/bin/nix-store --optimise \
+ && /nix/var/nix/profiles/default/bin/nix-store --verify --check-contents
+
+# Somehow this file is missing?
+RUN mkdir -p /etc/bash && touch /etc/bash/bashrc
+
+ONBUILD ENV \
+ ENV=/etc/profile \
+ USER=root \
+ PATH=/nix/var/nix/profiles/default/bin:/nix/var/nix/profiles/default/sbin:/bin:/sbin:/usr/bin:/usr/sbin \
+ GIT_SSL_CAINFO=/etc/ssl/certs/ca-certificates.crt \
+ NIX_SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
+
+ENV \
+ ENV=/etc/profile \
+ USER=root \
+ PATH=/nix/var/nix/profiles/default/bin:/nix/var/nix/profiles/default/sbin:/bin:/sbin:/usr/bin:/usr/sbin \
+ GIT_SSL_CAINFO=/etc/ssl/certs/ca-certificates.crt \
+ NIX_SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt \
+ NIX_PATH=/nix/var/nix/profiles/per-user/root/channels
+
+# Add your user the alpine way
+RUN apk add --no-cache --update shadow \
+ && groupadd -g $(getent group docker | cut -d: -f3) docker \
+ && groupadd -g $(id -g) ${USER} \
+ && useradd -g $(id -g) --groups wheel,docker -u $(id -u) ${USER} \
+ && rm -rf /var/cache/apk/*
+EOF
+ docker build . -t nixos-${USER} -f /tmp/docker-build-${USER}
+ fi
+ docker run --volumes-from=nix-data-${USER} --rm -it \
+ -v /var/run/docker.sock:/var/run/docker.sock \
+ -v /etc/kube:/etc/kube \
+ -v /etc/ssl/certs/ca-bundle.crt:/etc/ssl/certs/ca-bundle.crt \
+ -v /etc/ssl/certs/ca-bundle.crt:/etc/ssl/certs/ca-certificates.crt \
+ -e GIT_SSL_CAINFO=/etc/ssl/certs/ca-bundle.crt \
+ -e NIX_SSL_CERT_FILE=/etc/ssl/certs/ca-bundle.crt \
+ -e SSL_CERT_FILE=/etc/ssl/certs/ca-bundle.crt \
+ -e no_proxy=$no_proxy \
+ -e http_proxy=$http_proxy \
+ -e https_proxy=$http_proxy \
+ -e SHELL=bash \
+ -e USER=${USER} \
+ -u $(id -u):$(id -g) \
+ --group-add wheel \
+ --group-add docker \
+ -v ${HOME}:${HOME} \
+ -w ${HOME} \
+ --name nixos-${USER} \
+ --network host \
+ nixos-${USER} bash --login
+ ;;
+ clear)
+ docker run --rm --volumes-from=nix-data-${USER} nixos/nix nix-collect-garbage -d
+ ;;
+ list)
+ docker run --rm --volumes-from nix-data-${USER} nixos/nix ls -la /nix
+ ;;
+esac
diff --git a/mut/bin/notmuch-hook b/mut/bin/notmuch-hook
new file mode 100644
index 0000000..da376b6
--- /dev/null
+++ b/mut/bin/notmuch-hook
@@ -0,0 +1,17 @@
+. <(pass show personal/notmuch)
+notmuch new --quiet
+notmuch tag -new +unread +jobs -- 'tag:new and (from:jobs-listings* or from:jobs-noreply*)'
+notmuch tag -new +unread +houses -- 'tag:new and (from:"'$MAKELAAR'" or thread:{'$MAKELAAR'})'
+notmuch tag -new -inbox +unread +dev -- 'tag:new and (from:/.*github.com/ or thread:{from:/.*github.com/})'
+
+notmuch tag -new +inbox +unread -- tag:new
+
+# Gmail + mbsync = a lot of duplicates due to the archive
+notmuch tag -new -inbox +archive -- 'folder:/Archive/ -folder:/Inbox/ -folder:/\[Gmail\]/ -folder:/FarDrafts/ -folder:/Important/ -folder:/Sent/'
+
+# Tag messages with files that were moved to trash in neomutt
+notmuch tag --remove-all +trash -- folder:/Trash/
+# Same but with messages with files that were moved to spam
+notmuch tag --remove-all +spam -- folder:/Spam/
+# Remove files of messages that were tagged but still have files left behind in the mailbox, should be fine since gmail already keeps a duplicate in the Archive so the message will not be deleted only one file of the message
+notmuch search --output=files -- 'folder:/Inbox/ -tag:inbox' | grep Inbox | xargs >/dev/null 2>&1 rm
diff --git a/mut/bin/openfile b/mut/bin/openfile
new file mode 100644
index 0000000..0f60b10
--- /dev/null
+++ b/mut/bin/openfile
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+# Helps open a file with xdg-open from mutt in a external program without weird side effects.
+tempdir="${XDG_CACHE_HOME:-$HOME/.cache}/mutt-wizard/files"
+file="$tempdir/${1##*/}"
+[ "$(uname)" = "Darwin" ] && opener="open" || opener="setsid -f xdg-open"
+mkdir -p "$tempdir"
+cp -f "$1" "$file"
+$opener "$file" >/dev/null 2>&1
+find "${tempdir:?}" -mtime +1 -type f -delete
diff --git a/mut/bin/pass-ansible-vault-client b/mut/bin/pass-ansible-vault-client
new file mode 100755
index 0000000..8b8d026
--- /dev/null
+++ b/mut/bin/pass-ansible-vault-client
@@ -0,0 +1,17 @@
+#!@bash@/bin/bash
+VAULT_ID=""
+while [[ $# -gt 0 ]]; do
+ case $1 in
+ --vault-id)
+ VAULT_ID=$2
+ shift
+ shift
+ ;;
+ --vault-id=*)
+ VAULT_ID="${1#*=}"
+ shift
+ ;;
+ esac
+done
+
+pass show work/ansible-vault/$VAULT_ID
diff --git a/mut/bin/sb-battery b/mut/bin/sb-battery
new file mode 100644
index 0000000..aeb7413
--- /dev/null
+++ b/mut/bin/sb-battery
@@ -0,0 +1,37 @@
+#!/bin/sh
+
+# Prints all batteries, their percentage remaining and an emoji corresponding
+# to charge status (🔌 for plugged up, 🔋 for discharging on battery, etc.).
+
+case $BUTTON in
+ 3) notify-send "🔋 Battery module" "🔋: discharging
+🛑: not charging
+♻: stagnant charge
+🔌: charging
+⚡: charged
+❗: battery very low!
+- Scroll to change adjust xbacklight." ;;
+ 4) xbacklight -inc 10 ;;
+ 5) xbacklight -dec 10 ;;
+ 6) "$TERMINAL" -e "$EDITOR" "$0" ;;
+esac
+
+# Loop through all attached batteries and format the info
+for battery in /sys/class/power_supply/BAT?*; do
+ # If non-first battery, print a space separator.
+ [ -n "${capacity+x}" ] && printf " "
+ # Sets up the status and capacity
+ case "$(cat "$battery/status" 2>&1)" in
+ "Full") status="⚡" ;;
+ "Discharging") status="🔋" ;;
+ "Charging") status="🔌" ;;
+ "Not charging") status="🛑" ;;
+ "Unknown") status="♻️" ;;
+ *) exit 1 ;;
+ esac
+ capacity="$(cat "$battery/capacity" 2>&1)"
+ # Will make a warn variable if discharging and low
+ [ "$status" = "🔋" ] && [ "$capacity" -le 25 ] && warn="❗"
+ # Prints the info
+ printf "%s%s%d%%" "$status" "$warn" "$capacity"; unset warn
+done && printf "\\n"
diff --git a/mut/bin/sb-clock b/mut/bin/sb-clock
new file mode 100644
index 0000000..ba9e43d
--- /dev/null
+++ b/mut/bin/sb-clock
@@ -0,0 +1,29 @@
+#!/bin/sh
+
+clock=$(date '+%I')
+
+case "$clock" in
+ "00") icon="🕛" ;;
+ "01") icon="🕐" ;;
+ "02") icon="🕑" ;;
+ "03") icon="🕒" ;;
+ "04") icon="🕓" ;;
+ "05") icon="🕔" ;;
+ "06") icon="🕕" ;;
+ "07") icon="🕖" ;;
+ "08") icon="🕗" ;;
+ "09") icon="🕘" ;;
+ "10") icon="🕙" ;;
+ "11") icon="🕚" ;;
+ "12") icon="🕛" ;;
+esac
+
+case $BUTTON in
+ 1) notify-send "This Month" "$(cal --color=always | sed "s/..7m/<b><span color=\"cyan\">/;s|..0m|</span></b>|")" && notify-send "Appointments" "$(calcurse -d3)" ;;
+ 2) setsid -f "$TERMINAL" -e calcurse ;;
+ 3) notify-send "📅 Time/date module" "\- Left click to show upcoming appointments for the next three days via \`calcurse -d3\` and show the month via \`cal\`
+- Middle click opens calcurse if installed" ;;
+ 6) "$TERMINAL" -e "$EDITOR" "$0" ;;
+esac
+
+date "+%Y %b %d (%a) $icon%I:%M%p"
diff --git a/mut/bin/sb-internet b/mut/bin/sb-internet
new file mode 100644
index 0000000..225d376
--- /dev/null
+++ b/mut/bin/sb-internet
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+# Show wifi 📶 and percent strength or 📡 if none.
+# Show 🌐 if connected to ethernet or ❎ if none.
+# Show 🔒 if a vpn connection is active
+
+case $BUTTON in
+ 1) "$TERMINAL" -e nmtui; pkill -RTMIN+4 dwmblocks ;;
+ 3) notify-send "🌐 Internet module" "\- Click to connect
+❌: wifi disabled
+📡: no wifi connection
+📶: wifi connection with quality
+❎: no ethernet
+🌐: ethernet working
+🔒: vpn is active
+" ;;
+ 6) "$TERMINAL" -e "$EDITOR" "$0" ;;
+esac
+
+if grep -xq 'up' /sys/class/net/w*/operstate 2>/dev/null ; then
+ wifiicon="$(awk '/^\s*w/ { print "📶", int($3 * 100 / 70) "% " }' /proc/net/wireless)"
+elif grep -xq 'down' /sys/class/net/w*/operstate 2>/dev/null ; then
+ grep -xq '0x1003' /sys/class/net/w*/flags && wifiicon="📡 " || wifiicon="❌ "
+fi
+
+printf "%s%s%s\n" "$wifiicon" "$(sed "s/down/❎/;s/up/🌐/" /sys/class/net/e*/operstate 2>/dev/null)" "$(sed "s/.*/🔒/" /sys/class/net/tun*/operstate 2>/dev/null)"
diff --git a/mut/bin/sb-mailbox b/mut/bin/sb-mailbox
new file mode 100644
index 0000000..ab1669e
--- /dev/null
+++ b/mut/bin/sb-mailbox
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+# Displays number of unread mail and an loading icon if updating.
+# When clicked, brings up `neomutt`.
+
+case $BUTTON in
+ 1) setsid -f "$TERMINAL" -e neomutt ;;
+ 2) setsid -f mailsync >/dev/null ;;
+ 3) notify-send "📬 Mail module" "\- Shows unread mail
+- Shows 🔃 if syncing mail
+- Left click opens neomutt
+- Middle click syncs mail" ;;
+ 6) "$TERMINAL" -e "$EDITOR" "$0" ;;
+esac
+
+unread="$(find "${XDG_DATA_HOME:-$HOME/.local/share}"/mail/*/[Ii][Nn][Bb][Oo][Xx]/new/* -type f | wc -l 2>/dev/null)"
+
+pidof mbsync >/dev/null 2>&1 && icon="🔃"
+
+[ "$unread" = "0" ] && [ "$icon" = "" ] || echo "📬$unread$icon"
diff --git a/mut/bin/sb-nettraf b/mut/bin/sb-nettraf
new file mode 100644
index 0000000..06b3c49
--- /dev/null
+++ b/mut/bin/sb-nettraf
@@ -0,0 +1,29 @@
+#!/bin/sh
+
+# Module showing network traffic. Shows how much data has been received (RX) or
+# transmitted (TX) since the previous time this script ran. So if run every
+# second, gives network traffic per second.
+
+case $BUTTON in
+ 1) setsid -f "$TERMINAL" -e bmon ;;
+ 3) notify-send "🌐 Network traffic module" "🔻: Traffic received
+🔺: Traffic transmitted" ;;
+ 6) "$TERMINAL" -e "$EDITOR" "$0" ;;
+esac
+
+update() {
+ sum=0
+ for arg; do
+ read -r i < "$arg"
+ sum=$(( sum + i ))
+ done
+ cache=/tmp/${1##*/}
+ [ -f "$cache" ] && read -r old < "$cache" || old=0
+ printf %d\\n "$sum" > "$cache"
+ printf %d\\n $(( sum - old ))
+}
+
+rx=$(update /sys/class/net/[ew]*/statistics/rx_bytes)
+tx=$(update /sys/class/net/[ew]*/statistics/tx_bytes)
+
+printf "🔻%4sB 🔺%4sB\\n" $(numfmt --to=iec $rx $tx)
diff --git a/mut/bin/sb-news b/mut/bin/sb-news
new file mode 100644
index 0000000..a155c0a
--- /dev/null
+++ b/mut/bin/sb-news
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+# Displays number of unread news items and an loading icon if updating.
+# When clicked, brings up `newsboat`.
+
+case $BUTTON in
+ 1) setsid "$TERMINAL" -e newsboat ;;
+ 2) setsid -f newsup >/dev/null exit ;;
+ 3) notify-send "📰 News module" "\- Shows unread news items
+- Shows 🔃 if updating with \`newsup\`
+- Left click opens newsboat
+- Middle click syncs RSS feeds
+<b>Note:</b> Only one instance of newsboat (including updates) may be running at a time." ;;
+ 6) "$TERMINAL" -e "$EDITOR" "$0" ;;
+esac
+
+ cat /tmp/newsupdate 2>/dev/null || echo "$(newsboat -x print-unread | awk '{ if($1>0) print "📰" $1}')$(cat "${XDG_CONFIG_HOME:-$HOME/.config}"/newsboat/.update 2>/dev/null)"
diff --git a/mut/bin/set-bg b/mut/bin/set-bg
new file mode 100644
index 0000000..bede726
--- /dev/null
+++ b/mut/bin/set-bg
@@ -0,0 +1,15 @@
+#!@bash@/bin/bash
+reload=0
+while getopts "r" opt; do
+ case "$opt" in
+ h|\?) exit 0 ;;
+ r) reload=1 ;;
+ esac
+done
+if [ $reload -eq 1 ]; then
+ # (cat ~/.cache/wal/sequences &)
+ wal -R
+else
+ sxiv -tob ~/bg | parallel wal -i
+fi
+kak -l | parallel '<<< "colorscheme wal" kak -p {}'
diff --git a/mut/bin/spectrwmbar b/mut/bin/spectrwmbar
new file mode 100644
index 0000000..a106b01
--- /dev/null
+++ b/mut/bin/spectrwmbar
@@ -0,0 +1,59 @@
+#!/usr/bin/env sh
+# script for spectrwm status bar
+
+trap 'update' 5
+
+fgcolors=("+@fg=1;" "+@fg=2;" "+@fg=3;" "+@fg=4;" "+@fg=5;" "+@fg=6;" "+@fg=7;" "+@fg=8;")
+nfgcolors=${#fgcolors[@]}
+
+SLEEP_SEC=5m
+
+repeat() {
+ i=0; while [ $i -lt $1 ]
+ do
+ echo -ne "$TOKEN"
+ i=$(( i + 1 ))
+ done
+}
+
+cpu() {
+ read cpu a b c previdle rest < /proc/stat
+ prevtotal=$((a+b+c+previdle))
+ sleep 0.5
+ read cpu a b c idle rest < /proc/stat
+ total=$((a+b+c+idle))
+ cpu=$((100*( (total-prevtotal) - (idle-previdle) ) / (total-prevtotal) ))
+ echo -e "CPU: $cpu%"
+}
+
+battery() {
+ BATTERY="$(cat /sys/class/power_supply/BAT0/capacity)"
+
+ BAR_LEFT=$BATTERY
+ BATTERY_BAR=""
+ BLOCK=$(( 100 / nfgcolors ))
+ TOKEN=$(printf '\u2588')
+
+ BAT_COL=$(( $nfgcolors -1 ))
+ #loops forever outputting a line every SLEEP_SEC secs
+ while [ $(( BAR_LEFT - BLOCK )) -gt 0 ]
+ do
+ BATTERY_BAR="${fgcolors[$BAT_COL]}$(repeat $BLOCK)${BATTERY_BAR}"
+ BAR_LEFT=$(( BAR_LEFT - BLOCK ))
+ BAT_COL=$(( BAT_COL - 1))
+ done
+
+ BATTERY_BAR="BATTERY: ${fgcolors[$BAT_COL]}$(repeat $BAR_LEFT)${BATTERY_BAR}"
+ echo $BATTERY_BAR
+}
+
+update() {
+ echo "$(cpu) $(battery)"
+ wait
+}
+
+while :; do
+ update
+ sleep $SLEEP_SEC &
+ wait
+done
diff --git a/mut/bin/sysact b/mut/bin/sysact
new file mode 100755
index 0000000..4bb92dc
--- /dev/null
+++ b/mut/bin/sysact
@@ -0,0 +1,21 @@
+#!/bin/sh
+
+# A dmenu wrapper script for system functions.
+export WM="dwm"
+ctl='systemctl'
+
+wmpid(){ # This function is needed if there are multiple instances of the window manager.
+ echo "$(pidof dwm)"
+}
+
+case "$(printf "🔒 lock\n🚪 leave $WM\n♻️ renew $WM\n🐻 hibernate\n🔃 reboot\n🖥️shutdown\n💤 sleep\n📺 display off" | dmenu -i -p 'Action: ')" in
+ '🔒 lock') slock ;;
+ "🚪 leave $WM") kill -TERM "$(wmpid)" ;;
+ "♻️ renew $WM") kill -HUP "$(wmpid)" ;;
+ '🐻 hibernate') slock $ctl hibernate -i ;;
+ '💤 sleep') slock $ctl suspend -i ;;
+ '🔃 reboot') $ctl reboot -i ;;
+ '🖥️shutdown') $ctl poweroff -i ;;
+ '📺 display off') xset dpms force off ;;
+ *) exit 1 ;;
+esac
diff --git a/mut/bin/terragrunt b/mut/bin/terragrunt
new file mode 100755
index 0000000..38918e8
--- /dev/null
+++ b/mut/bin/terragrunt
@@ -0,0 +1,94 @@
+#!@bash@/bin/bash
+TERRAGRUNT_ARGS=()
+CONTEXT=""
+ENV=""
+MODULE=""
+FULL=0
+while [[ $# -gt 0 ]]; do
+ case $1 in
+ -full)
+ FULL=1
+ shift
+ ;;
+ -m|--module-path)
+ MODULE="$2"
+ shift
+ shift
+ ;;
+ -m=*|--module-path=*)
+ MODULE="${1#*=}"
+ shift
+ ;;
+ -e|--env)
+ ABS_ENV="$2"
+ CONTEXT=${ABS_ENV%/*}
+ ENV=${ABS_ENV#*/}
+ shift
+ shift
+ ;;
+ -e=*|--env=*)
+ ABS_ENV="${1#*=}"
+ CONTEXT=${ABS_ENV%/*}
+ ENV=${ABS_ENV#*/}
+ shift
+ ;;
+ *|-*)
+ TERRAGRUNT_ARGS+=("$1")
+ shift
+ esac
+done
+
+TTY=""
+case ${TERRAGRUNT_ARGS[0]} in
+ plan)
+ TERRAGRUNT_ARGS+=(-no-color -compact-warnings)
+ ;;
+ apply|destroy)
+ TTY="-t"
+ for arg in $TERRAGRUNT_ARGS; do
+ if [[ $arg -eq "gruntplan" ]]; then
+ TTY=""
+ fi
+ done
+ TERRAGRUNT_ARGS+=(-no-color -compact-warnings)
+ ;;
+ init)
+ TERRAGRUNT_ARGS+=(-no-color -compact-warnings)
+ ;;
+esac
+
+VARIABLES=""
+REPO="${PWD}"
+TERRAGRUNT_EXTRA_MOUNTS=""
+for var in $(pass show work/env)
+do
+ case $var in
+ TERRAGRUNT_EXTRA_MOUNTS*)
+ TERRAGRUNT_EXTRA_MOUNTS="$TERRAGRUNT_EXTRA_MOUNTS ${var#*=}"
+ ;;
+ *)
+ VARIABLES="$VARIABLES$(printf ' -e %s' "$var")"
+ ;;
+ esac
+done
+
+for var in $(printenv)
+do
+ case $var in
+ TF_*)
+ VARIABLES="$VARIABLES$(printf ' -e %s' $var)"
+ ;;
+ esac
+done
+
+ENVIRONMENTS="$REPO/environments"
+WORKDIR="$ENVIRONMENTS/$ENV/$MODULE"
+
+# TODO(mike): how to do concise mode | grep -E '(^.*[#~+-] .*|^[[:punct:]]|Plan)'
+# TODO(mike): check expiry of azure directory
+echo "docker run --rm -i $TTY $VARIABLES -v $HOME/.terragrunt-cache:/tmp -v $HOME/.azure:/root/.azure -v $HOME/.netrc:/root/.netrc $TERRAGRUNT_EXTRA_MOUNTS -v ${REPO}:${REPO} -w ${WORKDIR} $TERRAGRUNT_CONTAINER terragrunt ${TERRAGRUNT_ARGS[@]} | filter-ansi | grep --line-buffered -E '(^ .*[#~+-] .*|^[[:punct:]]|^Plan.*|^\S.*)'"
+if [[ $FULL -eq 0 ]]; then
+ docker run --rm -i $TTY $VARIABLES -v $HOME/.terragrunt-cache:/tmp -v $HOME/.azure:/root/.azure -v $HOME/.netrc:/root/.netrc $TERRAGRUNT_EXTRA_MOUNTS -v ${REPO}:${REPO} -w ${WORKDIR} $TERRAGRUNT_CONTAINER terragrunt ${TERRAGRUNT_ARGS[@]} | filter-ansi | grep --line-buffered -E '(^ .*[#~+-] .*|^[[:punct:]]|^Plan.*|^\S.*)'
+else
+ docker run --rm -i $TTY $VARIABLES -v $HOME/.terragrunt-cache:/tmp -v $HOME/.azure:/root/.azure -v $HOME/.netrc:/root/.netrc $TERRAGRUNT_EXTRA_MOUNTS -v ${REPO}:${REPO} -w ${WORKDIR} $TERRAGRUNT_CONTAINER terragrunt ${TERRAGRUNT_ARGS[@]} | filter-ansi
+fi
diff --git a/mut/bin/tmux-normal-mode b/mut/bin/tmux-normal-mode
new file mode 100644
index 0000000..5730017
--- /dev/null
+++ b/mut/bin/tmux-normal-mode
@@ -0,0 +1,28 @@
+ # Make our own copy-mode with Kakoune!
+ # cursor_y=$(tmux display-message -t "''${pane_id}" -p "#{cursor_y}") ;\
+ # cursor_x=$(tmux display-message -t "''${pane_id}" -p "#{cursor_x}") ;\
+ # pane_height=$(tmux display-message -t "''${pane_id}" -p "#{pane_height}") ;\
+ # line_count="$(wc -l "$file" |awk "{print \$1}")" ;\
+ # sel_line=$(( line_count - ( pane_height - cursor_y ) + 1 )) ;\
+ # printf "sel = %s\n" "$line_count" >>/tmp/debug.log ;\
+ # cursor="''${sel_line}.''${cursor_x},''${sel_line}.''${cursor_x}" ;\
+ # printf "cursor = %s\n" "$cursor" >>/tmp/debug.log
+
+kakoune_session="$(tmux display-message -p "#{window_name}" | sed "s/kakc@//")"
+dispatch_name="dispatch://$(tmux display-message -p "#{pane_start_command}")"
+case "${@}" in
+ '')
+ output=$(mktemp -d /tmp/kak-tmux.XXXXXXXX)/fifo
+ mkfifo ${output}
+ ( tmux capture-pane -S '-' -E '-' -J -e -p -t $TMUX_PANE | filter-ansi >${output} & )
+ tmux new-window -t kaks@$kakoune_session -n "$dispatch_name" -d "
+ kak -c '$kakoune_session' -e \"edit -fifo ${output} '${dispatch_name}';\
+ set-option buffer readonly true ;\
+ set-option window filetype dispatch ;\
+ hook -always -once buffer BufCloseFifo .* %{ nop %sh{ rm -r $(dirname ${output}) } }\""
+ tmux swap-pane -s kaks@$kakoune_session:"$dispatch_name".0 -t :
+ ;;
+ --quit)
+ tmux break-pane -t kaks@$kakoune_session -a -d -n "$dispatch_name"
+ ;;
+esac
diff --git a/mut/bin/transadd b/mut/bin/transadd
new file mode 100644
index 0000000..a598fad
--- /dev/null
+++ b/mut/bin/transadd
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+# Mimeapp script for adding torrent to transmission-daemon, but will also start the daemon first if not running.
+
+# transmission-daemon sometimes fails to take remote requests in its first moments, hence the sleep.
+
+pidof transmission-daemon >/dev/null || (transmission-daemon && notify-send "Starting transmission daemon..." && sleep 3 && pkill -RTMIN+7 "${STATUSBAR:-dwmblocks}")
+
+transmission-remote -a "$@" && notify-send "🔽 Torrent added."