diff options
Diffstat (limited to 'bin')
| -rwxr-xr-x | bin/beep | 62 | ||||
| -rwxr-xr-x | bin/enter | 20 | ||||
| -rwxr-xr-x | bin/grimshot | 223 | ||||
| -rwxr-xr-x | bin/gui-enter | 10 | ||||
| -rwxr-xr-x | bin/hibiki/prompt | 6 | ||||
| -rwxr-xr-x | bin/mnts | 43 | ||||
| -rwxr-xr-x | bin/pomo | 68 | ||||
| -rwxr-xr-x | bin/rm | 10 | ||||
| -rwxr-xr-x | bin/safe-env | 10 | ||||
| -rwxr-xr-x | bin/semver | 85 | ||||
| -rwxr-xr-x | bin/soundswitch | 259 | ||||
| -rwxr-xr-x | bin/swx | 141 | ||||
| -rwxr-xr-x | bin/trash | 98 | ||||
| -rwxr-xr-x | bin/xdg-exec | 2 |
14 files changed, 606 insertions, 431 deletions
diff --git a/bin/beep b/bin/beep index 4d0e16b..4dc53fb 100755 --- a/bin/beep +++ b/bin/beep @@ -1,16 +1,56 @@ #!/bin/sh + vol=${BEEP_VOL:-0.5} -snd=${BEEP_SND:-$HOME/Music/sounds/miui/complete.ogg} -subject=${BEEP_SUB:-beep} -message=${BEEP_MSG:-"<i>ringing the bell...</i>"} -icon=${BEEP_ICN:-/usr/share/icons/Adwaita/scalable/status/task-due-symbolic.svg} +snd=${BEEP_SND:-$HOME/Music/sounds/miui/} +subject=${BEEP_SUB:-Beep} +message=${BEEP_MSG:-"<i>The bell rang</i>"} +icon=${BEEP_ICN:-"$(iconez -p $PPID | head -n1)"} +nobel= +nonotify= +while getopts v:s:S:M:i:bNh opt; do + case "$opt" in + v) vol=${OPTARG} ;; + s) snd=${OPTARG} ;; + # S) subject=${OPTARG} ;; + # M) message=${OPTARG} ;; + # i) icon=${OPTARG} ;; + N) nonotify=1 ;; + b) nobel=1 ;; + h | ?) + printf "usage: %s [-h] -- NOTIFY_SEND_ARGS\n" "$(basename "$0")" + printf "\n" + printf " -v \t volume (default: ${vol})\n" + printf " -s \t sound file (default: ${snd})\n" + printf " -b \t don't sound terminal bell (default: false)\n" + printf " -N \t don't send notification (default: false)\n" + printf "\n" + exit 2 + ;; + esac +done +shift $((OPTIND - 1)) + +( + echo ${PPID} -notify-send -a beep -u normal -i "${icon}" \ - "${subject}" "${message}" & + [ -z "${nobel}" ] && tput bel & -tput bel & + if [ -z "${nonotify}" ]; then + if [ -z "$*" ]; then + notify-send -a beep -u normal -i "${icon}" "${subject}" "${message}" & + else + notify-send -a beep -u normal -i "${icon}" "$@" & + fi + fi -exec paplay \ - --property=media.role=event \ - --volume="${vol}" \ - "${snd}" + if [ ! -f "${snd}" ]; then + case "${1}" in + done) snd=${snd}/complete.ogg ;; + *) snd=${snd}/bell.ogg ;; + esac + fi + paplay \ + --property=media.role=event \ + --volume="${vol}" \ + "${snd}" +) & diff --git a/bin/enter b/bin/enter index 77d79e3..68db3d5 100755 --- a/bin/enter +++ b/bin/enter @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash set -e [ -n "$DEBUG" ] && set -x @@ -11,6 +11,7 @@ become= verbose= cwd=$PWD no_tty= +read_only= usage() { printf "usage: %s OPTIONS -- [ARGS]\n" "$(basename "$0")" @@ -24,12 +25,13 @@ usage() { printf " -v (be verbose)\n" printf " -c CWD\n" printf " -T (not tty)\n" + printf " -W (readonly)\n" printf "\n" printf "Enter the container defined in Dockerfile, with \$PWD mounted at /src\n" exit 2 } -while getopts t:i:f:o:c:vBDTh o; do +while getopts t:i:f:o:c:vBDTWh o; do case $o in t) target="$OPTARG" ;; i) img="$OPTARG" ;; @@ -40,6 +42,7 @@ while getopts t:i:f:o:c:vBDTh o; do B) become=1 ;; v) verbose=1 ;; T) no_tty=1 ;; + W) read_only=1 ;; h | ?) usage ;; esac done @@ -85,6 +88,9 @@ extra_args= [ -z "$no_tty" ] \ && extra_args="${extra_args} --tty" +[ -n "$read_only" ] \ + && read_only=",ro" + ep="sh" [ -n "$1" ] && { ep="$1" @@ -93,8 +99,14 @@ ep="sh" [ -n "$verbose" ] && { set -x; } -cname=$(mktemp --dry-run enterXXXX) +if dev=$(echo "$@" | grep -Po '\/dev\/[^ ]*'); then + extra_args="${extra_args} --device=${dev}" +fi + +cname=$(mktemp --dry-run enter_XXXX) exec docker run --name "$cname" --rm -i \ + --env-file <(safe-env) \ --uts host \ + --ipc host \ --entrypoint="$ep" \ - --mount=type=bind,src="$cwd",dst=/src -w /src $extra_args "$img" $@ + --mount=type=bind,src="$cwd",dst=/src"$read_only" -w /src $extra_args "$img" $@ diff --git a/bin/grimshot b/bin/grimshot index 4d4dd81..af7bcd1 100755 --- a/bin/grimshot +++ b/bin/grimshot @@ -20,143 +20,150 @@ ## `grimshot check` - verify if tools are installed _slurp() { - slurp -d -c '#4E437188' -w 3 + slurp -d -c '#4E437188' -w 3 +} +_silence_notifications() { + once -k mako + trap '{ once mako; }' EXIT } ACTION=${1:-usage} SUBJECT=${2:-screen} FILE=${3:-$(xdg-user-dir PICTURES)/screenshots/$(now).png} case "$ACTION" in - usage|help|-h|--help) - echo "Usage:" - echo " grimshot copy|save|rec win|screen|area|output [FILE]" - echo "Troubleshoot:" - echo " grimshot check" - exit + usage | help | -h | --help) + echo "Usage:" + echo " grimshot copy|save|rec win|screen|area|output [FILE]" + echo "Troubleshoot:" + echo " grimshot check" + exit + ;; esac notify() { - notify-send -i "${TMP:-${FILE}}" -t 3000 -a grimshot "$@" - # notify-send -i "${TMP:-${FILE}}" -t 3000 "$@" + notify-send -i "${TMP:-${FILE}}" -t 3000 -a grimshot "$@" + # notify-send -i "${TMP:-${FILE}}" -t 3000 "$@" } notifyOk() { - TITLE=${2:-"Screenshot"} - MESSAGE=${1:-"OK"} - notify "$TITLE" "$MESSAGE" + TITLE=${2:-"Screenshot"} + MESSAGE=${1:-"OK"} + notify "$TITLE" "$MESSAGE" } notifyError() { - TITLE=${2:-"Screenshot"} - MESSAGE=${1:-"Error taking screenshot with grim"} - TMP=/usr/share/icons/Adwaita/scalable/apps/applets-screenshooter-symbolic.svg - notify -u critical "$TITLE" "$MESSAGE" + TITLE=${2:-"Screenshot"} + MESSAGE=${1:-"Error taking screenshot with grim"} + TMP=/usr/share/icons/Adwaita/scalable/apps/applets-screenshooter-symbolic.svg + notify -u critical "$TITLE" "$MESSAGE" } die() { - MSG=${1:-Bye} - notifyError "Error: $MSG" - exit 2 + MSG=${1:-Bye} + notifyError "Error: $MSG" + exit 2 } check() { - COMMAND=$1 - command -v "$COMMAND" > /dev/null 2>&1 - if [ $? ]; then - RESULT="OK" - else - RESULT="NOT FOUND" - fi - echo " $COMMAND: $RESULT" + COMMAND=$1 + command -v "$COMMAND" >/dev/null 2>&1 + if [ $? ]; then + RESULT="OK" + else + RESULT="NOT FOUND" + fi + echo " $COMMAND: $RESULT" } takeScreenshot() { - FILE=$1 - GEOM=$2 - OUTPUT=$3 - if [ -n "$GEOM" ]; then - grim -g "$GEOM" "$FILE" || die "Unable to invoke grim" - elif [ -n "$OUTPUT" ]; then - grim -o "$OUTPUT" "$FILE" || die "Unable to invoke grim" - else - grim "$FILE" || die "Unable to invoke grim" - fi + FILE=$1 + GEOM=$2 + OUTPUT=$3 + if [ -n "$GEOM" ]; then + grim -g "$GEOM" "$FILE" || die "Unable to invoke grim" + elif [ -n "$OUTPUT" ]; then + grim -o "$OUTPUT" "$FILE" || die "Unable to invoke grim" + else + grim "$FILE" || die "Unable to invoke grim" + fi } recordScreen() { - FILE=$1 - GEOM=$2 - OUTPUT=$3 - REC_OPTS="-d /dev/dri/renderD128" - if [ -n "$GEOM" ]; then - wf-recorder ${REC_OPTS} -g "${GEOM}" -f "$FILE" || die "Unable to invoke wf-recorder" - elif [ -n "$OUTPUT" ]; then - wf-recorder ${REC_OPTS} -o "${OUTPUT}" -f "$FILE" || die "Unable to invoke wf-recorder" - else - wf-recorder ${REC_OPTS} -f "$FILE" || die "Unable to invoke wf-recorder" - fi + _silence_notifications + + FILE=$1 + GEOM=$2 + OUTPUT=$3 + REC_OPTS="-d /dev/dri/renderD128" + if [ -n "$GEOM" ]; then + wf-recorder ${REC_OPTS} -g "${GEOM}" -f "$FILE" || die "Unable to invoke wf-recorder" + elif [ -n "$OUTPUT" ]; then + wf-recorder ${REC_OPTS} -o "${OUTPUT}" -f "$FILE" || die "Unable to invoke wf-recorder" + else + wf-recorder ${REC_OPTS} -f "$FILE" || die "Unable to invoke wf-recorder" + fi } -if [ "$ACTION" = "check" ] ; then - echo "Checking if required tools are installed. If something is missing, install it to your system and make it available in PATH..." - check grim - check slurp - check wf-recorder - check swaymsg - check swq - check wl-copy - check jq - check notify-send - check mktemp - exit -elif [ "$SUBJECT" = "area" ] ; then - GEOM=$(_slurp) - [ -z "$GEOM" ] && die "Selection cancelled" - WHAT="Area" -elif [ "$SUBJECT" = "win" ] ; then - FOCUSED=$(swaymsg -t get_tree | jq -r 'recurse(.nodes[]?, .floating_nodes[]?) | select(.focused)') - GEOM=$(echo "$FOCUSED" | jq -r '.rect | "\(.x),\(.y) \(.width)x\(.height)"') - APP_ID=$(echo "$FOCUSED" | jq -r '.app_id') - WHAT="$APP_ID window" -elif [ "$SUBJECT" = "screen" ] ; then - GEOM="" - WHAT="Screen" -elif [ "$SUBJECT" = "output" ] ; then - GEOM="" - OUTPUT="$(swq current output)" - WHAT="output $OUTPUT" +if [ "$ACTION" = "check" ]; then + echo "Checking if required tools are installed. If something is missing, install it to your system and make it available in PATH..." + check grim + check slurp + check wf-recorder + check swaymsg + check swq + check wl-copy + check jq + check notify-send + check mktemp + exit +elif [ "$SUBJECT" = "area" ]; then + GEOM=$(_slurp) + [ -z "$GEOM" ] && die "Selection cancelled" + WHAT="Area" +elif [ "$SUBJECT" = "win" ]; then + FOCUSED=$(swaymsg -t get_tree | jq -r 'recurse(.nodes[]?, .floating_nodes[]?) | select(.focused)') + GEOM=$(echo "$FOCUSED" | jq -r '.rect | "\(.x),\(.y) \(.width)x\(.height)"') + APP_ID=$(echo "$FOCUSED" | jq -r '.app_id') + WHAT="$APP_ID window" +elif [ "$SUBJECT" = "screen" ]; then + GEOM="" + WHAT="Screen" +elif [ "$SUBJECT" = "output" ]; then + GEOM="" + OUTPUT="$(swq current output)" + WHAT="output $OUTPUT" else - die "Unknown subject to take a screen shot from" "$SUBJECT" + die "Unknown subject to take a screen shot from" "$SUBJECT" fi -if [ "$ACTION" = "copy" ] ; then - TMP=$(mktemp) || die "Unable to create temp file: is mktemp installed?" - takeScreenshot "$TMP" "$GEOM" "$OUTPUT" - wl-copy --type image/png < "$TMP" || die "Clipboard error" - notifyOk "$WHAT copied to clipboard" - rm "$TMP" -elif [ "$ACTION" = "save" ] ; then - takeScreenshot "$FILE" "$GEOM" "$OUTPUT" - if [ $? ]; then - TITLE="Screenshot of $SUBJECT" - MESSAGE=$(basename "$FILE") - wl-copy --type image/png < "$FILE" || die "Clipboard error" - notifyOk "$MESSAGE" "$TITLE" - else - notifyError "Error taking screenshot with grim" - fi -elif [ "$ACTION" = "rec" ] ; then - echo "$FILE" | awk '/png$/{exit 0}' && \ - FILE=$(xdg-user-dir VIDEOS)/grimshot/$(now).mp4 - # create dir if not exists - [ -d "$(dirname "$FILE")" ] || mkdir -p "$(dirname "$FILE")" - recordScreen "$FILE" "$GEOM" "$OUTPUT" - wl-copy "$FILE" || die "Clipboard error" - if [ $? ]; then - TITLE="Screen recording of $SUBJECT" - MESSAGE=$(basename "$FILE") - notifyOk "$MESSAGE" "$TITLE" - else - notifyError "Error recording screen with wf-recorder" - fi +if [ "$ACTION" = "copy" ]; then + TMP=$(mktemp) || die "Unable to create temp file: is mktemp installed?" + takeScreenshot "$TMP" "$GEOM" "$OUTPUT" + wl-copy --type image/png <"$TMP" || die "Clipboard error" + notifyOk "$WHAT copied to clipboard" + rm "$TMP" +elif [ "$ACTION" = "save" ]; then + takeScreenshot "$FILE" "$GEOM" "$OUTPUT" + if [ $? ]; then + TITLE="Screenshot of $SUBJECT" + MESSAGE=$(basename "$FILE") + wl-copy --type image/png <"$FILE" || die "Clipboard error" + notifyOk "$MESSAGE" "$TITLE" + else + notifyError "Error taking screenshot with grim" + fi +elif [ "$ACTION" = "rec" ]; then + echo "$FILE" | awk '/png$/{exit 0}' \ + && FILE=$(xdg-user-dir VIDEOS)/grimshot/$(now).mp4 + # create dir if not exists + [ -d "$(dirname "$FILE")" ] || mkdir -p "$(dirname "$FILE")" + recordScreen "$FILE" "$GEOM" "$OUTPUT" + wl-copy "$FILE" || die "Clipboard error" + if [ $? ]; then + TITLE="Screen recording of $SUBJECT" + MESSAGE=$(basename "$FILE") + notifyOk "$MESSAGE" "$TITLE" + else + notifyError "Error recording screen with wf-recorder" + fi else - die "Unknown action" "$ACTION" + die "Unknown action" "$ACTION" fi diff --git a/bin/gui-enter b/bin/gui-enter index e14bafb..ac7a479 100755 --- a/bin/gui-enter +++ b/bin/gui-enter @@ -13,7 +13,7 @@ usage() { } case "$1" in --h) usage && exit 0 ;; + -h) usage && exit 0 ;; esac user="${1}" @@ -26,15 +26,17 @@ marker_bins=" oguri kanshi waybar - gammastep + wlsunset pipewire swayidle " pid= for bin in ${marker_bins}; do - pid=$(cat "/run/user/"${uid}"/"${bin}".pid") + pid=$(cat "/run/user/${uid}/${bin}.pid") kill -0 "${pid}" && break done +# grep -zE '^(SWAY|I3|WAYLAND|DBUS|XDG|PATH)' /proc/"${pid}"/environ | tr '\0' '\n' + env=$(grep -zE '^(SWAY|I3|WAYLAND|DBUS|XDG|PATH)' /proc/"${pid}"/environ | tr '\0' ' ' || true) -exec doas -u "${user}" env ${env} "${@}" +exec doas -nu "${user}" -- env ${env} "${@}" diff --git a/bin/hibiki/prompt b/bin/hibiki/prompt index 4109817..d23fc28 100755 --- a/bin/hibiki/prompt +++ b/bin/hibiki/prompt @@ -16,6 +16,8 @@ JOBS='`[ \j -gt 0 ] && printf " ∆\j"`' # show git-bug tickets # shellcheck disable=SC2016 -BUGS='`exit=$?; git rev-parse >/dev/null 2>&1 && { bugn=$(git bug ls --status=open | wc -l); [ $bugn -gt 0 ] && printf " ⚑${bugn}"; }; exit $exit`' +# BUGS='`exit=$?; git rev-parse >/dev/null 2>&1 && { bugn=$(git bug ls --status=open | wc -l); [ $bugn -gt 0 ] && printf " ⚑${bugn}"; }; exit $exit`' +BUGS='' -echo "${SET_TERM_TITLE}${color}\w${RESET}${JOBS}${BUGS} ❱ " +# ❱⫶ +echo "⋮ ${SET_TERM_TITLE}${color}\w${RESET}${JOBS}${BUGS} ❯ " diff --git a/bin/mnts b/bin/mnts index 817d372..56eb185 100755 --- a/bin/mnts +++ b/bin/mnts @@ -5,9 +5,10 @@ # [ -n "$DEBUG" ] && set -x +[ "$1" = "-o" ] && open=1 # check requirements -for app in awk jq lsblk notify-send udisksctl; do +for app in awk jq lsblk notify-send udisksctl swx vifm; do if ! command -v "$app" >/dev/null; then printf "%s: %s not installed but required\n" "$(basename "$0")" "$app" >&2 exit 1 @@ -16,21 +17,35 @@ done export MENU_PROMPT=" mnts" -handle() { - line=$(awk '{print $0}') - [ -z "${line}" ] && exit 0 - - path=$(echo "${line}"|awk -F\\t '{print $3}'|xargs) - mode=$(echo "${line}"|awk -F\\t '{if(length($3)<1) print "mount";else print "unmount";}'|xargs) - drv=$(echo "${line}"|awk -F\\t '{print $1}'|xargs) - label=$(echo "${line}"|awk -F\\t '{print $2}'|xargs) - [ -n "${DEBUG}" ] && printf 'DEBUG: mode:%s, drv:%s, path:%s\n' "${mode}" "${drv}" "${path}"; - _outp=$(udisksctl "${mode}" -b "${drv}" 2>&1) - if [ $? = 0 ]; then \ - notify-send -a mnts mnts "${_outp}" +mount() { + line=$1 + path=$(echo "${line}" | awk -F\\t '{print $3}' | xargs) + mode=$(echo "${line}" | awk -F\\t '{if(length($3)<1) print "mount";else print "unmount";}' | xargs) + drv=$(echo "${line}" | awk -F\\t '{print $1}' | xargs) + label=$(echo "${line}" | awk -F\\t '{print $2}' | xargs) + [ -n "${DEBUG}" ] && printf 'DEBUG: mode:%s, drv:%s, path:%s\n' "${mode}" "${drv}" "${path}" + logfile=$(mktemp --tmpdir -t "mnts-${label}-XXXXX") + if udisksctl "${mode}" -b "${drv}" >"${logfile}" 2>&1; then + if [ "${mode}" = "mount" ]; then + op=plus + _op="+" + else + op=remove + _op="-" + fi + notify-send -i /usr/share/icons/mdi/scalable/harddisk-${op}.svg -a mnts mnts "$(cat "${logfile}")" + printf "%s\t%s\t%s\n" "${_op}" "${drv}" "${path}" + [ -n "${open}" ] && [ "${mode}" = "mount" ] && swx -t -- vifm "${path}" else - notify-send -a mnts -u critical -t 30000 mnts "${mode}ing ${label} failed:\n<i>${_outp}</i>" + notify-send -i /usr/share/icons/mdi/scalable/harddisk.svg -a mnts -u critical -t 30000 mnts "${mode}ing ${label} failed:\n<i>$(cat "${logfile}")</i>" fi + rm "${logfile}" +} + +handle() { + while read -r line; do + mount "${line}" & + done } lsblk -fJ \ diff --git a/bin/pomo b/bin/pomo index b14ffed..c26729e 100755 --- a/bin/pomo +++ b/bin/pomo @@ -1,8 +1,19 @@ #!/bin/sh -WORK=15m -BREAK=3m -PAUSE=5m +[ "$1" = "-h" ] || [ "$1" = "--help" ] && { + echo "usage: $(basename $(readlink -f -- "$0")) [-1] WORK BREAK PAUSE" + echo + echo " WORK (default: 15m)" + echo " BREAK (default: 3m)" + echo " PAUSE (default: 5m)" + echo + exit 0 +} + +[ "$1" = "-1" ] && _once=1 && shift +WORK=${1:-15}m +BREAK=${2:-3}m +PAUSE=${3:-5}m WORK_BELL=/home/robert/Music/sounds/215415__unfa__ping.wav BREAK_BELL=/home/robert/Music/sounds/320655__rhodesmas__level-up-01.wav @@ -10,43 +21,52 @@ PAUSE_BELL=/home/robert/Music/sounds/32304__acclivity__shipsbell.wav END_BELL=/home/robert/Music/sounds/105228__chimerical__old-fashion-radio-jingle-2.wav log() { - echo "$@" - notify-send -a pomo "pomo" "$@" + echo "$@" + notify-send -i /usr/share/icons/mdi/scalable/progress-clock.svg -a pomo "pomo" "$@" } play() { - pw-play --media-role=Event --volume=0.4 "$@" + paplay --property=media.role=event --volume=0.2 "$@" } nag() { - swaynag --type=warning --dismiss-button=ok "$@" + swaynag --type=warning --dismiss-button=ok "$@" } _work() { - log "[$(date +%k:%M:%S)] work for ${WORK}" - play "${WORK_BELL}" 1>&2 2>/dev/null & - sleep "${WORK}" + play "${WORK_BELL}" 1>&2 2>/dev/null & + log "[$(date +%k:%M:%S)] work for ${WORK}" + sleep "${WORK}" } _break() { - log "[$(date +%k:%M:%S)] take a ${BREAK} break" - play "${BREAK_BELL}" 1>&2 2>/dev/null & - nag -m "pomo: take a ${BREAK} break" - sleep "${BREAK}" + play "${BREAK_BELL}" 1>&2 2>/dev/null & + nag -m "pomo: take a ${BREAK} break" + log "[$(date +%k:%M:%S)] take a ${BREAK} break" + sleep "${BREAK}" } _pause() { - log "[$(date +%k:%M:%S)] pause for ${PAUSE}" - play "${PAUSE_BELL}" 1>&2 2>/dev/null & - nag -m "pomo: pause for ${PAUSE}" - sleep "${PAUSE}" + play "${PAUSE_BELL}" 1>&2 2>/dev/null & + nag -m "pomo: pause for ${PAUSE}" + log "[$(date +%k:%M:%S)] pause for ${PAUSE}" + sleep "${PAUSE}" +} + +_end() { + aplay "${END_BELL}" 1>&2 2>/dev/null & + nag -m "[$(date +%k:%M:%S)] the end" } trap '{ printf "\n"; log "[$(date +%k:%M:%S)] goodbye"; exit 0; }' INT +if [ -n "${_once}" ]; then + _work && _end + exit 0 +fi + while true; do - _work && _break - _work && _break - _work && _break - _work && _pause - aplay "${END_BELL}" 1>&2 2>/dev/null & - nag -m "[$(date +%k:%M:%S)] the end" + _work && _break + _work && _break + _work && _break + _work && _pause + _end done diff --git a/bin/rm b/bin/rm index f3a604c..b164647 100755 --- a/bin/rm +++ b/bin/rm @@ -1,8 +1,8 @@ #!/bin/bash -if [ ! -t 1 ]; then +if [ ! -t 1 ] || [ -n "$UNSAFE_RM" ]; then # shellcheck disable=SC2068 - exec /bin/rm $@ + exec /bin/rm "$@" fi # stop me from being stupid @@ -20,7 +20,7 @@ done if [ -n "${force}" ] && [ -n "${recurse}" ]; then tput setaf 1 - ls -l "${!OPTIND}" >&2 + exa --color=never -a "${!OPTIND}" >&2 echo "!" echo "! recursive force not allowed" >&2 echo "!" @@ -30,9 +30,9 @@ fi if [ -n "${recurse}" ]; then tput setaf 1 - ls -l "${!OPTIND}" >&2 + exa --color=never -a "${!OPTIND}" >&2 tput sgr0 fi # shellcheck disable=SC2068 -exec /bin/rm -I --one-file-system $@ +exec /bin/rm -I --one-file-system "$@" diff --git a/bin/safe-env b/bin/safe-env new file mode 100755 index 0000000..2056503 --- /dev/null +++ b/bin/safe-env @@ -0,0 +1,10 @@ +#!/bin/sh + +env | grep -v \ + -e '^[} _]' \ + -e BASH_FUNC \ + -e SHELL \ + -e XDG \ + -e JAVA -e JDK \ + -e GOPATH \ + -e HOME -e MANPATH -e HOME -e PWD -e USER -e PATH diff --git a/bin/semver b/bin/semver index 876ae65..4072662 100755 --- a/bin/semver +++ b/bin/semver @@ -18,7 +18,6 @@ simple_tag = True force = False changelog = False - def usage(): print(f"usage: {sys.argv[0]} OPTIONS COMMANDS") print(""" @@ -28,7 +27,7 @@ OPTIONS: \t-h\tshow this help \t-a\tannotate tag \t-f\toverwrite existing tag -\t-c\tdon't write changelog +\t-c\twrite CHANGELOG COMMANDS: \tpatch @@ -61,40 +60,49 @@ if any(item in ["-h", "--help", "help"] for item in argv): if subprocess.run(["git", "branch", "--show-current"], stdout=subprocess.PIPE).stdout.decode().strip() != "master": - print("WARNING! Not on the master branch.") + print("WARNING: not on master branch.") subprocess.run(["git", "pull", "--rebase"]) -p = subprocess.run(["git", "describe", "--abbrev=0", "--tags"], - stdout=subprocess.PIPE) -describe = p.stdout.decode().strip() +describe = subprocess.run(["git", "describe", "--abbrev=0", "--tags"], + stdout=subprocess.PIPE).stdout.decode().strip() # TODO also ask to re-append the trailing portion.... e.g. -rev1 -prepend = '' -if describe[0] == 'v': - describe = describe[1:] - prepend = 'v' +prepend = None -old_version = describe.split("-")[0].split(".") -if len(old_version) == 2: - [major, minor] = old_version - [major, minor] = map(int, [major, minor]) - patch = 0 -elif len(old_version) == 3: - [major, minor, patch] = old_version - [major, minor, patch] = map(int, [major, minor, patch]) +if describe: + if describe[0] == 'v': + describe = describe[1:] + prepend = 'v' -else: - print( - f"WARNING: git describe returned invalid semver version: \"{describe}\"" - ) - sys.exit(1) - # old_version = [0, 0, 0] + old_version = describe.split("-")[0].split(".") + if len(old_version) == 2: + [major, minor] = old_version + [major, minor] = map(int, [major, minor]) + patch = 0 + elif len(old_version) == 3: + [major, minor, patch] = old_version + [major, minor, patch] = map(int, [major, minor, patch]) -p = subprocess.run( - ["git", "shortlog", "--no-merges", f"{prepend}{describe}..HEAD"], - stdout=subprocess.PIPE) -shortlog = p.stdout.decode() + else: + print( + f"WARNING: git describe returned invalid semver version: \"{describe}\"" + ) + sys.exit(1) + + old_version_revision = subprocess.run(["git", "log", "--pretty=%H", "-1", describe], + stdout=subprocess.PIPE).stdout.decode().strip() + head_revision = subprocess.run(["git", "log", "--pretty=%H", "-1", "HEAD"], + stdout=subprocess.PIPE).stdout.decode().strip() + if old_version_revision == head_revision: + print(f"WARNING: HEAD already tagged as {describe}") + if not force: + sys.exit(0) + +if not simple_tag or changelog: + shortlog = subprocess.run( + ["git", "shortlog", "--no-merges", f"{prepend}{describe}..HEAD"], + stdout=subprocess.PIPE).stdout.decode() new_version = None @@ -109,28 +117,20 @@ elif argv[0] == "major": else: new_version = argv[0] -if new_version is None: +if not new_version: if len(old_version) == 2 and patch == 0: new_version = f"{major}.{minor}" else: new_version = f"{major}.{minor}.{patch}" -if prepend != '': +if prepend and (new_version[0] != 'v'): new_version = prepend + new_version -p = None if os.path.exists("contrib/_incr_version"): p = subprocess.run(["contrib/_incr_version", describe, new_version]) -elif os.path.exists(".git/_incr_version"): - print("Warning: _incr_version found at legacy path") - p = subprocess.run([".git/_incr_version", describe, new_version]) -else: - print("Warning: no _incr_version script. " + - "Does this project have any specific release requirements?") - -if p and p.returncode != 0: - print("Error: _incr_version returned nonzero exit code") - sys.exit(1) + if p.returncode != 0: + print("Error: _incr_version returned nonzero exit code") + sys.exit(1) args = ["git", "tag"] if force: @@ -148,6 +148,8 @@ else: args.extend(["-m", new_version, new_version]) subprocess.run(args) +print(f"Tagged {new_version}") + if changelog: import time now = time.strftime("%Y-%m-%d", time.localtime()) @@ -158,3 +160,4 @@ if changelog: f.write(shortlog) f.write(data) f.flush() + print("Generated CHANGELOG") diff --git a/bin/soundswitch b/bin/soundswitch index acd287a..e39a292 100755 --- a/bin/soundswitch +++ b/bin/soundswitch @@ -1,14 +1,17 @@ #!/bin/sh # # DESCRIPTION: -# dmenu-based pulseaudio helper +# dmenu-based audio helper # +# TODO +# - auto-select the currently active profile + set -e [ -n "$DEBUG" ] && set -x # check requirements -for tool in jq swq pactl perl; do +for tool in jq swq pactl perl pw-dump; do if ! command -v "$tool" >/dev/null; then printf "%s: %s not installed but required\n" "$(basename "$0")" "$tool" >&2 exit 1 @@ -17,9 +20,9 @@ done DEFAULT_PROFILE="output:analog-stereo+input:analog-stereo" HDMI_PROFILE="output:hdmi-stereo" -export MENU_PROMPT="soundswitch" _menu() { + export MENU_PROMPT="soundswitch" menu -l 8 } @@ -49,24 +52,44 @@ usage() { exit 2 } _args="$*" -while getopts hIOgfpHRmMvV name; do +while getopts hIOgfpHRmMvVB name; do case ${name} in - g) mode=global ;; - f) mode=focused ;; - p) mode=profile ;; - H) mode=hdmi ;; - R) mode=reset ;; - O) output=1 ;; - I) input=1 ;; - # quick actions, to make move to pipewire easier - m) mode=none ; output=1 ; mute=1 ;; - M) mode=none ; input=1 ; mute=1 ;; - v) mode=none ; output=1 ; volume_down=1 ;; - V) mode=none ; output=1 ; volume_up=1 ;; - h|?) echo "$*" ; usage ;; + g) mode=global ;; + f) mode=focused ;; + p) mode=profile output=1 input=1 ;; + H) mode=hdmi output=1 input=1 ;; + R) mode=reset ;; + B) mode=mute output=1 input=1 ;; + O) output=1 ;; + I) input=1 ;; + # quick actions, to make move to pipewire easier + m) + mode=none + output=1 + mute=1 + ;; + M) + mode=none + input=1 + mute=1 + ;; + v) + mode=none + output=1 + volume_down=1 + ;; + V) + mode=none + output=1 + volume_up=1 + ;; + h | ?) + echo "$*" + usage + ;; esac done -shift $((OPTIND-1)) +shift $((OPTIND - 1)) # ask mode _mode_global=" global" @@ -74,17 +97,20 @@ _mode_focused=" focused" _mode_profile_card=" card profile" _mode_profile_hdmi=" hdmi profile" _mode_profile_reset=" reset profile" +_mode_mute=" mute" if [ -z "$mode" ]; then - printf "$_mode_global\n$_mode_focused\n$_mode_profile_card\n$_mode_profile_hdmi\n$_mode_profile_reset\n" | _menu | { + printf "$_mode_global\n$_mode_focused\n$_mode_profile_card\n$_mode_profile_hdmi\n$_mode_profile_reset\n$_mode_mute\n" | _menu | { read -r line case ${line} in - $_mode_global) exec "$0" -g "$*" ;; - $_mode_focused) exec "$0" -f "$*" ;; - $_mode_profile_card) exec "$0" -p "$*" ;; - $_mode_profile_hdmi) exec "$0" -H "$*" ;; - $_mode_profile_reset) exec "$0" -R "$*" ;; - *) - usage ;; + $_mode_global) exec "$0" -g "$*" ;; + $_mode_focused) exec "$0" -f "$*" ;; + $_mode_profile_card) exec "$0" -p "$*" ;; + $_mode_profile_hdmi) exec "$0" -H "$*" ;; + $_mode_profile_reset) exec "$0" -R "$*" ;; + $_mode_mute) exec "$0" -B "$*" ;; + *) + usage + ;; esac } exit $? @@ -98,9 +124,9 @@ if [ -n "$mode" ]; then printf "$_mode_output\n$_mode_input\n" | _menu | { read -r line case ${line} in - $_mode_output) exec "$0" -O $_args ;; - $_mode_input) exec "$0" -I $_args ;; - *) usage ;; + $_mode_output) exec "$0" -O $_args ;; + $_mode_input) exec "$0" -I $_args ;; + *) usage ;; esac } fi @@ -112,110 +138,123 @@ fi [ -n "$volume_down" ] && exec pactl set-sink-volume '@DEFAULT_SINK@' '-5%' [ -n "$volume_up" ] && exec pactl set-sink-volume '@DEFAULT_SINK@' '+5%' -[ -n "$output" ] && keyword="sink" && what="sink-input" -[ -n "$input" ] && keyword="source" && what="source-output" +[ -n "$output" ] && keyword="sink" && what="sink-input" +[ -n "$input" ] && keyword="source" && what="source-output" # returns the sink_id -selects() -{ - pactl list short "${1}s" | cut -f2 | menu +selects() { + pactl list short "${1}s" | cut -f2 | _menu } -notif() -{ +notif() { topic=$1 mesg=$2 urgency=normal [ -n "$3" ] && urgency=critical - notify-send -u ${urgency} -a soundswitch "soundswitch: ${topic}" "${mesg}" + notify-send -i /usr/share/icons/mdi/scalable/cast-audio.svg -u ${urgency} -a soundswitch "soundswitch: ${topic}" "${mesg}" } case ${mode} in -global) - target=$(selects "${keyword}") - if [ -z "${target}" ]; then - notif "focused" "no target ${what}" err - exit 1 - fi + global) + target=$(selects "${keyword}") + if [ -z "${target}" ]; then + notif "focused" "no target ${what}" err + exit 1 + fi - notif "global" "switch to <i>${target}</i>" - # set new default - pactl "set-default-${keyword}" "${target}" - # move all attached to the new target - pactl list "${what}s" short | cut -f1 \ - | xargs -i pactl "move-${what}" "{}" "${target}" - ;; - -focused) - # parse pid of currently focused container - # then get the sink-inputs for it and parse the sink-input-id - focused_binary=$(swq current con | jq -r '.pid' | xargs ps -o comm=) - what_id=$(printf "%s\n" "${focused_binary}" \ - | xargs pactl list "${what}s" \ + notif "global" "switch to <i>${target}</i>" + # set new default + pactl "set-default-${keyword}" "${target}" + # move all attached to the new target + pactl list "${what}s" short | cut -f1 \ + | xargs -i pactl "move-${what}" "{}" "${target}" + ;; + + focused) + # parse pid of currently focused container + # then get the sink-inputs for it and parse the sink-input-id + focused_binary=$(swq current con | jq -r '.pid' | xargs ps -o comm=) + what_id=$(printf "%s\n" "${focused_binary}" \ + | xargs pactl list "${what}s" \ | tr '\n' '\r' \ | perl -pe 's/[^\r]*index: ([0-9]+).+?application\.process\.binary = "([^\r]+)"\r.+?(?=index:|$)/\2=\1\r/g' \ | tr '\r' '\n' \ | grep "^{}" \ - | cut -d'=' -f2) - if [ -z "${what_id}" ]; then - notif "focused" "no ${what}" err - exit 1 - fi + | cut -d'=' -f2) + if [ -z "${what_id}" ]; then + notif "focused" "no ${what}" err + exit 1 + fi - # select where to switch to - target=$(selects "${keyword}") - if [ -z "${target}" ]; then - exit 1 - fi + # select where to switch to + target=$(selects "${keyword}") + if [ -z "${target}" ]; then + exit 1 + fi - notif "${focused_binary}" "switch to <i>${target}</i>" - pactl move-sink-input "${what_id}" "${target}" - ;; + notif "${focused_binary}" "switch to <i>${target}</i>" + pactl move-sink-input "${what_id}" "${target}" + ;; -profile) - target_card=$(selects "card") - if [ -z "${target_card}" ]; then - exit 1 - fi + profile) + target_card=$(selects "card") + if [ -z "${target_card}" ]; then + exit 1 + fi - # [^\r]#([0-9]+).*?Name: ([^\r]+).*?Profiles:\r(.*?)Active.*?(?=Card #|$) - target_profile=$(pactl list cards \ - | tr '\n' '\r' \ - | perl -pe 's/[^\r]#([0-9]+).*?Name: ([^\r]+).*?Profiles:\r(.*?)Active.*?(?=Card #|$)/\2~\3`/g' \ - | tr -d '\t' \ - | tr '`' '\n' \ - | grep "${target_card}" \ - | cut -d'~' -f2- \ - | tr '\r' '\n' \ - | xargs -L1 \ - | _menu \ - | perl -pe 's/^\s*([^\s]+):\s.*$/\1/') - if [ -z "${target_profile}" ]; then - exit 1 - fi + # [^\r]#([0-9]+).*?Name: ([^\r]+).*?Profiles:\r(.*?)Active.*?(?=Card #|$) + target_profile=$(pactl list cards \ + | tr '\n' '\r' \ + | perl -pe 's/[^\r]#([0-9]+).*?Name: ([^\r]+).*?Profiles:\r(.*?)Active.*?(?=Card #|$)/\2~\3`/g' \ + | tr -d '\t' \ + | tr '`' '\n' \ + | grep "${target_card}" \ + | cut -d'~' -f2- \ + | tr '\r' '\n' \ + | xargs -L1 \ + | _menu \ + | perl -pe 's/^\s*([^\s]+):\s.*$/\1/') + if [ -z "${target_profile}" ]; then + exit 1 + fi - notif "profile" "switch <i>${target_card}</i> to ${target_profile} profile" - pactl set-card-profile "${target_card}" "${target_profile}" - ;; + notif "profile" "switch <i>${target_card}</i> to ${target_profile} profile" + pactl set-card-profile "${target_card}" "${target_profile}" + ;; -hdmi) - target_card=$(selects "card") - if [ -z "${target_card}" ]; then - exit 1 - fi + hdmi) + target_card=$(selects "card") + if [ -z "${target_card}" ]; then + exit 1 + fi - notif "hdmi" "switch <i>${target_card}</i> to HDMI profile" - pactl set-card-profile "${target_card}" ${HDMI_PROFILE} - exit $? - ;; + notif "hdmi" "switch <i>${target_card}</i> to HDMI profile" + pactl set-card-profile "${target_card}" ${HDMI_PROFILE} + exit $? + ;; -reset) - target_card=$(selects "card") - if [ -z "${target_card}" ]; then - exit 1 - fi + reset) + target_card=$(selects "card") + if [ -z "${target_card}" ]; then + exit 1 + fi + + notif "reset" "switch <i>${target_card}</i> to default profile" + pactl set-card-profile "${target_card}" ${DEFAULT_PROFILE} + ;; + + mute) + _data=$(pw-dump -N | jq -r '.. | select(.type?=="PipeWire:Interface:Node" and .info.props."media.class"?=="Stream/Output/Audio" and .info.props."stream.is-live"?==true) | @text') + _id=$(printf "${_data}" | jq -r '. | [ .info.props."application.name", .info.props."application.process.id", .id ] | @tsv' \ + | awk '{ system("swaymsg -t get_tree | jq -r \".. | select(.pid?==" $2 ") | .name\" | grep -v Picture-in-Picture | tr -d \"\\n\""); printf " [%s]", $3 }' \ + | _menu \ + | perl -pe 's/^.*\[([0-9]+)\]$/\1/') + if [ -z "${_id}" ]; then + exit 1 + fi - notif "reset" "switch <i>${target_card}</i> to default profile" - pactl set-card-profile "${target_card}" ${DEFAULT_PROFILE} - ;; + _oid=$(printf "${_data}" | jq -r --argjson id "${_id}" '.. | select(.id?==$id) | .info.props."object.id"') + _target_state=$(printf "${_data}" | jq -r --argjson id "${_id}" '.. | select(.id?==$id) | .info.params.Props[0] | .mute = (.mute | not) | @text') + pw-cli set-param "${_oid}" Props "${_target_state}" + ;; esac diff --git a/bin/swx b/bin/swx index 01003fc..1ba942b 100755 --- a/bin/swx +++ b/bin/swx @@ -30,55 +30,59 @@ mark= term_title= while getopts b:w:o:g:I:r:stfF:aSM:T:h name; do case "$name" in - b) # border - border="${OPTARG}" ;; - w) # move to workspace - wspace="${OPTARG}" ;; - o) # move to output - output="${OPTARG}" ;; - g) # geometry - geometry="${OPTARG}" ;; - t) # termify - termify=1 ;; - r) # rotate - if ! command -v cage >/dev/null; then - printf "%s: cage not installed but required to rotate containers" "$0" >&2 - exit 1 - fi - rotate="${OPTARG}" ;; - s) # set container to sticky - sticky=1 ;; - f) # set container to float - floating=1 ;; - F) - floating="${OPTARG}" ;; - a) # auto-tiling enabled - autotile=1 ;; - S) # launch into scratchpad - into_scratchpad=1 ;; - M) # mark - mark="${OPTARG}" ;; - T) # set terminal title - term_title="${OPTARG}" ;; + b) # border + border="${OPTARG}" ;; + w) # move to workspace + wspace="${OPTARG}" ;; + o) # move to output + output="${OPTARG}" ;; + g) # geometry + geometry="${OPTARG}" ;; + t) # termify + termify=1 ;; + r) # rotate + if ! command -v cage >/dev/null; then + printf "%s: cage not installed but required to rotate containers" "$0" >&2 + exit 1 + fi + rotate="${OPTARG}" + ;; + s) # set container to sticky + sticky=1 ;; + f) # set container to float + floating=1 ;; + F) + floating="${OPTARG}" + ;; + a) # auto-tiling enabled + autotile=1 ;; + S) # launch into scratchpad + into_scratchpad=1 ;; + M) # mark + mark="${OPTARG}" ;; + T) # set terminal title + term_title="${OPTARG}" ;; - h|?) printf "usage: %s [-bwogIrsfoSMT] COMMAND\n" "$(basename "$0")" - printf "\n" - printf " -t \t\trun COMMAND in \$TERM\n" - printf " -b BORDER \tset border property\n" - printf " -w WORKSPACE \tmove to workspace\n" - printf " -o OUTPUT \tmove to output\n" - printf " -g GEOMETRY \tresize/position window\n" - printf " -r ROTATION \trotate the container, requires cage(1)\n" - printf " -s \t\tmake COMMAND a sticky window, appearing on all workspaces\n" - printf " -f \t\tmake COMMAND a floating window\n" - printf " -F OPTIONS\tmake COMMAND a floating window\n\t\tsee centercon(1) for possible options\n" - printf " -a \t\tauto-tiling; always open COMMAND on the shorter edge of\n\t\tthe current container\n" - printf " -S \t\tmove the container into the scratchpad\n" - printf " -M MARK\t\set MARK on the container\n" - printf " -T TERM_TITLE\t\set a title on the terminal (only makes sense with -t)\n" - printf "\n" - printf "See sway(5) for possible options for BORDER, WORKSPACE, OUTPUT and GEOMETRY.\n" - exit 2 ;; + h | ?) + printf "usage: %s [-bwogIrsfoSMT] COMMAND\n" "$(basename "$0")" + printf "\n" + printf " -t \t\trun COMMAND in \$TERM\n" + printf " -b BORDER \tset border property\n" + printf " -w WORKSPACE \tmove to workspace\n" + printf " -o OUTPUT \tmove to output\n" + printf " -g GEOMETRY \tresize/position window\n" + printf " -r ROTATION \trotate the container, requires cage(1)\n" + printf " -s \t\tmake COMMAND a sticky window, appearing on all workspaces\n" + printf " -f \t\tmake COMMAND a floating window\n" + printf " -F OPTIONS\tmake COMMAND a floating window\n\t\tsee centercon(1) for possible options\n" + printf " -a \t\tauto-tiling; always open COMMAND on the shorter edge of\n\t\tthe current container\n" + printf " -S \t\tmove the container into the scratchpad\n" + printf " -M MARK\t\set MARK on the container\n" + printf " -T TERM_TITLE\t\set a title on the terminal (only makes sense with -t)\n" + printf "\n" + printf "See sway(5) for possible options for BORDER, WORKSPACE, OUTPUT and GEOMETRY.\n" + exit 2 + ;; esac # block until we have a con_id matching on pid of the spawned process patience=1 @@ -93,15 +97,19 @@ shift command="${arg0} ${*}" -# needs to be termified? +# needs to be termified # spawn a $TERM instance and exec that if [ -n "${termify}" ]; then - case ${TERM:-foot} in - alacritty) term_args="--title=${term_title:-${arg0}} --class=${term_title:-${arg0}} --command" ;; - foot) term_args="--title=${term_title:-${arg0}} --app-id=${term_title:-${arg0}} --" ;; - *) term_args="" ;; - esac - command="${TERM} ${term_args} ${command}" + if [ -n "${floating}" ]; then + term_args="floaterm" + else + term_args="foot" + fi + term_args="${term_args} --title=${term_title:-${arg0}} --app-id=${term_title:-${arg0}}" + if [ -n "${SWX_TERM_ARGS}" ]; then + term_args="${term_args} ${SWX_TERM_ARGS}" + fi + command="${term_args} -- ${command}" fi # needs to be rotated @@ -109,7 +117,7 @@ fi if [ -n "${rotate}" ]; then # figure out how many "-r" flags we need rotate_args="" - while [ $(( (rotate / 90) >= 1 )) = 1 ]; do + while [ $(((rotate / 90) >= 1)) = 1 ]; do rotate_args="${rotate_args} -r" rotate=$((rotate - 90)) done @@ -124,21 +132,24 @@ fi if [ -n "${autotile}" ]; then layout=$(swq current con | jq -r '.layout') - # layout=$(swq current workspace | jq -r '.. | select(.type?=="con" and .name?==null) | .layout') + # layout=$(swq current workspace | jq -r '.. | select(.type?=="con" and .name?==null) | .layout') # notify-send swx "${layout}" case "${layout}" in - split*) - if [ "$(swq current con | jq '.rect | .width > .height')" = "true" ]; then - swaymsg splith - else - swaymsg splitv - fi - ;; + split*) + if [ "$(swq current con | jq '.rect | .width > .height')" = "true" ]; then + swaymsg splith + else + swaymsg splitv + fi + ;; esac fi swaymsg exec -- "${command}" >/dev/null -[ $? ] || { printf "error: failed to spawn \"${command}\"\n"; exit 1; } +[ $? ] || { + printf "error: failed to spawn \"${command}\"\n" + exit 1 +} [ -z "$patience" ] && exit 0 # waiting for container to appear con_id="$(swaymsg -t subscribe '["window"]' | jq -s '.[]|select(.change=="new")|.container.id')" diff --git a/bin/trash b/bin/trash index b3c534d..5a040cb 100755 --- a/bin/trash +++ b/bin/trash @@ -3,72 +3,86 @@ set -e [ -n "$DEBUG" ] && set -x +rmbin=/bin/rm + TRASH="$HOME/.trash" if [ ! -d "$TRASH" ]; then - mkdir -p "$TRASH" + mkdir -p "$TRASH" fi +ls_trash() { + # shellcheck disable=SC2068 + fd -H . "${TRASH:?}" $@ +} + empty_trash() { - if [ ! -d "$TRASH" ] || [ -z "$(ls "$TRASH")" ]; then - exit 0 - fi - echo " +++ trash +++" - ls "$TRASH" - printf " +++ take it out? [yN] "; read -r yn - if [ "$yn" = "y" ]; then - printf ' +++ removing %s/* ' "$TRASH" - rm -rf "${TRASH:?}/*" - echo 'done.' - fi + if [ ! -d "$TRASH" ] || [ -z "$(ls_trash)" ]; then + exit 0 + fi + echo " +++ trash +++" + ls_trash + read -r yn + if [ "$yn" = "y" ]; then + printf ' +++ removing everything under %s (%d)... ' "$TRASH" "$(fd . "${TRASH:?}" | wc -l)" + ls_trash -x $rmbin -r + echo 'done.' + fi } install_auto_empty() { - case "$SHELL" in - *zsh) logoutfile="$ZDOTDIR/.zlogout" ;; - *bash) logoutfile="$HOME/.bash_logout" ;; - *) - echo "unknown shell $SHELL" 1>&2; exit 1 ;; - esac - cat > "$logoutfile" <<EOF + case "$SHELL" in + *zsh) logoutfile="$ZDOTDIR/.zlogout" ;; + *bash) logoutfile="$HOME/.bash_logout" ;; + *) + echo "unknown shell $SHELL" 1>&2 + exit 1 + ;; + esac + cat >"$logoutfile" <<EOF # auto-empty-trash routine of $0 yes | $0 --empty EOF } ask() { - r=$(printf 'yes\nno\n' | MENU_PROMPT=" delete $1" menu) - [ "${r}" = "yes" ] && return 0 - return 1 + r=$(printf 'yes\nno\n' | MENU_PROMPT=" delete $1" menu) + [ "${r}" = "yes" ] && return 0 + return 1 } interactive=${TRASH_ASK:-} trashrm=${TRASH_RM:-} case "$1" in - -e|--empty) - empty_trash - exit 0 ;; - --install) - install_auto_empty - exit 0 ;; - -i) - interactive=1 - shift ;; - -h|--help) - echo "usage: trash [-e|--empty] FILE..." - exit 1 ;; + -e | --empty) + empty_trash + exit 0 + ;; + --install) + install_auto_empty + exit 0 + ;; + -i) + interactive=1 + shift + ;; + -h | --help) + echo "usage: trash [-e|--empty] FILE..." + exit 1 + ;; esac # main while test $# -gt 0; do - f="$1" ; shift + f="$1" + shift - [ -n "${interactive}" ] && { ask "$f" || continue; } + [ -n "${interactive}" ] && { ask "$f" || continue; } - echo "+ $(basename "$f")" - if [ -z "${trashrm}" ]; then - rm "$f" - else - mv "$f" "$TRASH/" - fi + echo "+ $(basename "$f")" + if [ -n "${trashrm}" ]; then + [ -d "$f" ] && $rmbin -r "$f" || $rmbin "$f" + else + mv "$f" "$TRASH/" + fi done diff --git a/bin/xdg-exec b/bin/xdg-exec index e8f3ccb..32801de 100755 --- a/bin/xdg-exec +++ b/bin/xdg-exec @@ -21,4 +21,4 @@ bin=$(awk ' /^TryExec=/{split($0,l,"="); if(not system("command -v l[2]")){exit 1}} /^Exec=/{printf gensub(/Exec=([^%]+).*$/, "\\1", "")} ' "$desktop" | sed 's/%.$//') -exec ${bin} $@ +exec ${bin} "$@" |