diff options
Diffstat (limited to '.local/bin')
92 files changed, 3342 insertions, 0 deletions
diff --git a/.local/bin/automountd b/.local/bin/automountd new file mode 100755 index 0000000..f09871f --- /dev/null +++ b/.local/bin/automountd @@ -0,0 +1,12 @@ +#!/bin/sh + +pathtoname() { + udevadm info -p /sys/"$1" | awk -v FS== '/DEVNAME/ {print $2}' +} + +stdbuf -oL -- udevadm monitor --udev -s block | while read -r -- _ _ event devpath _; do + if [ "$event" = add ]; then + devname=$(pathtoname "$devpath") + udisksctl mount --block-device "$devname" --no-user-interaction + fi +done diff --git a/.local/bin/backup b/.local/bin/backup new file mode 100755 index 0000000..8f6e00d --- /dev/null +++ b/.local/bin/backup @@ -0,0 +1,33 @@ +#!/bin/sh + +sudo cryptsetup open /dev/sdb1 backup +sudo mount --mkdir /dev/mapper/backup /mnt/backup +backup="/mnt/backup/$(hostname)" +[ -d "$backup" ] || + { echo "$0: directory doesn't exist: $backup" >&2; exit 1; } + +cd ~ || exit +rsync -Plru --delete \ + .config \ + .git \ + .gnupg \ + .local \ + .librewolf \ + .ssh \ + bin \ + DCIM \ + Dev \ + Documents \ + Downloads \ + GDrive \ + Music \ + Phone \ + Pictures \ + repos \ + Videos \ + "$backup/home/$USER/" + +find . -maxdepth 1 \( -type f -o -type l \) -exec rsync -Plu {} "$backup/home/$USER" \; + +echo "Backing up /etc directory..." +sudo rsync -Plruq --delete /etc "$backup" diff --git a/.local/bin/clearx b/.local/bin/clearx new file mode 100755 index 0000000..225c208 --- /dev/null +++ b/.local/bin/clearx @@ -0,0 +1,51 @@ +#!/bin/sh + +help() { echo "clearx - execute command in clear screen + +USAGE: + clearx [OPTION]... <command> + +OPTIONS: + -n no prompt when exiting + -h show this help message"; } + +err() { printf 'clearx: %s\n' "$@" >&2; exit 1; } +while getopts 'nh' o; do case "$o" in + n) nflag=0 ;; + h) help >&2; exit ;; + *) err "invalid option -- '$OPTARG'" ;; +esac done +shift $((OPTIND - 1)) + +[ "$#" -lt 1 ] && help >&2 && exit 1 +cmds="$*" +[ "$nflag" = 0 ] || + cmds="$cmds; printf '\n%s' 'Press <Enter> to continue: '; read -r arg" + +tmuxcmds="tmux set status off; $cmds; tmux set status on;" +set_screen() { + [ -z "$TMUX" ] && + err '$TMUX not set, only tmux is supported for screen program' + tmux new-window -n clearx "$tmuxcmds" +} +new_screen() { tmux new-session -s clearx "$tmuxcmds"; } + +terminal_emulator() { + [ -z "$DISPLAY" ] && return 1 + #err 'clearx: terminal_emulator: $DISPLAY not set' + case "$TERMINAL" in + '') echo 'clearx: $TERMINAL not set' && exit 1 ;; + alacritty) export TERMINAL="alacritty" ;; + esac + wmctrl -r :ACTIVE: -b remove,fullscreen + $TERMINAL -e sh -c "sleep 0.2; $cmds" & + sleep 0.2 && wmctrl -r :ACTIVE: -b add,fullscreen +} + +case "$TERM" in + '') err '$TERM not set' ;; + *screen*) set_screen ;; + *linux*) setfont ter-132n && new_screen ;; + *256*) terminal_emulator || new_screen ;; + *) err "no action for \$TERM: $TERM" +esac diff --git a/.local/bin/desktop/beautify b/.local/bin/desktop/beautify new file mode 100755 index 0000000..e535129 --- /dev/null +++ b/.local/bin/desktop/beautify @@ -0,0 +1,102 @@ +#!/bin/sh + +## properties of script + +## set home screen and lock screen wallpaper +HOMEWALL="${XDG_DATA_HOME:-$HOME/.local/share}/wallpapers/artix-wampire.png" +LOCKWALL="${XDG_DATA_HOME:-$HOME/.local/share}/wallpapers/artix-wampire.png" + +## choose random wallpaper from a directory +# WALLPAPERS="$HOME/.local/share/wallpapers" +## requires 'setbg' script found in lukesmithxyz github repo +setbg_link="https://github.com/LukeSmithxyz/voidrice/blob/master/.local/bin/setbg" +## path to download script files like setbg +BIN="$HOME/.local/bin" + +# Location to put lock screen wallpaper for lock program +LOCKWALL_LOC="/tmp/lockWall" + +## list of programs to be installed/uninstalled +PROGRAMS="eza dust conky picom xwallpaper cxxmatrix" +## some additional programs that I think are essential are installed below +## these will be not removed during uninstall + + +help() { echo "beautify - beautify you desktop environment + +USAGE: + beautify [OPTION]... + +OPTIONS: + -h show this help message + + -i install programs for beautification + -u uninstall beautification programs + -x clear beautifications + + The above group of options are conflicting. + Passing any one of them will disable the others. + +This is very much a personal script and is meant to be configured directly. +I have only made it work with arch linux and the pacman package manager."; } + +err() { printf 'beautify: %s\n' "$@" >&2; exit 1; } +while getopts 'iuxh' o; do case "$o" in + i) opflag=0 ;; + u) opflag=1 ;; + x) opflag=2 ;; + h) help >&2; exit ;; + *) err "invalid option -- '$OPTARG'" ;; +esac done +shift $((OPTIND - 1)) + +case "$opflag" in + 0) + PROGRAMS="$PROGRAMS neovim tmux dunst highlight starship" + sudo pacman -Syu --noconfirm + for pkg in $PROGRAMS; do + if ! pacman -Q "$pkg" >/dev/null; then + yay -S --noconfirm "$pkg" + fi + done + + mkdir -pv ~/.local/bin + wget -c "$setbg_link" -o "${BIN}/setbg" && chmod +x "${BIN}/setbg" + ;; + + 1) + for pkg in $PROGRAMS; do + if pacman -Q "$pkgs" >/dev/null; then + sudo pacman -Rns --noconfirm "$pkg" + fi + done + rm -f "$setbg" + ;; + + 2) + i3-msg 'gaps inner all set 0' + xwallpaper --clear + rm -f "$LOCKWALL_LOC" + killall -q -o 1s conky picom beautify + ;; +esac + +[ -n "$opflag" ] && exit + +if [ "${LOCKWALL%.png}" = "$LOCKWALL" ]; then + temp="/tmp/$(basename "${LOCKWALL%.*}.png")" + convert "$LOCKWALL" "$temp" + cp -f "$temp" "$LOCKWALL_LOC" + rm -f "$temp" +else + cp -f "$LOCKWALL" "$LOCKWALL_LOC" +fi + +i3-msg 'gaps inner all set 10' +xwallpaper --zoom "$HOMEWALL" +pidof -q conky || conky +pidof -q picom || picom -b + +if [ -e "$WALLPAPERS" ]; then + while sleep 1m; do setbg "$WALLPAPERS"; done +fi diff --git a/.local/bin/desktop/brightness b/.local/bin/desktop/brightness new file mode 100755 index 0000000..11733f4 --- /dev/null +++ b/.local/bin/desktop/brightness @@ -0,0 +1,32 @@ +#!/bin/sh + +help() { echo "brightness - change screen brightness +USAGE: brightness <up|down>"; } + +[ "$#" -lt 1 ] && help >&2 && exit 1 + +brightness="$(brightnessctl --machine-readable | cut -d, -f4 | tr -d %)" +step="$(( brightness / 10 + 1))" + +case "$1" in + up) brightnessctl --quiet set +${step}% ;; + down) brightnessctl --quiet set ${step}%- ;; + *) help >&2; exit 1 ;; +esac + +brightness="$(brightnessctl --machine-readable | cut -d, -f4)" + +if [ -n "$TMUX" ]; then + tmux display "Brightness: $brightness" + exit +fi + +notify() { [ -n "$DISPLAY" ] && notify-send -r 45234 "$1" "$2"; } +case "${brightness%\%}" in + [0-9]) notify "💡 Brightness: $brightness" ;; + [1-7][0-9]) notify "🔅 Brightness: $brightness" ;; + [89][0-9]) notify "🔆 Brightness: $brightness" ;; + 100) notify "🔆 MAX Brightness: $brightness" ;; + *) notify "brightness" "can't determine brightness" +esac +exit 0 diff --git a/.local/bin/desktop/detect-keys b/.local/bin/desktop/detect-keys new file mode 100755 index 0000000..da00dad --- /dev/null +++ b/.local/bin/desktop/detect-keys @@ -0,0 +1,3 @@ +#!/bin/sh + +xev | awk -F'[ )]+' '/^KeyPress/ { a[NR+2] } NR in a { printf "%-3s %s\n", $5, $8 }' diff --git a/.local/bin/desktop/dmenu-syncthing-devices b/.local/bin/desktop/dmenu-syncthing-devices new file mode 100755 index 0000000..bb93f6d --- /dev/null +++ b/.local/bin/desktop/dmenu-syncthing-devices @@ -0,0 +1,25 @@ +#!/bin/sh + +pidof -q syncthing || { + echo "ERROR: Syncthing is not running" >&2 + exit 2 +} + +get_devices() { + for device_id in $(syncthing cli config devices list); do + printf '%-10s %s\n' \ + "$(syncthing cli config devices "$device_id" name get)" \ + "$device_id" + done | nl -w1 -s'. ' +} + +device="$(get_devices | dmenu -l 10 -p "Syncthing devices")" +device_id="${device##* }" +[ -z "$device_id" ] && exit 1 + +if [ -n "$1" ]; then + xdotool type "$device_id" +else + printf '%s\n' "$device_id" | xclip -selection clipboard + notify-send "📋 Copied to clipboard" "$device_id" +fi diff --git a/.local/bin/desktop/dmenu-unicode b/.local/bin/desktop/dmenu-unicode new file mode 100755 index 0000000..16e1cfc --- /dev/null +++ b/.local/bin/desktop/dmenu-unicode @@ -0,0 +1,11 @@ +#!/bin/sh + +chosen=$(cat ~/.local/share/chars/* | dmenu -i -l 25 -fn :size=20) + +[ -z "$chosen" ] && exit + +if [ -n "$1" ]; then + printf "%s" "${chosen#* }" | cut -d\; -f1 | tr -d '\n' | xclip -selection clipboard +else + printf "%s" "${chosen%% *}" | xclip -selection clipboard +fi diff --git a/.local/bin/desktop/dmenu-zeal b/.local/bin/desktop/dmenu-zeal new file mode 100755 index 0000000..608be89 --- /dev/null +++ b/.local/bin/desktop/dmenu-zeal @@ -0,0 +1,27 @@ +#!/bin/sh + +cd ~/.local/share/Zeal/Zeal || exit + +selection="$(echo "Shell +C/C++ +Java +Python +$(find . -maxdepth 1 -type d ! -name 'docsets' | + tail +2 | cut -c3- | sed 's/^/ds:/') +" | dmenu -i -p "Select docset group")" + +case "$selection" in + Shell) key="bash,zsh,linux" ;; + C/C++) key="c,cpp,linux" ;; + Java) key="java,javaspec" ;; + Python) key="python,numpy,matplotlib" ;; + ds:*) + ln -sfT "${selection#ds:}" docsets + killall -q zeal; zeal + exit + ;; + *) exit 2 ;; +esac + +query="$(dmenu -p "Enter query")" +zeal "$key:$query" diff --git a/.local/bin/desktop/edit-graphical-buffer b/.local/bin/desktop/edit-graphical-buffer new file mode 100755 index 0000000..10eac8f --- /dev/null +++ b/.local/bin/desktop/edit-graphical-buffer @@ -0,0 +1,17 @@ +#!/bin/sh + +sleep 0.5 +xdotool key --clearmodifiers ctrl+a ctrl+c +content="$(xclip -o -sel clipboard)" + +tempfile=/tmp/scratch-buffer/$$.txt +mkdir -pv /tmp/scratch-buffer +echo "$content" | tee "$tempfile" > "$tempfile.bak" +${TERMINAL:-xdg-terminal-exec} -c dropdown_buffer -e nvim "$tempfile" + +diff "$tempfile" "$tempfile.bak" >/dev/null || { + xclip -sel clipboard < "$tempfile" + xdotool key --clearmodifiers ctrl+a ctrl+v +} + +rm -f "$tempfile" "$tempfile.bak" diff --git a/.local/bin/desktop/i3exit b/.local/bin/desktop/i3exit new file mode 100755 index 0000000..0be387c --- /dev/null +++ b/.local/bin/desktop/i3exit @@ -0,0 +1,54 @@ +#!/bin/sh + +# with openrc use loginctl +[ "$(cat /proc/1/comm)" = "systemd" ] && logind=systemctl || logind=loginctl + +command="$1" +system_control() { + if [ "$(loginctl show-session --property=NCurrentSessions --value)" -gt 2 ]; then + notify-send --replace-id=4252 \ + "i3exit" "Multiple users are logged in\nCant't $command" + exit + fi + eval "$@" +} + +lockWall="$HOME/.local/share/lockWall" +lock_desktop() { + [ -f "$lockWall" ] && + i3lock --tiling --image="$lockWall" || + i3lock --color=001177 + pkill ssh-agent +} + +case "$command" in + lock) + lock_desktop + xset dpms force off + ;; + logout) + switch-session + i3-msg exit + ;; + switch_user) + dm-tool switch-to-greeter + ;; + suspend) + lock_desktop; $logind suspend + ;; + hibernate) + system_control lock_desktop && $logind hibernate + ;; + reboot) + system_control $logind reboot + ;; + shutdown) + system_control $logind poweroff + ;; + *) + echo "== ! i3exit: missing or invalid argument ! ==" + echo "Try again with: lock | logout | switch_user | suspend | hibernate | reboot | shutdown" + exit 2 +esac + +exit 0 diff --git a/.local/bin/desktop/i3exit-script b/.local/bin/desktop/i3exit-script new file mode 100755 index 0000000..b27f0f5 --- /dev/null +++ b/.local/bin/desktop/i3exit-script @@ -0,0 +1,18 @@ +#!/bin/bash +# TODO: copy and configure the i3 script to take parametres +# possibly make it as syst-power + +# snippet for blur effect on lock screen + + +# DEPEDNDENCIES: i3lock imagemagic scrot + +PICTURE=/tmp/i3lock.png +SCREENSHOT="scrot $PICTURE" + +BLUR="5x4" + +$SCREENSHOT +convert $PICTURE -blur $BLUR $PICTURE +i3lock -i $PICTURE +rm $PICTURE diff --git a/.local/bin/desktop/librewolf-open b/.local/bin/desktop/librewolf-open new file mode 100755 index 0000000..4bb2d70 --- /dev/null +++ b/.local/bin/desktop/librewolf-open @@ -0,0 +1,39 @@ +#!/bin/sh + +window="LibreWolf" +running() { windows=$(wmctrl -l) + test "${windows#*"$window"}" != "$windows"; } +press() { sleep 0.1; xdotool keyup Super + xdotool key --clearmodifiers "$@"; } + +if ! running; then + notify-send "Starting $window..." + start="$(date +%s.%3N)" + setsid -f librewolf -P "${FFPROFILE:-default-release}" + for _ in $(seq 1000); do sleep 0.1; running && break; done + end="$(date +%s.%3N)" + time="$(echo "$end - $start" | bc)" + notify-send "$window" "Started in ${time}s" + started=1 +fi + +wmctrl -a "$window" || + { notify-send "ffbrowser" "ERROR: librewolf window not found"; exit 1; } +[ "$started" = 1 ] || press ctrl+t + +query="$*" +if [ "$query" != "${query#http*://}" ]; then + press ctrl+l +elif [ -e "$query" ]; then + query="$(readlink -f "$query")"; press ctrl+l +else + # workaround for ctrl+k not working at initial startup + [ "$started" = 1 ] && sleep 0.5 + press ctrl+k +fi + +if [ -n "$query" ]; then + xdotool type "$query" + press Return +fi + diff --git a/.local/bin/desktop/mlock b/.local/bin/desktop/mlock new file mode 100755 index 0000000..67da8a3 --- /dev/null +++ b/.local/bin/desktop/mlock @@ -0,0 +1,22 @@ +#!/bin/sh + +command -v xtrlock || exit + +[ "$(xrandr --current | grep -c "\S* connected \S\+.* (")" -gt 1 ] && { + xtrlock -b -f + xset dpms force off + exit +} + +TERMINAL="alacritty -t matrixlock" +if command -v cxxmatrix; then + $TERMINAL -e cxxmatrix & +elif command -v cmatrix; then + $TERMINAL -e sh -c 'sleep 0.5 && cmatrix' & +else + xtrlock -b -f; exit +fi + +xtrlock -f +sleep 0.2 +wmctrl -r matrixlock -b add,fullscreen diff --git a/.local/bin/desktop/remap b/.local/bin/desktop/remap new file mode 100755 index 0000000..3635464 --- /dev/null +++ b/.local/bin/desktop/remap @@ -0,0 +1,146 @@ +#!/bin/sh + +# This script cannot run without the X server (GUI) +# So exit if DISPLAY is not set +[ -z "$DISPLAY" ] && { + notify-send remap "ERROR: DISPLAY not set" + exit +} + +timeout="${KEY_RELEASE_TIMEOUT:-500}" + +help() { echo "remap - remap modifier keys for easy access + +USAGE: + remap [OPTION]... + +OPTIONS: + -x reset keys + -t toggle (remap/reset) + -s show remap status + -i show info of all key remaps + -h show this help message"; } + +key_info() { echo " + +-----------------+-----------------------------------+ + | Before | After | + +-----------------+-----------------+-----------------+ + | Key | On Hold | On Tap | + +-----------------+-----------------+-----------------+ + | Tab | Super | Tab | + | Caps Lock | Ctrl | Esc | + | Space | Shift | Space | + | Left Ctrl | Ctrl | Caps Lock | + | Escape | Tab | Tab | + +-----------------+-----------------+-----------------+ + +Note: + By default, 'On Tap' will timeout at 500 miliseconds. In other words, + if you release a key after timeout, the key will not be generated. + You can increase it's value by setting the \$KEY_RELEASE_TIMEOUT environment + variable. This is useful in case you don't have a fast typing speed. + +If you want to change more keys or want a different configuration, you +can edit the remap_keys() function inside this script. + "; } + +while getopts 'rxtsih' o; do case "$o" in + x) action=x ;; + t) action=t ;; + s) action=s ;; + i) key_info >&2; exit ;; + h) help >&2; exit ;; + *) printf "remap: invalid argument -- '%s'\n" "$OPTARG" ;; +esac; done + +status_file="/tmp/.remap.lock" +keymap_file="/tmp/.xmodmap.defaults" +[ -f "$keymap_file" ] || xmodmap -pke > "$keymap_file" + +msg() { + [ "$VERBOSE_REMAP" != 1 ] && return + printf "remap: %s\n" "$@" + # notify-send "remap" "$*" +} + +remap_keys() { + msg "remapping keys..." + # Fast key repeats + xset r rate 300 50 + + # New key behaviour on Hold + # lines after ! are comments + xmodmap - <<-EOF + ! Hold Caps_Lock -> Control_R + remove lock = Caps_Lock + remove Control = Control_R + ! keysym Control_R = Caps_Lock + keysym Caps_Lock = Control_R + ! add lock = Caps_Lock + add Control = Control_R + keycode any = Caps_Lock + + ! Hold space -> Shift_R + remove shift = Shift_R + keycode 65 = Shift_R + add shift = Shift_R + keycode any = space + + ! Hold Tab -> Super_L + ! ! Escape -> Tab + remove mod4 = Super_L + keycode 23 = Super_L + keycode any = Tab ISO_Left_Tab Tab ISO_Left_Tab + ! keycode 133 = Tab ISO_Left_Tab Tab ISO_Left_Tab + add mod4 = Super_L + ! keycode 230 = Escape + ! keycode 9 = Tab ISO_Left_Tab Tab ISO_Left_Tab + EOF + + # New key behaviour on Tap + killall xcape 2>/dev/null + xcape -t "$timeout" -e "Super_L=Tab" + xcape -t "$timeout" -e "Control_R=Escape" + xcape -t "$timeout" -e "Shift_L=Caps_Lock" + xcape -t "$timeout" -e "Shift_R=space" + date > "$status_file" + xset led 3 + msg "keys remapped" +} + + +reset_keys() { + msg "resetting keys..." + xset r rate + killall xcape 2>/dev/null + setxkbmap -layout us + xmodmap "$keymap_file" + + [ -f "$status_file" ] && rm "$status_file" + xset -led 3 + msg "keys reset" +} + +toggle_remap() { + if [ -f "$status_file" ]; then + reset_keys + else + remap_keys + fi +} + +remap_status() { + if [ -f "$status_file" ]; then + printf "Keys are remapped since " + cat "$status_file" + else + echo "Keys are NOT remapped" + fi +} + +case "$action" in + s) remap_status ;; + x) reset_keys ;; + t) toggle_remap ;; + *) remap_keys ;; +esac diff --git a/.local/bin/desktop/remapd b/.local/bin/desktop/remapd new file mode 100755 index 0000000..851d7d2 --- /dev/null +++ b/.local/bin/desktop/remapd @@ -0,0 +1,6 @@ +#!/bin/sh + +while :; do + remap + grep -qP -m1 '[^un]bind.+\/[^:]+\(usb\)' <(udevadm monitor -u -t seat -s input -s usb) +done diff --git a/.local/bin/desktop/setdp b/.local/bin/desktop/setdp new file mode 100755 index 0000000..48c6a7a --- /dev/null +++ b/.local/bin/desktop/setdp @@ -0,0 +1,36 @@ +#!/bin/sh + +displays="$(xrandr | grep "^\S* connected" | cut -d\ -f1)" +display_count="$(echo "$displays" | wc -l)" + +[ "$display_count" -gt 2 ] && + { echo "Too many displays to configure" >&2; exit 1; } + +set -- + + +if [ "$display_count" = 2 ]; then + + for display in $displays; do + case "$display" in + eDP*) export PRIMARY="$display"; set -- "$@" --output "$display" --mode 1920x1080 --primary --pos 0x270 ;; + HDMI*) set -- "$@" --output "$display" --mode 1920x1080 --pos 1920x0 --scale "1.25x1.25" ;; + esac + done + +else + + for display in $displays; do + case "$display" in + eDP*) set -- "$@" --output "$display" --primary --mode 1920x1080 --scale "1.1x1.1" ;; + HDMI*) set -- "$@" --output "$display" --mode 1366x768 --scale "1.25x1.25" ;; + LVDS*) set -- "$@" --output "$display" --primary ;; + DP*) set -- "$@" --output "$display" --primary --scale "1.1x1.1" ;; + esac + done + +fi + + +eval "xrandr --auto $*" + diff --git a/.local/bin/desktop/show-i3-keybindings b/.local/bin/desktop/show-i3-keybindings new file mode 100755 index 0000000..45d0626 --- /dev/null +++ b/.local/bin/desktop/show-i3-keybindings @@ -0,0 +1,11 @@ +#!/bin/sh + +if [ -n "$TERM" ]; then + grep '^bindsym' ~/.config/i3/config | sort | + sed 's/^bindsym \(\S*\)\s\+\(.*\)$/\1|\2/; s/\$super+/ /; s/Shift+/וּ /; s/$alt+/Alt /; s/Ctrl+/Ctrl /' | + column --table --separator='|' | less -r +else + grep '^bindsym' ~/.config/i3/config | sort | + sed 's/^bindsym \(\S*\)\s\+\(.*\)$/\1|\2/; s/\$super+/ /; s/Shift+/Shift /; s/$alt+/Alt /; s/Ctrl+/Ctrl /' | + column --table --separator='|' | yad --text-info +fi diff --git a/.local/bin/desktop/toggle-xeyes b/.local/bin/desktop/toggle-xeyes new file mode 100755 index 0000000..af5c590 --- /dev/null +++ b/.local/bin/desktop/toggle-xeyes @@ -0,0 +1,7 @@ +#!/bin/sh + +if pidof -q xeyes; then + killall xeyes +else + setsid -f xeyes +fi diff --git a/.local/bin/desktop/torbrowser b/.local/bin/desktop/torbrowser new file mode 100755 index 0000000..27e365b --- /dev/null +++ b/.local/bin/desktop/torbrowser @@ -0,0 +1,30 @@ +#!/bin/sh + +help() { echo "torbrowser - open or search in tor browser +USAGE: torbrowser <open|search> [query]"; } + +cmd="$1" +case "$cmd" in + open) extra_cmds='' ;; + search) extra_cmds='press ctrl+k' ;; + *) help >&2; exit 1 ;; +esac + +query="$2" +window="Tor Browser" +windows=$(wmctrl -l) +if [ "${windows##*"$window"}" = "$windows" ]; then + # query="$(dmenu -p "search in tor browser")" || exit + torbrowser-launcher && sleep 3 +fi + +press() { + xdotool keyup ctrl shift alt super meta BackSpace Tab Escape Return + xdotool key "$1" +} + +wmctrl -a "$window" +press ctrl+t +$extra_cmds +xdotool type "$query" +press Return diff --git a/.local/bin/desktop/volctl b/.local/bin/desktop/volctl new file mode 100755 index 0000000..7d0edb9 --- /dev/null +++ b/.local/bin/desktop/volctl @@ -0,0 +1,50 @@ +#!/bin/sh + +help() { echo "volctl - change system volume +USAGE: volctl <toggle|up|down>"; } + +[ "$#" -lt 1 ] && help >&2 && exit 1 + +case "$1" in + toggle) wpctl set-mute @DEFAULT_SINK@ toggle ;; + up) wpctl set-volume @DEFAULT_SINK@ 5%+ ;; + down) wpctl set-volume @DEFAULT_SINK@ 5%- ;; + *) help >&2; exit 1 ;; +esac + +vol="$(wpctl get-volume @DEFAULT_SINK@ | tr -d .)" +vol="${vol#Volume: }" + +notify() { + if [ -n "$DISPLAY" ]; then + notify-send -t 3000 -r 93475 "$1" + else + printf 'volume : ' + wpctl get-volume @DEFAULT_SINK@ + fi +} + +if [ "$vol" != "${vol% \[MUTED\]}" ]; then + vol="${vol% \[MUTED\]}" + muted=1 +else + muted=0 +fi + +vol="$(printf '%.0f' "$vol")" + +msg="" +if [ "$vol" -gt "100" ]; then icon="📢"; msg=" Boosted" +elif [ "$vol" = "100" ]; then icon="🔊"; msg=" Maxed" +elif [ "$vol" -gt "70" ]; then icon="🔊" +elif [ "$vol" -gt "30" ]; then icon="🔉" +elif [ "$vol" -gt "0" ]; then icon="🔈" +else icon="🔇" +fi + +if [ "$muted" -eq 1 ]; then + notify "🔇 Volume Muted ($vol%)" +else + notify "$icon Volume$msg: $vol%" +fi + diff --git a/.local/bin/development/dev b/.local/bin/development/dev new file mode 100755 index 0000000..76f1772 --- /dev/null +++ b/.local/bin/development/dev @@ -0,0 +1,179 @@ +#!/bin/sh + +err() { [ "$DEV_SUPRESS_ERRORS" = 1 ] || + printf "dev: %s\n" "$@" >&2; exit 5; } + +[ "$#" -lt 2 ] && { err "dev - execute action based on file +USAGE: dev <ACTION> <FILE> [ARGS...]"; } + +action="$1" +file="$2" +basename="${file##*/}" +shift 2 + +[ -e "$file" ] || err "$file: No such file or directory" + +# auxilary functions +findweb() { find "$@" -or -name '*.html'; } + + + +### ################################################################# +### BEGIN TASKS +### ################################################################# + +sh_lint() { shellcheck -x "$file"; } +sh_run() { $(sed -n '1s|^#!/.*/\(.*\)|\1|p' "$file") "$file" "$@"; } +zsh_run() { zsh "$file" "$@"; } +awk_run() { awk -f "$file" "$@"; } +pl_run() { perl "$file" "$@"; } + +md_run() { glow --pager --style dark "$file"; } +md_test() { pandoc -t pdf "$file" | zathura -; } +tex_compile() { pdflatex -output-directory="$(dirname "$file")" "$file"; } +tex_clean() { find "$(dirname "${1}")" -regex \ + '.*\(_minted.*\|.*\.\(4tc\|xref\|tmp\|pyc\|pyg\|pyo\|fls\|vrb\|fdb_latexmk\|bak\|swp\|aux\|log\|synctex\(busy\)\|lof\|lot\|maf\|idx\|mtc\|mtc0\|nav\|out\|snm\|toc\|bcf\|run\.xml\|synctex\.gz\|blg\|bbl\)\)' -delete; } +html_format() { tidy -q "$file" 2>/dev/null; } +html_lint() { tidy -q "$file" >/dev/null; } +html_run() { w3m "$file"; } +js_test() { node "$file"; } +json_format() { jq . "$file"; } +php_run() { php "$file" "$@"; } + +c_compile() { make "${file%.c}"; } +c_run() { "$(realpath "${file%.c}")" "$@"; } +c_clean() { rm -v "${file%.c}"; } + +go_format() { gofmt "$file"; } +go_lint() { gofmt -d "$file"; } +go_compile() { go build "$file"; } +go_run() { "$(realpath "${file%.go}")" "$@"; } +go_test() { go run "$file" "$@"; } +go_serve() { findweb . -name '*.go' | entr -r sh -c "printf '\n\n$ go run *.go\n'; go run *.go"; } + +c_test() { + out="${file%.c}" + # ARGS="$(sed -nE -e 's|.*#include\s*<(.*)>|-l\1|gp' "$file" | + # paste -d' ' -s)" + # echo "$ clang -o $out $file $ARGS" + # clang -o "$out" "$file" $ARGS && "$out" "$@" + make "$out" && echo && "$(realpath "$out")" "$@" +} + +cpp_test() { + out="$(realpath "${file%.cpp}")" + if [ -f GNUmakefile ] || [ -f makefile ] || [ -f Makefile ]; then + make && "${out%/*}/main" "$@" + else + g++ -o "$out" "$file" && "$out" "$@" + fi +} + +ino_test() { + [ -t 1 ] || set -- --no-color + if [ -c /dev/ttyACM0 ]; then + arduino-cli compile --fqbn arduino:avr:uno "$file" "$@" + arduino-cli upload --fqbn arduino:avr:uno --port /dev/ttyACM0 "$file" "$@" + if [ -t 1 ]; then + picocom /dev/ttyACM0 + else + stty -F /dev/ttyACM0 raw 9600 + cat /dev/ttyACM0 + fi + else + arduino-cli compile --fqbn arduino:avr:uno --output-dir . "$file" "$@" + rm -- *.eep *.elf *.bin *.with_bootloader.hex + fi +} + +java_test() { + if [ -f build.xml ]; then + ant + build="$(find . -name 'classes' -or -name 'build' | tail -1)" + class="$({ cd "$build" && + find . -name "$(basename "$file" .java).class"; } | + tail -1 | cut -c 3- | sed 's|.class||g' | tr '/' '.')" + else + mkdir -pv build + build="$(dirname "$file")/build" + class="$(basename "$file" .java)" + javac -d "$build" "$file" + fi + java -cp "$build:lib/*" "$class" +} + +kt_test() { + out="${file%.*}.jar" + bash /opt/android-studio/plugins/Kotlin/kotlinc/bin/kotlinc "$file" -include-runtime -d "$out" + java -jar "$out" + rm "$out" +} + +py_serve() { findweb . -name '*.py' | entr -r python "$file"; } +# py_lint() { +# [ -t 1 ] && printf '\033[33m' +# pycodestyle "$file" >&2 +# [ -t 1 ] && printf '\033[0;39m' +# } + +py_run() { + python "$file" "$@" + # if [ -x "${XDG_DATA_HOME:-$HOME/.local/share}/virtualenvs/main/bin/python" ]; then + # "${XDG_DATA_HOME:-$HOME/.local/share}/virtualenvs/main/bin/python" "$file" "$@" + # else + # python "$file" "$@" + # fi +} + +### ################################################################# +### END TASKS +### ################################################################# + + + +filetype=$(file --brief --mime-type "$file") +case $filetype in + text/x-c) filetype_ext="c" ;; + text/x-script.python) filetype_ext="py" ;; + text/x-shellscript) filetype_ext="sh" ;; + text/html) filetype_ext="html" ;; + application/javascript) filetype_ext="js" ;; + text/x-php) filetype_ext="php" ;; + text/x-awk) filetype_ext="awk" ;; +esac + +if [ "${basename#*.}" != "${basename}" ]; then + file_ext="${basename##*.}" +else + [ -z "$filetype_ext" ] && err "no file type association for $filetype" + NO_BASENAME=1 +fi + +execute_task() { + [ "$NO_BASENAME" != 1 ] && { + file_task="${file_ext}_${action}" + [ "${tasks#*"[$file_task]"}" != "$tasks" ] && + { $file_task; local ret=$?; local tasked=1; } + } + [ "$tasked" != 1 ] && { + filetype_task="${filetype_ext}_${action}" + [ "${tasks#*"[$filetype_task]"}" != "$tasks" ] && + { $filetype_task; local ret=$?; local tasked=1; } + } + [ "$tasked" != 1 ] && return 1 + [ "$ret" != 0 ] && printf "\nshell returned %s\n" "$ret" >&2 + return 0 +} + +tasks="$(sed -n "/^### BEGIN TASKS$/,/^### END TASKS$/ s/\(^[a-zA-Z0-9_]\+\)().*/[\1]/p" "$0")" + +if [ "$action" = test ]; then + execute_task && exit + for action in lint compile run; do + execute_task && tested=1 + done + [ "$tested" != 1 ] && err "no tests for .${file_ext:-$filetype_ext} file" + exit 0 +fi + +execute_task || err "no $action action for .${file_ext:-$filetype_ext} file" diff --git a/.local/bin/development/getcomproot b/.local/bin/development/getcomproot new file mode 100755 index 0000000..16e946a --- /dev/null +++ b/.local/bin/development/getcomproot @@ -0,0 +1,14 @@ +#!/bin/bash + +# author: Luke Smith +# +# A helper script for LaTeX/groff files used by `compiler` and `opout`. +# The user can add the root file of a larger project as a comment as below: +# % root = mainfile.tex +# And the compiler script will run on that instead of the opened file. + +texroot="$(grep -i "^.\+\s*root\s*=\s*\S\+" "$1")" +texroot="${texroot##*=}" +texroot="${texroot//[\"\' ]}" + +[ -f "$texroot" ] && readlink -f "$texroot" || exit 1 diff --git a/.local/bin/development/gitpush b/.local/bin/development/gitpush new file mode 100755 index 0000000..97aa43b --- /dev/null +++ b/.local/bin/development/gitpush @@ -0,0 +1,10 @@ +#!/bin/sh + +case "$(git config --get remote.origin.url)" in + *csstudent41*) sshadd ~/.ssh/github.com_id_ed25519 ;; + *labstudent41*) sshadd ~/.ssh/labstudent41_id_ed25519 ;; +esac + +git add --all +git commit # --allow-empty-message +git push -u origin diff --git a/.local/bin/development/gitw b/.local/bin/development/gitw new file mode 100755 index 0000000..881c81c --- /dev/null +++ b/.local/bin/development/gitw @@ -0,0 +1,18 @@ +#!/bin/sh + +# git-web: open the url of current git repositary in a web browser. +# USAGE: gitw [remote] +# 'remote' is set to origin if not provided. + +err() { printf "gitw: %s\n" "$@" >&2; exit 1; } + +git rev-parse --is-inside-work-tree >/dev/null || exit + +remote="${1:-origin}" +url="$(git remote get-url "$remote" | + sed "s|^git@\(\S\+\):|https://\1/|")" || exit + +[ -z "$url" ] || [ "$remote" = "$url" ] && + err "remote has no url: $remote" + +xdg-open "$url" diff --git a/.local/bin/development/ipy b/.local/bin/development/ipy new file mode 100755 index 0000000..1f39550 --- /dev/null +++ b/.local/bin/development/ipy @@ -0,0 +1,4 @@ +#!/bin/sh + +unset PYTHONSTARTUP +"${XDG_DATA_HOME:-$HOME/.local/share}/virtualenvs/main/bin/ipython" "$@" diff --git a/.local/bin/development/ipytest b/.local/bin/development/ipytest new file mode 100755 index 0000000..17a5a55 --- /dev/null +++ b/.local/bin/development/ipytest @@ -0,0 +1,23 @@ +#!/bin/sh +# create a 'dev' firefox profile and use it in selenium + +[ -z "$FF_DEV_PROFILE" ] && [ -d ~/.librewolf ] && + FF_DEV_PROFILE="$(find ~/.librewolf/ -maxdepth 1 -type d -name '????????.dev')" + +[ -z "$FF_DEV_PROFILE" ] && [ -d ~/.librewolf ] && + FF_DEV_PROFILE="$(find ~/.mozilla/ -maxdepth 1 -type d -name '????????.dev')" + +ipy -i -c " +from selenium import webdriver +from selenium.webdriver.common.by import By + +options = webdriver.FirefoxOptions() +options.binary_location = '/usr/bin/librewolf' +options.profile = webdriver.FirefoxProfile(\"$FF_DEV_PROFILE\") + +d = webdriver.Firefox(options=options) +d.get(\"${1:-http://127.0.0.1}\") + +import atexit +atexit.register(d.quit) +" diff --git a/.local/bin/development/nx b/.local/bin/development/nx new file mode 100755 index 0000000..862be99 --- /dev/null +++ b/.local/bin/development/nx @@ -0,0 +1,148 @@ +#!/bin/sh + +help() { + echo "nx - create new script" + echo "USAGE: nx <script_name>" +} + +err() { printf '%s: %s\n' "$0" "$@" >&2; exit 1; } +warn() { + printf '%s: %s [Y/n] ' "$0" "$@" >&2; read -r arg + case "$arg" in ''|y|Y) ;; *) exit ;; esac +} + +while getopts 'h' o; do case "$o" in + h) help >&2; exit ;; + *) err "invalid option -- '$OPTARG'" ;; +esac done +shift $((OPTIND - 1)) + +[ "$#" -lt 1 ] && help && exit 1 +[ "$#" -gt 1 ] && err "too many arguments. Only one expected" + + +new_script() { + cat << EOF > "$1" +#!/bin/sh + +help() { echo "$1 - + +USAGE: + $1 [OPTION]... + +OPTIONS: + -h show this help message"; } + +err() { printf '$1: %s\n' "\$@" >&2; exit 1; } +while getopts 'h' o; do case "\$o" in + h) help; exit ;; + *) err "invalid option -- '\$OPTARG'" ;; +esac done +shift \$((OPTIND - 1)) + +[ "\$#" -lt 1 ] && help >&2 && exit 1 + +EOF + + chmod u+x -- "$1" || exit +} + + +new_c_file() { + cat << EOF > "$1" +#include <stdio.h> + +int main() +{ + printf("Hello\n"); + + return 0; +} +EOF +} + + +new_cpp_file() { + cat << EOF > "$1" +#include <iostream> + +using namespace std; + +int main() +{ + cout << "Hello" << endl; + + cin.get(); + return 0; +} +EOF +} + + +new_py_file() { + cat << EOF > "$1" +import timeit + +print("Finished in %fs" % timeit.timeit()) +EOF +} + + +new_java_file() { + PATTERN="Scanner" + VIMCMDS="normal!2n\n noh" + cat << EOF > "$1" +import java.util.Scanner; + +class ${1%.java} { + public static void main(String args[]) { + Scanner sc = new Scanner(System.in); + + System.out.println("Finished!"); + sc.close + } +} +EOF +} + + +file="$1" + +new_file() { + case "$file" in + *.c) new_c_file "$file" ;; + *.cpp) new_cpp_file "$file" ;; + *.py) new_py_file "$file" ;; + *.java) new_java_file "$file" ;; + *) new_script "$file" ;; + esac +} + +if [ -f "$file" ]; then + [ ! -w "$file" ] && chmod u+rw "$file" + if [ -s "$file" ]; then + warn "'$file' already exists, edit existing file?" || exit + else + warn "an empty file '$file' already exists, fill and edit?" && + new_file "$file" + fi +elif [ -e "$file" ]; then + err "'$file' already exists and is a non-regular file" +else + new_file "$file" +fi + +ls -lF --color -- "$file" + +case "$EDITOR" in + '') echo "$0: \$EDITOR variable not set" >&2 && exit 1 ;; + vi|*vim*) + VIMCONF="$(mktemp)"; export VIMCONF + [ -n "$VIOPTS" ] && echo "set $VIOPTS" >> "$VIMCONF" + [ -n "$PATTERN" ] && echo "/$PATTERN" >> "$VIMCONF" + [ -n "$VIMCMDS" ] && echo "$VIMCMDS" >> "$VIMCONF" + $EDITOR -S "$VIMCONF" "$file" + rm -f "$VIMCONF" + ;; + *) $EDITOR "$file" ;; +esac; exit diff --git a/.local/bin/development/opout b/.local/bin/development/opout new file mode 100755 index 0000000..3adc8fd --- /dev/null +++ b/.local/bin/development/opout @@ -0,0 +1,12 @@ +#!/bin/sh + +basename="${1%.*}" +err() { printf "opout: %s\n" "$@" >&2; exit 1; } + +case "${*}" in + '') err "filename required" ;; + *.tex|*.sil|*.m[dse]|*.[rR]md|*.mom|*.[0-9]) target="$(getcomproot "$1" || echo "$1")" ; setsid -f "${OPENER:-xdg-open}" "${target%.*}".pdf >/dev/null 2>&1 ;; + *.html) setsid -f xdg-open "$basename".html >/dev/null 2>&1 ;; + *.sent) setsid -f sent "$1" >/dev/null 2>&1 ;; + *) err "file extension unmatched" +esac diff --git a/.local/bin/development/pipsearch b/.local/bin/development/pipsearch new file mode 100755 index 0000000..0d1d495 --- /dev/null +++ b/.local/bin/development/pipsearch @@ -0,0 +1,4 @@ +#!/bin/sh + +{ sleep 1 && tmux send-keys /search\ results Enter; } & +tmux new w3m "http://pypi.org/search?q=$*" diff --git a/.local/bin/development/py b/.local/bin/development/py new file mode 100755 index 0000000..af32c95 --- /dev/null +++ b/.local/bin/development/py @@ -0,0 +1,4 @@ +#!/bin/sh + +"${XDG_DATA_HOME:-$HOME/.local/share}/virtualenvs/main/bin/python" "$@" + diff --git a/.local/bin/development/pyh b/.local/bin/development/pyh new file mode 100755 index 0000000..fdd524a --- /dev/null +++ b/.local/bin/development/pyh @@ -0,0 +1,12 @@ +#!/bin/sh + +# python-help: get help for keywords in python + +[ -x "${XDG_DATA_HOME:-$HOME/.local/share}/virtualenvs/main/bin/python" ] && + alias python="${XDG_DATA_HOME:-$HOME/.local/share}/virtualenvs/main/bin/python" + +if [ "$#" -gt 0 ]; then + python -c "help('$*')" +else + python -c "help()" +fi diff --git a/.local/bin/development/texclear b/.local/bin/development/texclear new file mode 100755 index 0000000..6ad3c12 --- /dev/null +++ b/.local/bin/development/texclear @@ -0,0 +1,9 @@ +#!/bin/sh + +# Clears the build files of a LaTeX/XeLaTeX build. +# I have vim run this file whenever I exit a .tex file. + +[ "${1##*.}" = "tex" ] && { + find "$(dirname "${1}")" -regex '.*\(_minted.*\|.*\.\(4tc\|xref\|tmp\|pyc\|pyg\|pyo\|fls\|vrb\|fdb_latexmk\|bak\|swp\|aux\|log\|synctex\(busy\)\|lof\|lot\|maf\|idx\|mtc\|mtc0\|nav\|out\|snm\|toc\|bcf\|run\.xml\|synctex\.gz\|blg\|bbl\)\)' -delete +} || printf "Provide a .tex file.\n" + diff --git a/.local/bin/fcode b/.local/bin/fcode new file mode 100755 index 0000000..8da7a17 --- /dev/null +++ b/.local/bin/fcode @@ -0,0 +1,23 @@ +#!/bin/sh + +# fzf-unicode: get a list of emojis or unicode charecters using fzf +# place your charecter files in plain text in ~/.local/share/chars/* + +FZF_HIST="$HOME/.local/share/fzf/unicode_history" +mkdir -pv ~/.local/share/fzf + +if [ "$OPENFLAG" = 0 ]; then + notify-send fzf-unicode "$*" + chosen="$(printf '%s\n' "$@" | cut -d\ -f1 | tr -d '\n')" + echo "$chosen" | xclip -selection clipboard + notify-send "'$chosen' copied to clipboard." + exit +fi + +cut -d ';' -f1 ~/.local/share/chars/* | + fzf -m --history="$FZF_HIST" \ + --header="Copy Emojis to Clipboard" --header-first \ + --preview 'printf "%s\n" {+} | cut -d\ -f1 | tr -d "\n"' \ + --preview-window=nohidden,up,1 \ + --bind 'ctrl-/:change-preview-window(down|up)' \ + --bind 'enter:execute(echo {q} >> $FZF_HIST; OPENFLAG=0 fzf-unicode {+})' diff --git a/.local/bin/fdict b/.local/bin/fdict new file mode 100755 index 0000000..8a4ed61 --- /dev/null +++ b/.local/bin/fdict @@ -0,0 +1,25 @@ +#!/bin/sh + +# fzf-dict: get word definitions using sdcv + +mkdir -pv ~/.local/share/fzf +export SDCV_PAGER="less -R" + +if [ "$OPENFLAG" = 0 ]; then + sdcv --color \ + -u 'WordNet® 3.0 (En-En)' \ + -u 'American Heritage Dictionary 4th Ed. (En-En)' \ + -u 'Urban Dictionary P1 (En-En)' \ + -u 'Urban Dictionary P2 (En-En)' \ + "$@" + sdcv -u 'Wikipedia English - Free Encyclopedia' "$@" | w3m -T text/html + exit +fi + +grep -v \' "${PREFIX:-/usr}/share/dict/words" | fzf \ + --history "$HOME/.local/share/fzf/word_history" \ + --header "Startdict Dictionary" --header-first \ + --preview='OPENFLAG=0 fzf-words {} | fold -sw "$FZF_PREVIEW_COLUMNS"' \ + --preview-window='nohidden,75%' --tiebreak=begin --print-query \ + --bind 'alt-enter:execute(OPENFLAG=0 fzf-words {q})' \ + --bind 'enter:execute(OPENFLAG=0 fzf-words {})' diff --git a/.local/bin/fgrp b/.local/bin/fgrp new file mode 100755 index 0000000..ddf3448 --- /dev/null +++ b/.local/bin/fgrp @@ -0,0 +1,27 @@ +#!/bin/sh + +# fzf-grep: browse through grepped lines using fzf + +if [ "$OPENFLAG" = 0 ]; then + location="$(echo "$*" | sed 's/^\(.*\):\([0-9]\+\):.*$/\1|\2/')" + file="${location%|*}"; line="${location##*|}" + case "${OPENWITH:=$EDITOR}" in + ''|vi|*vim*) $OPENWITH +"$line" "$file" ;; + *) $OPENWITH "$file" ;; + esac; exit +fi + +mkdir -pv "${XDG_DATA_HOME:=$HOME/.local/share}/fzf" +export FZF_HIST="$XDG_DATA_HOME/fzf/grep_history" +grep -Rnsi --exclude-dir=.git --exclude-dir=node_modules --color=always "$@" | + fzf --ansi \ + --history="$FZF_HIST" \ + --prompt="grep > " \ + --preview='preview "$(echo {1} | cut -d: -f1)"' \ + --preview-window="hidden" \ + --bind 'ctrl-v:toggle-preview,ctrl-space:toggle-preview' \ + --bind "ctrl-r:reload(grep -Rns --color=always $*)" \ + --bind 'enter:execute(echo {} >> "$FZF_HIST"; OPENFLAG=0 fgrp {})' \ + --bind 'alt-e:execute(echo {} >> "$FZF_HIST"; OPENFLAG=0 OPENWITH=${EDITOR:-vi} fgrp {})' \ + --bind 'alt-o:execute(echo {} >> "$FZF_HIST"; OPENFLAG=0 OPENWITH=${OPENER:-xdg-open} fgrp {})' \ + --bind 'alt-O:execute(echo {} >> "$FZF_HIST"; OPENFLAG=0 OPENWITH=${FILES:-lf} fgrp {})' diff --git a/.local/bin/filter b/.local/bin/filter new file mode 100755 index 0000000..9d3e5e3 --- /dev/null +++ b/.local/bin/filter @@ -0,0 +1,52 @@ +#!/bin/sh + +help() { echo "filter - filter input based on given expression to evaluate + +USAGE: + filter [OPTION]... <FILTER_EXPRESSION> [FILES]... + +OPTIONS: + -i update files with filtered content + -h show this help message + +FILTER_EXPRESSION is a contains the command string that will be executed to test +the input line. {} should be used as a placeholder that will be replaced to the +double-quoted string of the input line. If the command evaluates to true, the +line is printed to stdout. +"; } + +err() { printf 'filter: %s\n' "$@" >&2; exit 1; } +while getopts 'ih' o; do case "$o" in + i) iflag=1 ;; + h) help; exit ;; + *) err "invalid option -- '$OPTARG'" ;; +esac done +shift $((OPTIND - 1)) + +[ "$#" -lt 1 ] && help >&2 && exit 1 +filter="$1"; shift + +evaluate() { + while IFS= read -r line; do + escaped_line="$(printf "%s\n" "$line" | sed "s|\"|\\\\\\\\\"|")" + cmd="$(printf "%s\n" "$filter" | sed "s|{}|\"$escaped_line\"|")" + eval "$cmd" && printf "%s\n" "$line" + done +} + +if [ "$iflag" = 1 ]; then + for file in "$@"; do + [ -z "$1" ] && err "option -i requires file argument and none were passed" + tmp="$(mktemp "/tmp/$file.tmp-filter.XXXXXX")" + evaluate < "$file" > "$tmp" + mv "$tmp" "$file" + done + exit +fi + +if [ -n "$1" ]; then + evaluate < "$@" +else + evaluate +fi + diff --git a/.local/bin/fm b/.local/bin/fm new file mode 100755 index 0000000..2f4fbb8 --- /dev/null +++ b/.local/bin/fm @@ -0,0 +1,22 @@ +#!/bin/sh + +# fzf-man: fuzzy search manual pages + +if [ "$OPENFLAG" = 0 ]; then + input="$*"; page="${input%%)*}"; + name="${page%%[ (]*}"; section="${page#*(}" + if [ "$name" = "$section" ]; then + man "$name" + else + man "$section" "$name" + fi; exit +fi + +mkdir -pv "${XDG_DATA_HOME:=$HOME/.local/share}/fzf" +export FZF_HIST="${XDG_DATA_HOME:=$HOME/.local/share}/fzf/manual_history" + +apropos -l "${@:-.}" | fzf --history="$FZF_HIST" --prompt="man: " \ + --preview='MANWIDTH=$FZF_PREVIEW_COLUMNS OPENFLAG=0 fm {}' \ + --preview-window="hidden" --tiebreak="begin" \ + --bind 'ctrl-v:toggle-preview,ctrl-space:toggle-preview' \ + --bind 'enter:execute(echo {1} >> "$FZF_HIST"; OPENFLAG=0 fm {})' diff --git a/.local/bin/fmd b/.local/bin/fmd new file mode 100755 index 0000000..0139d77 --- /dev/null +++ b/.local/bin/fmd @@ -0,0 +1,26 @@ +#!/bin/sh + +# fzf-media: fuzzy search media files +# Useful when you want to look through a list of video without having to +# bother with their individual supplementary files like subtitles. + +export PREVIEW="${PREVIEW:-"cat \"\$(dirname {})/.description/\${\$(basename {})%.*}.txt\" 2>/dev/null || preview {}"}" + +find "$@" -type f \ + ! -path '*/.*' \ + ! -name '*.srt' \ + ! -name '*.vtt' \ + ! -name '*.description' \ + ! -wholename '.description/*' \ + ! -name '*.info.json' \ + ! -name '*.live_chat.json' \ + ! -name '*.yt*' | + sort | + fzf --multi --reverse \ + --history="${FZF_HIST:=$HOME/.local/share/fzf/media_history}" \ + --header="${FZF_HEADER:-Browse Media Files}" --header-first \ + --preview="$PREVIEW" --preview-window=hidden \ + --bind 'alt-C:execute( ffbrowser "$(mediainfo --inform="General;%Comment%" {})" )' \ + --bind 'ctrl-o:execute(append-to-history {q} "$FZF_HIST"; ${OPENER:-xdg-open} {})' \ + --bind "alt-3:change-preview($PREVIEW)" \ + --bind 'alt-#:execute($PREVIEW | less)' diff --git a/.local/bin/fpm b/.local/bin/fpm new file mode 100755 index 0000000..8da3d35 --- /dev/null +++ b/.local/bin/fpm @@ -0,0 +1,148 @@ +#!/bin/sh + +help() { echo "fzf-pm - fzf package manager + +USAGE: + fzf-pkgs [OPTION]... [QUERY] + +OPTIONS: + -g list global [all] packages + -l list local [instllaed] packages (default) + -i select and install packages (implies -g) + -u select and uninstall packages (implies -l) + -v show verbose output + -h show this help message + + (for Arch linux only) + -a AUR_HELPER specify command for AUR helper + + (special options) + -s PACKAGE print package info + -p print package manager + + Note: passing global (-g) or local (-l) pkg list will cancel + any install (-i) or uninstall (-u) operations started previously. + +ENVIRONMENT VARIABLES: + AUR_HELPER set an AUR helper command for Arch linux + +Following package managers are supported: + apt, pkg, pacman and any pacman compatible AUR helper + +QUERY is mandatory when using an AUR Helper" ;} + +while getopts 's:gliuha:p' o; do case "$o" in + s) sflag=0; pkg="$OPTARG" ;; + g) operation=""; opmsg=""; list_all=0 ;; + l) operation=""; opmsg=""; list_all=1 ;; + i) operation="install_pkgs"; opmsg="to Install"; list_all=0 ;; + u) operation="uninstall_pkgs"; opmsg="to Uninstall"; list_all=1 ;; + h) help; exit ;; + a) export AUR_HELPER="$OPTARG" ;; + p) pflag=0 ;; + *) printf "fzf-pkgs: invalid option -- '%s'" "$OPTARG"; exit 1 ;; +esac done +shift $((OPTIND - 1)) + +if command -v apt-get >> /dev/null; then + alias pkg_sort='sed -e "s/ - / => /"' + + if [ "$list_all" = 0 ]; then + export pkg_info='apt-cache show' + alias list_pkgs='apt-cache search .' + alias search_pkg='apt-cache search' + else + export DPKG_COLOR='always' + export pkg_info='dpkg-query --status' + format='${Package} - ${Description}\n' + alias list_pkgs='dpkg-query --show --showformat "$format"' + alias search_pkg='dpkg-query --show --showformat "$format" | grep' + fi + + if command -v pkg >> /dev/null; then + export PKGMAN="pkg" + alias install_pkgs='pkg install' + alias uninstall_pkgs='pkg uninstall' + else + export PKGMAN="apt" + alias install_pkgs='sudo apt-get install' + alias uninstall_pkgs='sudo apt-get remove' + fi + +elif command -v pacman >> /dev/null; then + alias pkg_sort='sed -e "N;s/\n\s*/ => /"' + + if [ -n "$AUR_HELPER" ]; then + export PKGMAN="$AUR_HELPER" + if command -v "$PKGMAN" >/dev/null; then + alias install_pkgs='$PKGMAN -S' + alias uninstall_pkgs='$PKGMAN -Rns' + else + echo "fzf-pkgs: AUR Helper '$PKGMAN' command not found" >&2 && + exit 1 + fi + else + export PKGMAN='pacman' + alias install_pkgs='sudo $PKGMAN -S' + alias uninstall_pkgs='sudo $PKGMAN -Rns' + fi + + if [ "$list_all" = 0 ]; then + export pkg_info="$PKGMAN --color=always -Si" + alias list_pkgs='$PKGMAN --color=always -Ss' + alias search_pkg='$PKGMAN --color=always -Ss' + else + export pkg_info="$PKGMAN --color=always -Qi" + alias list_pkgs='$PKGMAN --color=always -Qs' + alias search_pkg='$PKGMAN --color=always -Qs' + fi + +else + echo "fzf-pkgs: package manager not found" >&2 + exit 1 +fi + +if [ "$pflag" = 0 ]; then + printf "%s\n" "$PKGMAN" + exit +elif [ "$sflag" = 0 ]; then + printf "$ %s '%s'\n" "$pkg_info" "$pkg" + $pkg_info $pkg + exit +fi + +query="$1" +if [ -n "$AUR_HELPER" ] && [ -z "$query" ] && [ "$list_all" = 0 ]; then + echo "fzf-pkgs: providing QUERY is mandatory when using an AUR Helper" + exit 1 + # printf "query: "; read -r query + # [ -z "$query" ] && exit 1 +fi + +if [ -n "$query" ]; then + prompt="searching '$query' " + get_pkgs() { search_pkg "$query"; } +else + get_pkgs() { list_pkgs; } +fi + +[ -z "$FZF_HIST_DIR" ] && export FZF_HIST_DIR="$HOME/.local/share/fzf" +fzff() { + preview=' + echo "selected packages:"; + printf "\t%s\n" {+1} | tr " " "\n" + echo + eval "$pkg_info 2>/dev/null" {1} + ' + fzf --ansi --multi \ + --history="${FZF_HIST_DIR:-$HOME/.local/share}/package_history" \ + --header="Select packages $opmsg" --header-first --prompt="$prompt> " \ + --preview="$preview" --preview-window="hidden" --tiebreak='begin' \ + --bind 'ctrl-v:toggle-preview,ctrl-space:toggle-preview' +} + +pkgs="$(get_pkgs | pkg_sort | fzff | cut -d' ' -f1 | tr '\n' ' ')" +[ -n "$pkgs" ] || exit 2 +echo "$pkgs" +[ -n "$operation" ] && eval $operation $pkgs + diff --git a/.local/bin/fsend b/.local/bin/fsend new file mode 100755 index 0000000..f75739d --- /dev/null +++ b/.local/bin/fsend @@ -0,0 +1,47 @@ +#!/bin/sh + +content="${1:-$(xprint | fzf -m --header "Select clipboard lines to send")}" || exit +host="${2:-$(sed '/^Host \(.*\)/!d; s//\1/' ~/.ssh/config | fzf --header "Send to?")}" || exit +sshadd "$(find ~/.ssh -name "${host}_id_*" | head -1)" +[ -z "$NOTIFY" ] && command -V notify-send >/dev/null && NOTIFY=1 + +notify() { + [ "$NOTIFY" = 1 ] && notify-send -r 8529 "$@" + printf "%s\n" "$@" +} + +transferto() { + notify "Transfering files to $host:$1/" "$content" + rsync -PLru --progress "$content" "$host:$1/" +} + +if [ -e "$content" ]; then + case "$content" in + *.txt|*.pdf) transferto "Documents" ;; + *) + case "$(file --brief --mime-type "$content")" in + text/*) transferto "Documents" ;; + image/*) transferto "Pictures" ;; + audio/*) transferto "Music" ;; + video/*) transferto "Videos" ;; + *) transferto "Downloads" ;; + esac + ;; + esac + +else + case "$content" in + http*) notify "Opening link in $host" "$content" + ssh "$host" "xdg-open \"$content\"" ;; + *) notify "Copying in $host's clipboard" "$content" + ssh "$host" "termux-clipboard-set \"$content\"" ;; + esac +fi + +if [ $? = 0 ]; then + notify " Done (fzf-send)" +else + notify " ❌ Errors Occured (fzf-send)" + printf "\n%s" "Press Enter to continue..." + read -r +fi diff --git a/.local/bin/fw b/.local/bin/fw new file mode 100755 index 0000000..ada20e8 --- /dev/null +++ b/.local/bin/fw @@ -0,0 +1,10 @@ +#!/bin/sh + +export FZF_HIST="$HOME/.local/share/fzf/wiki_history" +export FZF_HEADER="Search local wiki files" +export FZF_DEFAULT_OPTS="$FZF_DEFAULT_OPTS --delimiter='/' --with-nth=-1" +fmd \ + /mnt/storage/Media/Tech/ \ + /mnt/storage/Library \ + /usr/share/doc/arch-wiki/html/en \ + "$@" ! -name '*.css' diff --git a/.local/bin/help b/.local/bin/help new file mode 100755 index 0000000..046b1cc --- /dev/null +++ b/.local/bin/help @@ -0,0 +1,99 @@ +#!/bin/sh + +help() { echo "help - get help for shell commands or programs + +USAGE: + help [OPTION...] <QUERY> + +OPTIONS: + -a show all available help + -h show this help message + "; } + +while getopts 'avh' o; do case "$o" in + a) aflag=0;; + h) help; exit ;; + *) printf "help: invalid option -- '%s'" "$OPTARG" ;; +esac done +shift $((OPTIND - 1)) + +[ "$#" -lt 1 ] && help >&2 && exit 2 + + +############################################################## +### H E L P F U N C T I O N S I N O R D E R ### +############################################################## + +man_query() { + man -w "$query" >/dev/null 2>&1 || return 2 + man -a "$query" +} + +info_query() { + # if command -v info + [ -n "$(info --where "$query")" ] || return 2 + info --vi-keys --all "$query" +} + +show_script() { + file="$(which "$query" 2>/dev/null)" || return 2 + "${PAGER:-less}" "$file" +} + +cmd_help() { + if content="$($query -h 2>/dev/null)"; then + printf "$ %s -h" "$query" + elif content="$($query --help 2>/dev/null)"; then + printf "$ %s --help" "$query" + else + return 2 + fi + printf '\n%s\n' "$content" | "${PAGER:-less}" -X + echo +} + +tldr_query() { + content="$(tldr --color=always "$query" 2>/dev/null)" || return 2 + printf "\n$ tldr '%s'\n%s\n\n" "$query" "$content" | "${PAGER:-less}" -X +} + +pkg_info() { + if command -v pacman >/dev/null; then + cmd="$ pacman -Si $query" + info="$(pacman -Si "$query" 2>/dev/null)" || return 2 + elif command -v apt >/dev/null; then + cmd="$ apt show $query" + info="$(apt show "$query" 2>/dev/null)" || return 2 + elif command -v pkg >/dev/null; then + cmd="$ pkg info $query" + info="$(pkg info "$query" 2>/dev/null)" || return 2 + else + return + fi + [ -z "$info" ] && return 2 + printf "\n%s\n%s\n\n" "$cmd" "$info" | "${PAGER:-less}" -X +} + +########################################################## +### E N D O F H E L P F U N C T I O N S ### +########################################################## + + +help_funcs="$(sed -ne "/^### H E L P/,/^### E N D/ s/^\([a-zA-Z0-9_]\+\)\(\).*/\1/p" "$0")" +main() { + if [ "$aflag" = 0 ]; then + eval "$help_funcs" + else + eval "$(echo "$help_funcs" | sed -z 's/\n/||/g' | sed 's/||$//')" + fi +} + +query="$*" +[ -f "$query" ] && { "${PAGER:-less}" "$query"; exit 0; } +[ -d "$query" ] && + { ls -AlFh --color --group-directories-first -- "$query"; exit 0; } + +command -V "$query" 2>/dev/null && { echo; export HELP_FOUND=1; } + +main || [ "$HELP_FOUND" = 1 ] || + { echo "No help found for '$query'" >&2; exit 2; } diff --git a/.local/bin/launch-gtypist b/.local/bin/launch-gtypist new file mode 100755 index 0000000..c5f452f --- /dev/null +++ b/.local/bin/launch-gtypist @@ -0,0 +1,101 @@ +#!/bin/sh + + +help() { + echo "launch-gtypist - launch gtypist in fullscreen + +USAGE: + launch-gtypist [OPTION]... + +OPTIONS: + -l LESSON start gtypist lesson + -f FILE load lesson from a file + -e % max error percentage + -v verbose output + -h show this help message + +LESSON can optionally be followed by the exercise number seprated by a colon. +Example - Q2:3, which means 3rd execercise of lesson Q2. +If LESSON is provided through the command line along with a file with -f +option then the file will ignored" +} + + +while getopts 'l:f:e:vh' o; do case "$o" in + l) use_file=1; current="$OPTARG" ;; + f) use_file=0; file="$OPTARG" ;; + e) export GTYPIST_OPTS="$GTYPIST_OPTS --max-error=$OPTARG" ;; + v) vflag=0 ;; + h) help; exit ;; + *) echo "launch-gtypist: invalid option -- '${OPTARG}'" + echo 'Try `launch-gtypist -h` for more information.' >&2; exit 1 ;; +esac done +shift $((OPTIND - 1)) + +msg() { [ "$vflag" = 0 ] && printf ':: %s\n' "$@" >&2; true; } +notify() { + [ -n "$DISPLAY" ] && notify-send 'launch-gtypist' "$@" + printf '%s\n' "$@" +} + +if [ "$use_file" = 0 ]; then + msg "Getting lesson from file: $file" + current="$(sed -En 's/^gtypist lesson\s*-\s*(.*)$/\1/p' "$file")" || + exit 1 + [ -z "$current" ] && + printf 'launch-gtypist: current gtypist lesson not found in:\n\t%s\n' \ + "$file" && exit 1 +fi + +[ -n "$1" ] && current="$1" && shift +[ "${current#*:}" != "$current" ] && lesson="${current%:*}" && + exercise="${current##*:}" || lesson="$current" +[ -n "$lesson" ] && { + msg "Gtypist lesson name: $lesson" + export GTYPIST_OPTS="$GTYPIST_OPTS --start-label=$lesson" +} + +tmuxx() { [ -z "$TMUX" ] && return 1; tmux "$@"; } + + +shift_exercise() { + msg "Shifting to exercise $exercise" + sleep 1 + + keys() { + if [ -n "$TMUX" ]; then + for key in "$@"; do + tmux send-keys -t gtypist "$key"; + done + else + xdotool key --clearmodifiers --delay 100 "$@" + fi + } + + for i in $(seq "$((exercise-1))"); do + if [ "$i" -gt 1 ]; then + keys Escape n + else + keys space space space space space Escape Escape n + fi + done +} + + +msg "Switcing to default keymap" +# kmonad-manage stop +remap -x + +msg "Waiting for terminal columns to get more than 100..." +while [ "$(tput cols)" -lt 100 ]; do sleep 0.5; done +tmuxx rename-window gtypist +[ -n "$exercise" ] && shift_exercise & +msg " >>> Gtypist started." +msg " gtypist $GTYPIST_OPTS $*" +gtypist $GTYPIST_OPTS $@ +msg " <<< Gtypist exited." +tmuxx set-window-option automatic-rename on + +msg "Switcing to user keymap" +# kmonad-manage start +remap diff --git a/.local/bin/lessopen.sh b/.local/bin/lessopen.sh new file mode 100755 index 0000000..df4a58e --- /dev/null +++ b/.local/bin/lessopen.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +[ -d "$1" ] && { tree -CL 3 "$1"; exit; } + +if command -V highlight >/dev/null; then + highlight --force --out-format=ansi -- "$1" +else + cat "$1" +fi diff --git a/.local/bin/loop b/.local/bin/loop new file mode 100755 index 0000000..d3dccc7 --- /dev/null +++ b/.local/bin/loop @@ -0,0 +1,45 @@ +#!/bin/sh + +help() { + echo "loop - execute command in loop + +USAGE: + loop [OPTION]... <COMMAND> + +OPTIONS: + -n INTERVAL sleep for given INTERVAL time between loops + all arguments of \`sleep\` command are valid + -c COUNT maximum count of loops (default: 1000) + -s clear screen for every execution + -q quiet, redirect output to /dev/null + -h show this help message + +ENVIRONMENT VARIABLES: + LOOP_INTERVAL set INTERVAL time + MAX_LOOP_COUNT set loop COUNT" +} + +err() { printf 'loop: %s\n' "$@" >&2; exit 1; } + +while getopts 'sc:n:qh' o; do case "$o" in + s) cflag=1 ;; + n) export LOOP_INTERVAL="$OPTARG" ;; + c) export MAX_LOOP_COUNT="$OPTARG" ;; + q) qflag=1 ;; + h) help; exit ;; + *) err "invalid option -- $OPTARG" ;; +esac done +shift $((OPTIND - 1)) + +[ "$#" -lt 1 ] && err "no COMMAND given" +cmds="$*" +max_count="${MAX_LOOP_COUNT:-1000}" +[ -n "$LOOP_INTERVAL" ] && cmds="$cmds; sleep '$LOOP_INTERVAL'" +[ "$cflag" = 1 ] && cmds="clear; $cmds" +[ "$qflag" = 1 ] && cmds="$cmds >/dev/null" + +for count in $(seq "$max_count"); do + eval "$cmds" || break +done + +[ "$count" -ge "$max_count" ] && err "reached max loop COUNT: $max_count" diff --git a/.local/bin/lsinputs b/.local/bin/lsinputs new file mode 100755 index 0000000..8bb091f --- /dev/null +++ b/.local/bin/lsinputs @@ -0,0 +1,12 @@ +#!/bin/bash + +for sysdevpath in $(find /sys/bus/usb/devices/usb*/ -name dev); do + ( + syspath="${sysdevpath%/dev}" + devname="$(udevadm info -q name -p $syspath)" + [[ "$devname" == "bus/"* ]] && exit + eval "$(udevadm info -q property --export -p $syspath)" + [[ -z "$ID_SERIAL" ]] && exit + echo "/dev/$devname - $ID_SERIAL" + ) +done diff --git a/.local/bin/mnt b/.local/bin/mnt new file mode 100755 index 0000000..8470667 --- /dev/null +++ b/.local/bin/mnt @@ -0,0 +1,39 @@ +#!/bin/sh + +sudo mkdir -p "${MOUNTPATH:=/run/media/$USER}" +sudo chown "$USER:$USER" "$MOUNTPATH" + +makepath() { + [ -d "$path" ] && { rmdir "$path" || exit; } + mkdir -p "$path" +} + +case "$1" in + + mtp:*) + path="$MOUNTPATH/${1#mtp:}" + makepath + simple-mtpfs "$path" + ;; + + *:|*:/*) + path="$MOUNTPATH/${1%%:*}" + makepath + if grep -q "^\[${1%:}\]$" "${XDG_CONFIG_HOME:-$HOME/.config}/rclone/rclone.conf"; then + rclone mount --daemon "$1" "$path" + else + sshfs "$1" "$path" + fi + ;; + + *) + if sudo cryptsetup isLuks "$1"; then + uuid=$(sudo cryptsetup luksUUID "$1" | tr -d -) + test -b /dev/disk/by-id/dm-uuid-*$uuid* && exit + sudo cryptsetup open "$1" "crypt-$uuid" + udisksctl mount -b "/dev/mapper/crypt-$uuid" + exit + fi + udisksctl mount -b "$1" + ;; +esac diff --git a/.local/bin/open b/.local/bin/open new file mode 100755 index 0000000..a996105 --- /dev/null +++ b/.local/bin/open @@ -0,0 +1,48 @@ +#!/bin/sh + +[ -z "$1" ] && echo "USAGE: open <FILE>" >&2 && exit 1 + +for file in "$@"; do + case "$file" in + + *.pdf|*.djvu|*.epub) setsid -f zathura "$file" ;; + *.png|*.jpg|*.jpeg|*.webp) setsid -f nsxiv "$file" ;; + *.gif|*.mkv|*.mp3|*.mp4|*.webm|*.ogg) ${PLAYER:-mpv --sub-auto=fuzzy} "$file" ;; + *.html) ${BROWSER:-w3m} "$file" ;; + *.pl.txt) fpl "$file" ;; + *.txt|*.description) ${PAGER:-less} "$file" ;; + *.md) glow --pager "$file" ;; + *.css|*.json|*.ipynb|*.vim|*.lua|*.iso|*.zip) LESSOPEN="|preview %s" less -r "$file" ;; + *.srt) fzf-subtitles -o "$file" ;; + *.dig) setsid -f digital "$file" ;; + *.doc|*.docx|*.ppt|*.pptx) setsid -f libreoffice "$file" ;; + *.sc|*.xls|*.xlsx) sc-im "$file" ;; + *.sim1) simulide "$file" ;; + *.xz) ${EDITOR:-nvim} "$file" ;; + + *) + filetype="$(file --dereference --brief --mime-type "$file")" + case "$filetype" in + inode/directory) ${FILES:-lf} "$file" ; exit ;; + text/html*) ${BROWSER:-w3m} "$file" ;; + *pdf|*djvu|*epub+zip|*oxps|*fictionbook) setsid -f zathura "$file" ;; + text/*|*json|*zip|*zstd) "${EDITOR:-nvim}" "$file" ;; + application/vnd.openxmlformats-officedocument.*) setsid -f libreoffice "$file" ;; + application/sc) sc-im "$file" ;; + application/x-executable) "$file" ;; + image/*) setsid -f nsxiv "$file" ;; + video/*|audio/*) ${PLAYER:- mpv --sub-auto=fuzzy} "$file" ;; + *) + xdg-open "$file" || exit + [ -n "$DISPLAY" ] && notify-send "⚠️ open: unknown filetype" "$filetype" + echo "open: unknown filetype: $filetype" >&2 + ;; + esac + ;; + + esac + + file="$(realpath "$file")" + sed -i "\|^$file$|d" "${XDG_DATA_HOME:-$HOME/.local/share}/openhist" + echo "$file" >> "${XDG_DATA_HOME:-$HOME/.local/share}/openhist" +done diff --git a/.local/bin/preview b/.local/bin/preview new file mode 100755 index 0000000..f0cedb0 --- /dev/null +++ b/.local/bin/preview @@ -0,0 +1,59 @@ +#!/bin/sh + +if [ -d "$1" ]; then + if [ -x /bin/eza ] || [ -x /usr/bin/eza ]; then + eza -alhF --group-directories-first --color=always --icons -- "$1" + else + ls -lhAF --group-directories-first --color -- "$1" + fi + readme="$(find "$1" -maxdepth 1 -name "README.*" | head -1)" + [ -n "$readme" ] && preview "$readme" + exit +fi + +alias highlight='highlight --out-format=ansi' + +case "$1" in + '') echo "preview: file name required" >&2; exit 1 ;; + *.html) w3m -dump "$1" ;; + *.md) glow -s dark --width="${FZF_PREVIEW_COLUMNS:-"$(tput cols)"}" "$1" ;; + # *.vim) highlight --syntax=vim --replace-tabs=2 -- "$1" ;; + *.js|*.vim|*.lua) highlight -- "$1" ;; + *.txt|*.description|*.srt) cat -- "$1" ;; + *.png|*.jpg|*.jpeg|*.webp|*.mp3|*.ogg|*.mp4|*.mkv|*.webm) mediainfo -- "$1" ;; + *.info.json) jq -C . "$1" ;; + *.json|*.ipynb) highlight --syntax=json -- "$1" ;; + *.tgz|*.tar.gz) tar tzf "$1" ;; + *.tar.bz2|*.tbz2) tar tjf "$1" ;; + *.tar.txz|*.txz) xz --list "$1" ;; + *.tar) tar tf "$1" ;; + *.zip|*.jar|*.war|*.ear|*.oxt) unzip -l "$1" ;; + *.rar) unrar l "$1" ;; + *.7z) 7z l "$1" ;; + *.zst) zstdcat "$1" ;; + *.[1-8]) man "$1" | col -b ;; + *.o) nm "$1" ;; + *.torrent) transmission-show "$1" ;; + *.iso) iso-info --no-header -l "$1" ;; + *odt|*.ods|*.odp|*.sxw) odt2txt "$1" ;; + *.doc) catdoc "$1" ;; + *.docx) docx2txt "$1" - ;; + # *.csv) sed s/,/\\n/g "$1" ;; + + *) + filetype=$(file --dereference --brief --mime-type "$1") + case $filetype in + *html) w3m -dump "$1" ;; + text/markdown) glow -s dark -w "$(tput cols)" "$1" ;; + application/json) highlight --syntax=json --replace-tabs=2 -- "$1" ;; + text/*) highlight --force -- "$1" ;; + audio/*|video/*|image/*) mediainfo -- "$1" ;; + *xz) xz --list "$1" ;; + *zip|*tar*|*7z*|*bzip2) atool --list -- "$1" ;; + *opendocument*) odt2txt "$1" ;; + application/pgp-encrypted) gpg -d -- "$1" ;; + *) file -b "$1" ;; + esac + ;; + +esac diff --git a/.local/bin/search b/.local/bin/search new file mode 100755 index 0000000..d9c1a3d --- /dev/null +++ b/.local/bin/search @@ -0,0 +1,62 @@ +#!/bin/sh + +help() { echo "search - search tool for unix users + +USAGE: + search [OPTION]... <QUERY> + +OPTIONS: + -h show this help message"; } + +err() { printf 'search: %s\n' "$@" >&2; exit 1; } +while getopts 'h' o; do case "$o" in + h) help >&2; exit ;; + *) err "invalid option -- '$OPTARG'" ;; +esac done +shift $((OPTIND - 1)) + +if [ "$PREVIEWFLAG" = 0 ]; then + [ -z "$INDEX" ] && export INDEX="$(echo "$*" | cut -d: -f1)" + [ -z "$LINE" ] && export LINE="$(echo "$*" | cut -d: -f2-)" + + case "$INDEX" in + wiki) "${FILE_HANDLER:-preview}" "/usr/share/doc/$LINE" ;; + docs) "${FILE_HANDLER:-preview}" "$HOME/.local/share/Zeal/Zeal/docsets/$LINE" ;; + media) "${FILE_HANDLER:-preview}" "/run/media/$USER/Storage/Media/$LINE" ;; + library) "${FILE_HANDLER:-preview}" "/run/media/$USER/Storage/Library/$LINE" ;; + tldr) tldr --color=always "$LINE" ;; + word) sdcv-dict "$LINE" ;; + man) + page="${LINE%%)*}"; name="${page%%[ (]*}"; section="${page#*(}" + if [ "$name" != "$section" ]; then + man "$section" "$name" + else + man "$name" + fi + ;; + pacman) pacman --color=always -Si "${LINE%% *}" ;; + esac + exit +fi + +if [ "$OPENFLAG" = 0 ]; then + export INDEX="$(echo "$*" | cut -d: -f1)" + export LINE="$(echo "$*" | cut -d: -f2-)" + export FILE_HANDLER="open" + + case "$INDEX" in + wiki|docs|web-docs|media|library|man) PREVIEWFLAG=0 search ;; + *) PREVIEWFLAG=0 search | less -r ;; + esac + exit +fi + +[ "$#" -lt 1 ] && help >&2 && exit 1 +FZF_HIST="$HOME/.local/share/fzf/search_history" + +cd "${SEARCHDB:-$HOME/.cache/search}" || exit +mkdir -pv ~/.local/share/fzf +grep -Rsi --color=always "$@" | fzf --ansi \ + --history="$FZF_HIST" \ + --preview="PREVIEWFLAG=0 search {}" \ + --bind 'enter:execute(echo {} >> $FZF_HIST; OPENFLAG=0 search {})' diff --git a/.local/bin/searchdb b/.local/bin/searchdb new file mode 100755 index 0000000..57e3fa8 --- /dev/null +++ b/.local/bin/searchdb @@ -0,0 +1,35 @@ +#!/bin/sh + +help() { + echo "searchdb - update local search database + +USAGE: + searchdb [OPTION]... + +OPTIONS: + -x clear all databases + -h show this help message" +} + +err() { printf 'searchdb: %s\n' "$@" >&2; exit 1; } +while getopts 'xh' o; do case "$o" in + x) rm -rf ~/.cache/search; exit ;; + h) help >&2; exit ;; + *) err "invalid option -- '$OPTARG'" ;; +esac done +shift $((OPTIND - 1)) + +rm -rf ~/.cache/search +export SEARCHDB="$HOME/.cache/search" +mkdir -p "$SEARCHDB" || exit +ln -sf /usr/share/dict/words "$SEARCHDB/word" + +tldr --list > "$SEARCHDB/tldr" +apropos . > "$SEARCHDB/man" +pacman -Ss | sed -e "N;s/\n\s*/ => /" > "$SEARCHDB/pacman" + +list() { find -L "$@" ! -wholename '*/.git*' -printf "%P\n"; } +list /usr/share/doc > "$SEARCHDB/wiki" +list ~/.local/share/Zeal/Zeal/docsets > "$SEARCHDB/docs" +list -L "/run/media/$USER/Storage/Media" > "$SEARCHDB/media" +list "/run/media/$USER/Storage/Library" > "$SEARCHDB/library" diff --git a/.local/bin/setbg b/.local/bin/setbg new file mode 100755 index 0000000..b636a37 --- /dev/null +++ b/.local/bin/setbg @@ -0,0 +1,18 @@ +--2024-10-23 16:26:25-- https://github.com/LukeSmithxyz/voidrice/blob/master/.local/bin/setbg +Loaded CA certificate '/etc/ssl/certs/ca-certificates.crt' +Resolving github.com (github.com)... 20.207.73.82 +Connecting to github.com (github.com)|20.207.73.82|:443... connected. +HTTP request sent, awaiting response... 200 OK +Length: unspecified [text/html] +Saving to: ‘setbg’ + + 0K .......... .......... .......... .......... .......... 3.47M + 50K .......... .......... .......... .......... .......... 9.00M + 100K .......... .......... .......... .......... .......... 10.7M + 150K .......... .......... .......... .......... .......... 10.7M + 200K .......... .......... .......... .......... .......... 10.9M + 250K .......... .......... .......... .......... .......... 11.2M + 300K .......... .......... .......... ....... 10.8M=0.04s + +2024-10-23 16:26:25 (8.07 MB/s) - ‘setbg’ saved [345695] + diff --git a/.local/bin/shortcuts b/.local/bin/shortcuts new file mode 100755 index 0000000..545799f --- /dev/null +++ b/.local/bin/shortcuts @@ -0,0 +1,35 @@ +#!/bin/sh + +config="${XDG_CONFIG_HOME:-$HOME/.config}" +bmdirs="$config/shell/bm-dirs" +bmfiles="$config/shell/bm-files" + +shell_shortcuts="$config/shell/shortcutrc" +zsh_named_dirs="$config/zsh/zshnameddirrc" +lf_shortcuts="$config/lf/shortcutrc" +vim_shortcuts="$config/nvim/shortcuts.vim" + +rm -f "$zsh_named_dirs" "$lf_shortcuts" "$vim_shortcuts" +printf "# vim: filetype=sh\n" > "$shell_shortcuts" + +eval "echo \"$(cat "$bmdirs")\"" | +awk -F'\t' " + !/^\s*#/ && !/^\s*$/ { + gsub(\"\\\s*#.*$\", \"\"); + printf(\"alias %s='cd %s && ls -A'\n\", \$1, \$2) >> \"$shell_shortcuts\" + printf(\"hash -d %s=%s\n\", \$1, \$2) >> \"$zsh_named_dirs\" + printf(\"map c%s :cd %s\n\", \$1, \$2) >> \"$lf_shortcuts\" + printf(\"cmap ;%s %s\n\", \$1, \$2) >> \"$vim_shortcuts\" + } + " + +eval "echo \"$(cat "$bmfiles")\"" | +awk -F'\t' " + !/^\s*#/ && !/^\s*$/ { + gsub(\"\\\s*#.*$\", \"\"); + printf(\"alias %s='\$EDITOR %s'\n\", \$1, \$2) >> \"$shell_shortcuts\" + printf(\"hash -d %s=%s\n\", \$1, \$2) >> \"$zsh_named_dirs\" + printf(\"map E%s $\$EDITOR %s\n\", \$1, \$2) >> \"$lf_shortcuts\" + printf(\"cmap ;%s %s\n\", \$1, \$2) >> \"$vim_shortcuts\" + } + " diff --git a/.local/bin/shorts/adbs b/.local/bin/shorts/adbs new file mode 100755 index 0000000..bca7733 --- /dev/null +++ b/.local/bin/shorts/adbs @@ -0,0 +1,3 @@ +#!/bin/sh + +adb -s "${ADB_DEVICE}" shell "$@" diff --git a/.local/bin/shorts/append-to-history b/.local/bin/shorts/append-to-history new file mode 100755 index 0000000..7d23dc8 --- /dev/null +++ b/.local/bin/shorts/append-to-history @@ -0,0 +1,5 @@ +#!/bin/sh + +[ -n "$1" ] || exit +sed -i "\|^${1}$|d" "${2}" +echo "$1" >> "$2" diff --git a/.local/bin/shorts/bs b/.local/bin/shorts/bs new file mode 100755 index 0000000..7e7ec0a --- /dev/null +++ b/.local/bin/shorts/bs @@ -0,0 +1,7 @@ +#!/bin/sh + +# build site + +cd "${SITE_BASE_DIR:-$HOME/Dev/sites/vikas.rocks}" || exit +rm -rf public/* +hugo diff --git a/.local/bin/shorts/conv b/.local/bin/shorts/conv new file mode 100755 index 0000000..92379e8 --- /dev/null +++ b/.local/bin/shorts/conv @@ -0,0 +1,10 @@ +#!/bin/sed -nf + +p +s/\([0-9]\+\)[0-9]\{3\}\([^A-Za-z0-9]\|$\)/\1K\2/gp +s/\([0-9]\+\)[0-9]\{3\}K\([^A-Za-z0-9]\|$\)/\1M\2/gp +s/\([0-9]\+\)[0-9]\{3\}M\([^A-Za-z0-9]\|$\)/\1G\2/gp +s/\([0-9]\+\)[0-9]\{3\}G\([^A-Za-z0-9]\|$\)/\1T\2/gp +s/\([0-9]\+\)[0-9]\{3\}T\([^A-Za-z0-9]\|$\)/\1P\2/gp +s/\([0-9]\+\)[0-9]\{3\}P\([^A-Za-z0-9]\|$\)/\1Z\2/gp +s/\([0-9]\+\)[0-9]\{3\}Z\([^A-Za-z0-9]\|$\)/\1Y\2/gp diff --git a/.local/bin/shorts/diffdirs b/.local/bin/shorts/diffdirs new file mode 100755 index 0000000..9585f9f --- /dev/null +++ b/.local/bin/shorts/diffdirs @@ -0,0 +1,6 @@ +#!/bin/sh + +tree --dirsfirst -aL 3 "$1" > "$PREFIX/tmp/dir1.tree.txt" +tree --dirsfirst -aL 3 "$2" > "$PREFIX/tmp/dir2.tree.txt" +nvim -d "$PREFIX/tmp/dir1.tree.txt" "$PREFIX/tmp/dir2.tree.txt" + diff --git a/.local/bin/shorts/font2svg b/.local/bin/shorts/font2svg new file mode 100755 index 0000000..539972d --- /dev/null +++ b/.local/bin/shorts/font2svg @@ -0,0 +1,3 @@ +#!/bin/sh + +fontforge -c "import fontforge; fontforge.open('$1').generate('${1%.*}.svg')" diff --git a/.local/bin/shorts/preview-bat b/.local/bin/shorts/preview-bat new file mode 100755 index 0000000..43d1532 --- /dev/null +++ b/.local/bin/shorts/preview-bat @@ -0,0 +1,3 @@ +#!/bin/sh + +bat --tabs=2 --style=plain --color=always "$@" diff --git a/.local/bin/shorts/preview-highlight b/.local/bin/shorts/preview-highlight new file mode 100755 index 0000000..0972538 --- /dev/null +++ b/.local/bin/shorts/preview-highlight @@ -0,0 +1,3 @@ +#!/bin/sh + +highlight --force --stdout --replace-tabs=2 --out-format=ansi "$@" diff --git a/.local/bin/shorts/refcitx b/.local/bin/shorts/refcitx new file mode 100755 index 0000000..e99fcd3 --- /dev/null +++ b/.local/bin/shorts/refcitx @@ -0,0 +1,6 @@ +#!/bin/sh + +fcitx +sleep 0.1 +remap + diff --git a/.local/bin/shorts/sc b/.local/bin/shorts/sc new file mode 100755 index 0000000..8760379 --- /dev/null +++ b/.local/bin/shorts/sc @@ -0,0 +1,3 @@ +#!/bin/sh + +sc-im "$@" diff --git a/.local/bin/shorts/scrcpy-k b/.local/bin/shorts/scrcpy-k new file mode 100755 index 0000000..139732b --- /dev/null +++ b/.local/bin/shorts/scrcpy-k @@ -0,0 +1,8 @@ +#!/bin/sh + +remap -x +adb connect blue:43896 +notify-send scrcpy-k "Starting scrcpy..." +scrcpy -K --no-playback +notify-send scrcpy-k "Connection closed..." +remap diff --git a/.local/bin/shorts/ssha b/.local/bin/shorts/ssha new file mode 100755 index 0000000..3cbf87c --- /dev/null +++ b/.local/bin/shorts/ssha @@ -0,0 +1,5 @@ +#!/bin/sh + +[ "$TERM" != "${TERM#st-256color}" ] && export TERM=xterm-256color +sshadd "$(find ~/.ssh -name "${1}_id_*" | head -1)" +ssh "$@" -t "tmux attach -t $USER || tmux new -s $USER" diff --git a/.local/bin/shorts/sync-server b/.local/bin/shorts/sync-server new file mode 100755 index 0000000..641db9c --- /dev/null +++ b/.local/bin/shorts/sync-server @@ -0,0 +1,12 @@ +#!/bin/sh + +sshadd "$HOME/.ssh/${1}_id_ed25519" +sync() { rsync -PRru --delete --exclude "*.git" "$@"; } + +sync \ + "${XDG_CONFIG_HOME:-$HOME/.config}/./vim/vimrc" \ + "${XDG_CONFIG_HOME:-$HOME/.config}/./tmux/tmux.conf" \ + "${XDG_CONFIG_HOME:-$HOME/.config}/./shell/aliasrc" \ + "${XDG_CONFIG_HOME:-$HOME/.config}/./shell/inputrc" \ + "${XDG_CONFIG_HOME:-$HOME/.config}/./shell/server.profile" \ + "${1}:.config" diff --git a/.local/bin/shorts/syncdrive b/.local/bin/shorts/syncdrive new file mode 100755 index 0000000..3d010cc --- /dev/null +++ b/.local/bin/shorts/syncdrive @@ -0,0 +1,3 @@ +#!/bin/sh + +rclone -v sync --delete-excluded --exclude=".git/**" ~/GDrive gdrive: diff --git a/.local/bin/shorts/synchs b/.local/bin/shorts/synchs new file mode 100755 index 0000000..244dd48 --- /dev/null +++ b/.local/bin/shorts/synchs @@ -0,0 +1,7 @@ +#!/bin/sh + +sync-server rpi + +# rsync -u ~/.config/lf/lfrc /tmp/lfrc +# sed -i '/set icons/d' /tmp/lfrc +# rsync -Pu /tmp/lfrc rpi:.config/lf/ diff --git a/.local/bin/shorts/synctab b/.local/bin/shorts/synctab new file mode 100755 index 0000000..1e44419 --- /dev/null +++ b/.local/bin/shorts/synctab @@ -0,0 +1,19 @@ +#!/bin/sh + +sshadd ~/.ssh/tab_id_ed25519 +sync() { rsync -Pru --delete --exclude "*.git" "$@"; } + +sync ~/GDrive/ tab:GDrive/ +sync "${XDG_VIDEOS_DIR:-$HOME/Videos}" tab:Videos/ + +sync -R \ + "${XDG_DOCUMENTS_DIR:-$HOME/Documents}/./allreader" \ + "${XDG_DOCUMENTS_DIR:-$HOME/Documents}/./latex" \ + "${XDG_DOCUMENTS_DIR:-$HOME/Documents}/./Notes/bookmarks.txt" \ + tab:Documents/ + +sync \ + "${XDG_MUSIC_DIR:-$HOME/Music}/Piano" \ + "${XDG_MUSIC_DIR:-$HOME/Music}/Devotional" \ + tab:Music/ + diff --git a/.local/bin/shorts/xdg-terminal-exec b/.local/bin/shorts/xdg-terminal-exec new file mode 100755 index 0000000..43ed65d --- /dev/null +++ b/.local/bin/shorts/xdg-terminal-exec @@ -0,0 +1,3 @@ +#!/bin/sh + +st -e "$@" diff --git a/.local/bin/shorts/xprint b/.local/bin/shorts/xprint new file mode 100755 index 0000000..12156f2 --- /dev/null +++ b/.local/bin/shorts/xprint @@ -0,0 +1,8 @@ +#!/bin/sh + +[ -n "$TERMUX_VERSION" ] && { termux-clipboard-get; exit; } + +xclip -out -selection clipboard 2>/dev/null || +xclip -out -selection secondry 2>/dev/null || +xclip -out -selection primary 2>/dev/null || +notify-send "Selection and clipboard is empty" diff --git a/.local/bin/sshadd b/.local/bin/sshadd new file mode 100755 index 0000000..6fb3b18 --- /dev/null +++ b/.local/bin/sshadd @@ -0,0 +1,17 @@ +#!/bin/sh + +[ -z "$SSH_AUTH_SOCK" ] && export SSH_AUTH_SOCK="$HOME/.ssh/ssh_auth_sock" +msg=$(ssh-add -L 2>&1) +if [ "$msg" = 'Could not open a connection to authentication agent.' ] || + [ "$msg" = 'Error connecting to agent: No such file or directory' ] || + [ "$msg" = 'Error connecting to agent: Connection refused' ]; then + rm -f "${SSH_AUTH_SOCK}" + ssh-agent -a "${SSH_AUTH_SOCK}" > /dev/null +fi + +private_key="$1" +content="$(cat "$1.pub")" +if [ "$msg" = "The agent has no identities." ] || + [ "${msg#*$content}" = "$msg" ]; then + ssh-add "$private_key" +fi diff --git a/.local/bin/statusbar/cpu_usage b/.local/bin/statusbar/cpu_usage new file mode 100755 index 0000000..be729e2 --- /dev/null +++ b/.local/bin/statusbar/cpu_usage @@ -0,0 +1,55 @@ +#!/usr/bin/perl +# +# Copyright 2014 Pierre Mavro <deimos@deimos.fr> +# Copyright 2014 Vivien Didelot <vivien@didelot.org> +# Copyright 2014 Andreas Guldstrand <andreas.guldstrand@gmail.com> +# +# Licensed under the terms of the GNU GPL v3, or any later version. + +use strict; +use warnings; +use utf8; +use Getopt::Long; + +# default values +my $t_warn = 50; +my $t_crit = 80; +my $cpu_usage = -1; + +sub help { + print "Usage: cpu_usage [-w <warning>] [-c <critical>]\n"; + print "-w <percent>: warning threshold to become yellow\n"; + print "-c <percent>: critical threshold to become red\n"; + exit 0; +} + +GetOptions("help|h" => \&help, + "w=i" => \$t_warn, + "c=i" => \$t_crit); + +# Get CPU usage +$ENV{LC_ALL}="en_US"; # if mpstat is not run under en_US locale, things may break, so make sure it is +open (MPSTAT, 'mpstat 1 1 |') or die; +while (<MPSTAT>) { + if (/^.*\s+(\d+\.\d+)\s+$/) { + $cpu_usage = 100 - $1; # 100% - %idle + last; + } +} +close(MPSTAT); + +$cpu_usage eq -1 and die 'Can\'t find CPU information'; + +# Print short_text, full_text +printf "%.1f%%\n", $cpu_usage; +# printf "%.2f%%\n", $cpu_usage; + +# # Print color, if needed +# if ($cpu_usage >= $t_crit) { +# print "#FF0000\n"; +# exit 33; +# } elsif ($cpu_usage >= $t_warn) { +# print "#FFFC00\n"; +# } + +exit 0; diff --git a/.local/bin/statusbar/i3bandwidth b/.local/bin/statusbar/i3bandwidth new file mode 100755 index 0000000..8877d28 --- /dev/null +++ b/.local/bin/statusbar/i3bandwidth @@ -0,0 +1,105 @@ +#!/usr/bin/bash +# Copyright (C) 2012 Stefan Breunig <stefan+measure-net-speed@mathphys.fsk.uni-heidelberg.de> +# Copyright (C) 2014 kaueraal +# Copyright (C) 2015 Thiago Perrotta <perrotta dot thiago at poli dot ufrj dot br> + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +case "$BLOCK_BUTTON" in + 2) $TERMINAL -e nvim "$0" ;; +esac + +# Use the provided interface, otherwise the device used for the default route. +if [[ -n $BLOCK_INSTANCE ]]; then + INTERFACE=$BLOCK_INSTANCE +else + INTERFACE=$(ip route | awk '/^default/ { print $5 ; exit }') +fi + +[ -z "$INTERFACE" ] && echo && exit + +# Issue #36 compliant. +if ! [ -e "/sys/class/net/${INTERFACE}/operstate" ] || ! [ "$(cat "/sys/class/net/${INTERFACE}/operstate")" = "up" ] +then + # echo "$INTERFACE down" + # echo "$INTERFACE down" + # echo "#FF0000" + echo " " + exit 0 +fi + +# path to store the old results in +path="/dev/shm/$(basename "$0")-${INTERFACE}" + +# grabbing data for each adapter. +read -r rx < "/sys/class/net/${INTERFACE}/statistics/rx_bytes" +read -r tx < "/sys/class/net/${INTERFACE}/statistics/tx_bytes" + +# get time +time=$(date +%s) + +# write current data if file does not exist. Do not exit, this will cause +# problems if this file is sourced instead of executed as another process. +if ! [[ -f "${path}" ]]; then + echo "${time} ${rx} ${tx}" > "${path}" + chmod 0666 "${path}" +fi + +# read previous state and update data storage +read -r old < "${path}" +echo "${time} ${rx} ${tx}" > "${path}" + +# parse old data and calc time passed +old=(${old//;/ }) +time_diff=$(( time - old[0] )) + +# sanity check: has a positive amount of time passed +[[ "${time_diff}" -gt 0 ]] || { echo " "; exit; } + +# calc bytes transferred, and their rate in byte/s +rx_diff=$(( rx - old[1] )) +tx_diff=$(( tx - old[2] )) +rx_rate=$(( rx_diff / time_diff )) +tx_rate=$(( tx_diff / time_diff )) + +# shift by 10 bytes to get KiB/s. If the value is larger than +# 1024^2 = 1048576, then display MiB/s instead + +# incoming +rx_kib=$(( rx_rate >> 10 )) +if [ "$rx_kib" -gt 1 ]; then + # echo -n "📥 " + echo -n "↓ " + if [[ "$rx_rate" -gt 1048576 ]]; then + printf '%sM' "$(echo "scale=1; $rx_kib / 1024" | bc)" + else + echo -n "${rx_kib}K" + fi +fi + +# outgoing +tx_kib=$(( tx_rate >> 10 )) +if [ "$tx_kib" -gt 1 ]; then + # echo -n "📤 " + echo -n " ↑ " + if [[ "$tx_rate" -gt 1048576 ]]; then + printf '%sM' "$(echo "scale=1; $tx_kib / 1024" | bc)" + else + echo -n "${tx_kib}K" + fi +fi + +# echo +# echo +# echo "$BLOCK_COLOR_LEVEL1" diff --git a/.local/bin/statusbar/i3battery b/.local/bin/statusbar/i3battery new file mode 100755 index 0000000..5b2fb15 --- /dev/null +++ b/.local/bin/statusbar/i3battery @@ -0,0 +1,66 @@ +#!/bin/sh + +case "$BLOCK_BUTTON" in + 1) notify-send Temprature "$(sensors --no-adapter coretemp-isa-0000 | + tail +2 | sed "s|(.*)||")" ;; + 2) $TERMINAL -e "$EDITOR" "$0" ;; + 3) $TERMINAL -e battop ;; + 4) brightness up ;; + 5) brightness down ;; +esac; + +# Loop through all attached batteries and format the info +for battery in /sys/class/power_supply/BAT?*; do + capacity="$(cat "$battery/capacity" 2>&1)" + # If non-first battery, print a space separator. + # [ -n "${capacity+x}" ] && printf " " + # Sets up the status and capacity + status="$(cat "$battery/status" 2>&1)" + case "$status" in + "Full") icon="" ;; + "Discharging") case "$capacity" in + 9[0-9]) icon="" ;; + 8[0-9]) icon="" ;; + 7[0-9]) icon="" ;; + 6[0-9]) icon="" ;; + 5[0-9]) icon="" ;; + 4[0-9]) icon="" ;; + 3[0-9]) icon="" ;; + 2[0-9]) icon="" ;; + 1[0-9]|[0-9]) icon="" ;; + 100) icon="" ;; + esac ;; + "Charging") case "$capacity" in + 9[0-9]) icon="" ;; + 8[0-9]) icon="" ;; + 7[0-9]) icon="" ;; + 6[0-9]) icon="" ;; + 5[0-9]) icon="" ;; + 4[0-9]) icon="" ;; + 3[0-9]) icon="" ;; + 2[0-9]) icon="" ;; + 1[0-9]|[0-9]) icon="" ;; + 100) icon="" ;; + esac ;; + "Not charging") icon="" ;; + "Unknown") icon="" ;; + *) exit 1 ;; + esac + # Will make a warn variable if discharging and low + [ "$status" = "Discharging" ] && [ "$capacity" -le 25 ] && warn="❗" + # Prints the info + printf "%s%s %d%%" "$warn" "$icon" "$capacity"; unset warn +done && printf "\\n" + +echo +if [ $capacity -ge 80 ]; then + echo "$BLOCK_COLOR_LEVEL1" +elif [ $capacity -ge 40 ]; then + echo "$BLOCK_COLOR_LEVEL2" +elif [ $capacity -ge 20 ]; then + echo "$BLOCK_COLOR_LEVEL3" +elif [ $capacity -ge 10 ]; then + echo "$BLOCK_COLOR_LEVEL4" +else + echo "$BLOCK_COLOR_LEVEL5" +fi diff --git a/.local/bin/statusbar/i3cpu b/.local/bin/statusbar/i3cpu new file mode 100755 index 0000000..c5eeb68 --- /dev/null +++ b/.local/bin/statusbar/i3cpu @@ -0,0 +1,34 @@ +#!/bin/sh + +case "$BLOCK_BUTTON" in + 1) $TERMINAL -e gotop ;; + 2) $TERMINAL -e nvim "$(which i3cpu)" ;; + 3) echo "top,$TERMINAL -e top + htop,$TERMINAL -e htop + gotop,$TERMINAL -e gotop + nvtop,$TERMINAL -e nvtop" | jgmenu --vsimple --at-pointer ;; +esac; + +cpu_usage="$(cpu_usage)" +cpu="${cpu_usage%.*}" +printf "%s" "$cpu_usage" +# printf " " +# sb-cpubars + +echo +echo +# Print color, if needed +if [ "$cpu" -ge 90 ]; then + echo "$BLOCK_COLOR_LEVEL5"; + exit 33; +elif [ "$cpu" -ge 70 ]; then + echo "$BLOCK_COLOR_LEVEL4" +elif [ "$cpu" -ge 50 ]; then + echo "$BLOCK_COLOR_LEVEL3" +elif [ "$cpu" -ge 20 ]; then + echo "$BLOCK_COLOR_LEVEL2" +else + echo "$BLOCK_COLOR_LEVEL1" +fi + + diff --git a/.local/bin/statusbar/i3cpubars b/.local/bin/statusbar/i3cpubars new file mode 100755 index 0000000..c4c18af --- /dev/null +++ b/.local/bin/statusbar/i3cpubars @@ -0,0 +1,44 @@ +#!/bin/sh + +# Module showing CPU load as a changing bars. +# Just like in polybar. +# Each bar represents amount of load on one core since +# last run. + +# Cache in tmpfs to improve speed and reduce SSD load +cache=/tmp/cpubarscache + +case $BLOCK_BUTTON in + 2) setsid -f "$TERMINAL" -e htop ;; + 3) notify-send "🪨 CPU load module" "Each bar represents +one CPU core";; + 6) "$TERMINAL" -e "$EDITOR" "$0" ;; +esac + +# id total idle +stats=$(awk '/cpu[0-9]+/ {printf "%d %d %d\n", substr($1,4), ($2 + $3 + $4 + $5), $5 }' /proc/stat) +[ ! -f $cache ] && echo "$stats" > "$cache" +old=$(cat "$cache") +# printf "🪨" +echo "$stats" | while read -r row; do + id=${row%% *} + rest=${row#* } + total=${rest%% *} + idle=${rest##* } + + case "$(echo "$old" | awk '{if ($1 == id) + printf "%d\n", (1 - (idle - $3) / (total - $2))*100 /12.5}' \ + id="$id" total="$total" idle="$idle")" in + + "0") printf "▁";; + "1") printf "▂";; + "2") printf "▃";; + "3") printf "▄";; + "4") printf "▅";; + "5") printf "▆";; + "6") printf "▇";; + "7") printf "█";; + "8") printf "█";; + esac +done; # printf "\\n" +echo "$stats" > "$cache" diff --git a/.local/bin/statusbar/i3cpuload b/.local/bin/statusbar/i3cpuload new file mode 100755 index 0000000..6c14ddd --- /dev/null +++ b/.local/bin/statusbar/i3cpuload @@ -0,0 +1,68 @@ +#!/usr/bin/perl +# +# Copyright 2014 Pierre Mavro <deimos@deimos.fr> +# Copyright 2014 Vivien Didelot <vivien@didelot.org> +# Copyright 2014 Andreas Guldstrand <andreas.guldstrand@gmail.com> +# +# Licensed under the terms of the GNU GPL v3, or any later version. + +use strict; +use warnings; +use utf8; +use Getopt::Long; + +# default values +my $t_warn = $ENV{T_WARN} // 70; # default 50 +my $t_crit = $ENV{T_CRIT} // 90; # default 80 +my $cpu_usage = -1; +my $decimals = $ENV{DECIMALS} // 2; +my $label = $ENV{LABEL} // ""; + +sub help { + print "Usage: cpu_usage [-w <warning>] [-c <critical>] [-d <decimals>]\n"; + print "-w <percent>: warning threshold to become yellow\n"; + print "-c <percent>: critical threshold to become red\n"; + print "-d <decimals>: Use <decimals> decimals for percentage (default is $decimals) \n"; + exit 0; +} + +GetOptions("help|h" => \&help, + "w=i" => \$t_warn, + "c=i" => \$t_crit, + "d=i" => \$decimals, +); + +# Get CPU usage +$ENV{LC_ALL}="en_US"; # if mpstat is not run under en_US locale, things may break, so make sure it is +open (MPSTAT, 'mpstat |') or die; +while (<MPSTAT>) { + if (/^.*\s+(\d+\.\d+)[\s\x00]?$/) { + $cpu_usage = 100 - $1; # 100% - %idle + last; + } +} +close(MPSTAT); + +$cpu_usage eq -1 and die 'Can\'t find CPU information'; + +# Print short_text, full_text +print "${label}"; +printf "%.${decimals}f%%\n", $cpu_usage; + + +# print "\n"; +# # Print color, if needed +# if ($cpu_usage >= $t_crit) { +# print "$ENV{BLOCK_COLOR_LEVEL5}\n"; +# exit 33; +# } elsif ($cpu_usage >= $t_warn) { +# print "$ENV{BLOCK_COLOR_LEVEL4}\n"; +# } elsif ($cpu_usage >= 50) { +# print "$ENV{BLOCK_COLOR_LEVEL3}\n"; +# } elsif ($cpu_usage >= 20) { +# print "$ENV{BLOCK_COLOR_LEVEL2}\n"; +# } else { +# print "$ENV{BLOCK_COLOR_LEVEL1}\n"; +# } + +exit 0; diff --git a/.local/bin/statusbar/i3memory b/.local/bin/statusbar/i3memory new file mode 100755 index 0000000..edf9a73 --- /dev/null +++ b/.local/bin/statusbar/i3memory @@ -0,0 +1,33 @@ +#!/bin/sh + +case "$BLOCK_BUTTON" in + 1) $TERMINAL -e gotop ;; + 2) $TERMINAL -e nvim "$(which i3cpu)" ;; + 3) echo "top,$TERMINAL -e top + htop,$TERMINAL -e htop + gotop,$TERMINAL -e gotop + nvtop,$TERMINAL -e nvtop" | jgmenu --vsimple --at-pointer ;; +esac; + +memory="$(memory_percent)" +printf "%s" "$(memory_usage)" +# printf " " +# sb-cpubars + +echo +echo +# Print color, if needed +if [ "$memory" -ge 90 ]; then + echo "$BLOCK_COLOR_LEVEL5"; + exit 33; +elif [ "$memory" -ge 70 ]; then + echo "$BLOCK_COLOR_LEVEL4" +elif [ "$memory" -ge 50 ]; then + echo "$BLOCK_COLOR_LEVEL3" +elif [ "$memory" -ge 20 ]; then + echo "$BLOCK_COLOR_LEVEL2" +else + echo "$BLOCK_COLOR_LEVEL1" +fi + + diff --git a/.local/bin/statusbar/i3weather b/.local/bin/statusbar/i3weather new file mode 100755 index 0000000..2d34149 --- /dev/null +++ b/.local/bin/statusbar/i3weather @@ -0,0 +1,26 @@ +#!/bin/sh +# i3block for displaying the current temperature, humidity and precipitation, if wttr.in i unavailable then WEATHER UNAVAILABLE will be displayed + +case "$BLOCK_BUTTON" in + '') ;; + 1) + $TERMINAL -e less -r ~/.cache/weather.txt & sleep 0.3 + i3-msg 'move to workspace "12: Weather"; workspace "12: Weather"' >/dev/null 2>&1 + ;; + 2) $TERMINAL -e nvim "$0" ;; + *) notify-send "⛅ Refreshing weather info..." ;; +esac + +HTTP_WEATHER="https://wttr.in/Vasai" +# weather="$(curl -s "$HTTP_WEATHER?format=%c%C++❄️+%t++☀️+%f++🌬️+%w")" +weather="$(curl -Ss "$HTTP_WEATHER?0&T&Q" | cut -c 16- | head -2 | + xargs echo "$(curl -s "$HTTP_WEATHER?format=%c")")" + +if [ "$(echo "$weather" | grep -Ec "(Unknown|curl|HTML)")" -gt 0 ]; then + echo "WEATHER UNAVAILABLE" +else + echo "${weather:-⛅ -- }" +fi + +curl -s "$HTTP_WEATHER" > ~/.cache/weather.txt + diff --git a/.local/bin/statusbar/i3wifi b/.local/bin/statusbar/i3wifi new file mode 100755 index 0000000..689e3a2 --- /dev/null +++ b/.local/bin/statusbar/i3wifi @@ -0,0 +1,37 @@ +#!/bin/sh +# i3block for the displaying the wifi connectivity level +# If the wifi interface exists but no connection is active, "down" shall be displayed. + +case "$BLOCK_BUTTON" in + 1) $TERMINAL -e nmtui ;; + 2) $TERMINAL -e nvim "$0" ;; + 3) $TERMINAL -e nethogs ;; + # 3) echo "nethogs,$TERMINAL -e nethogs + # bmon,$TERMINAL -e bmon + # nmtui, $TERMINAL -e nmtui" | jgmenu --vsimple --at-pointer ;; +esac + +iface="$(find /sys/class/net/ -maxdepth 1 -name "w*" -printf "%f\n")" +if [ "$(cat "/sys/class/net/$iface/operstate")" = 'down' ]; then + icon=""; quality="down"; color="$BLOCK_COLOR_LEVEL5" +else + quality=$(grep "$iface" /proc/net/wireless | awk '{ print int($3 * 100 / 70) }') + if [ "$quality" = 100 ]; then + icon=""; color="$BLOCK_COLOR_LEVEL1" + elif [ "$quality" -ge 80 ]; then + icon=""; color="$BLOCK_COLOR_LEVEL1" + elif [ "$quality" -ge 60 ]; then + icon=""; color="$BLOCK_COLOR_LEVEL2" + elif [ "$quality" -ge 40 ]; then + icon=""; color="$BLOCK_COLOR_LEVEL3" + elif [ "$quality" -ge 20 ]; then + icon=""; color="$BLOCK_COLOR_LEVEL4" + else + icon=""; color="$BLOCK_COLOR_LEVEL5" + fi + [ -n "$quality" ] && quality="$quality%" +fi + +echo "$icon $quality" +echo +echo "$color" diff --git a/.local/bin/statusbar/memory_percent b/.local/bin/statusbar/memory_percent new file mode 100755 index 0000000..2b8da66 --- /dev/null +++ b/.local/bin/statusbar/memory_percent @@ -0,0 +1,57 @@ +#!/bin/sh +# Copyright (C) 2014 Julien Bonjean <julien@bonjean.info> + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +TYPE="${BLOCK_INSTANCE:-mem}" + +awk -v type=$TYPE ' +/^MemTotal:/ { + mem_total=$2 +} +/^MemFree:/ { + mem_free=$2 +} +/^Buffers:/ { + mem_free+=$2 +} +/^Cached:/ { + mem_free+=$2 +} +/^SwapTotal:/ { + swap_total=$2 +} +/^SwapFree:/ { + swap_free=$2 +} +END { + if (type == "swap") { + free=swap_free/1024/1024 + used=(swap_total-swap_free)/1024/1024 + total=swap_total/1024/1024 + } else { + free=mem_free/1024/1024 + used=(mem_total-mem_free)/1024/1024 + total=mem_total/1024/1024 + } + pct=0 + if (total > 0) { + pct=used/total*100 + } + # full text + # printf("%.1fG/%.1fG", used, total) + # printf("%.1fG", used) + printf("%d", pct) +} +' /proc/meminfo diff --git a/.local/bin/statusbar/memory_usage b/.local/bin/statusbar/memory_usage new file mode 100755 index 0000000..8f0fee4 --- /dev/null +++ b/.local/bin/statusbar/memory_usage @@ -0,0 +1,56 @@ +#!/bin/sh +# Copyright (C) 2014 Julien Bonjean <julien@bonjean.info> + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +TYPE="${BLOCK_INSTANCE:-mem}" + +awk -v type=$TYPE ' +/^MemTotal:/ { + mem_total=$2 +} +/^MemFree:/ { + mem_free=$2 +} +/^Buffers:/ { + mem_free+=$2 +} +/^Cached:/ { + mem_free+=$2 +} +/^SwapTotal:/ { + swap_total=$2 +} +/^SwapFree:/ { + swap_free=$2 +} +END { + if (type == "swap") { + free=swap_free/1024/1024 + used=(swap_total-swap_free)/1024/1024 + total=swap_total/1024/1024 + } else { + free=mem_free/1024/1024 + used=(mem_total-mem_free)/1024/1024 + total=mem_total/1024/1024 + } + pct=0 + if (total > 0) { + pct=used/total*100 + } + # full text + # printf("%.1fG/%.1fG", used, total) + printf("%.1fG", used) +} +' /proc/meminfo diff --git a/.local/bin/ttyl b/.local/bin/ttyl new file mode 100755 index 0000000..fd71280 --- /dev/null +++ b/.local/bin/ttyl @@ -0,0 +1,37 @@ +#!/bin/sh + +help() { + echo "ttyl - tty lock + +USAGE: + ttyl [OPTION]... [COMMAND] + +OPTIONS: + -a lock all TTYs + (default when no command is passed and terminal is a tty) + -c lock current TTY + -h show this help message" +} + +err() { printf 'ttyl: %s\n' "$@" >&2; exit 1; } + +while getopts 'ach' o; do case "$o" in + a) lockall=0 ;; + c) lockall=1 ;; + h) help >&2; exit ;; + *) err "invalid option -- '$OPTARG'" ;; +esac done +shift $((OPTIND - 1)) + +case "$lockall" in + 1) lock="vlock" ;; + 0) lock="vlock -a" ;; + *) + case "$(tty)" in + /dev/tty[1-7]) lock="vlock -a" ;; + *) lock="vlock" ;; + esac + ;; +esac + +sleep 1 && $@ & $lock diff --git a/.local/bin/unix b/.local/bin/unix new file mode 100755 index 0000000..a9fb96e --- /dev/null +++ b/.local/bin/unix @@ -0,0 +1,26 @@ +#!/bin/sh + +#original artwork by http://www.sanderfocus.nl/#/portfolio/tech-heroes +#converted to shell by #nixers @ irc.unix.chat + +cat << 'eof' + [38;5;255m,_ ,_==▄▂[0m + [38;5;255m, ▂▃▄▄▅▅[48;5;240m▅[48;5;20m▂[48;5;240m▅¾[0m. [38;5;199m/ [38;5;20m/[0m + [38;5;255m[48;5;20m▄[0m[38;5;255m[48;5;199m▆[38;5;16m[48;5;255m<´ [38;5;32m"[38;5;34m»[38;5;255m▓▓[48;5;32m▓[48;5;240m%[0m\ [38;5;199m/ [38;5;20m/ [38;5;45m/ [38;5;118m/[0m + [38;5;255m,[38;5;255m[48;5;240m▅[38;5;16m[48;5;255m7" [38;5;160m´[38;5;34m>[38;5;255m[48;5;39m▓▓[38;5;199m[48;5;255m▓[0m[38;5;255m% [38;5;20m/ [38;5;118m/ [38;5;199m> [38;5;118m/ [38;5;199m>[38;5;255m/[38;5;45m%[0m + [38;5;255m▐[48;5;240m[38;5;255m¶[48;5;240m[38;5;255m▓[48;5;255m [38;5;196m,[38;5;34m»[48;5;201m[38;5;255m▓▓[0m[38;5;255m¾´[0m [38;5;199m/[38;5;255m> %[38;5;199m/[38;5;118m%[38;5;255m/[38;5;199m/ [38;5;45m/ [38;5;199m/[0m + [38;5;255m[48;5;240m▓[48;5;255m[38;5;16m▃[48;5;16m[38;5;255m▅▅[38;5;16m[48;5;255m▅▃,,[38;5;32m▄[38;5;16m▅[38;5;255m[48;5;16m▅▅[38;5;255m[48;5;20mÆ[0m[38;5;255m\[0m[38;5;20m/[38;5;118m/[38;5;255m /[38;5;118m/[38;5;199m/[38;5;255m>[38;5;45m// [38;5;255m/[38;5;118m>[38;5;199m/ [38;5;20m/[0m + [48;5;20m[38;5;255mV[48;5;255m[38;5;16m║[48;5;20m[38;5;255m«[0m[38;5;255m¼.;[48;5;240m[38;5;255m→[48;5;255m[38;5;16m ║[0m[38;5;255m<«.,[48;5;25m[38;5;255m`[48;5;240m=[0m[38;5;20m/[38;5;199m/ [38;5;255m/>[38;5;45m/[38;5;118m/[38;5;255m%/[38;5;199m% / [38;5;20m/[0m + [38;5;20m//[48;5;255m[38;5;16m╠<´ -²,)[48;5;16m[38;5;255m(▓[48;5;255m[38;5;16m~"-[38;5;199m╝/[0m[38;5;255m¾[0m[38;5;199m/ [38;5;118m%[38;5;255m/[38;5;118m>[38;5;45m/ [38;5;118m/[38;5;199m>[0m + [38;5;20m/ / [38;5;118m/ [48;5;20m[38;5;255m▐[48;5;240m[38;5;16m%[48;5;255m -./▄▃▄[48;5;16m[38;5;255m▅[48;5;255m[38;5;16m▐[48;5;255m[38;5;16m, [38;5;199m/[48;5;199m[38;5;255m7[0m[38;5;20m/[38;5;199m/[38;5;255m;/[38;5;199m/[38;5;118m% [38;5;20m/ /[0m + [38;5;20m/ [38;5;199m/[38;5;255m/[38;5;45m/[38;5;118m/[38;5;255m[48;5;240m`[48;5;20m[38;5;255m▌[48;5;20m[38;5;255m▐[48;5;255m[38;5;16m %z[0m[38;5;255mWv xX[48;5;20m[38;5;255m▓[48;5;34m[38;5;255m▇[48;5;199m[38;255m▌[0m[38;5;20m/[38;5;199m/[38;5;255m&;[38;5;20m% [38;5;199m/ [38;5;20m/[0m + [38;5;20m/ / [38;5;255m/ [38;5;118m%[38;5;199m/[38;5;255m/%/[48;5;240m[38;5;255m¾[48;5;255m[38;5;16m½´[38;5;255m[48;5;16m▌[0m[38;5;246m▃▄[38;5;255m▄▄[38;5;246m▄▃▃[0m[48;5;16m[38;5;255m▐[38;5;255m[48;5;199m¶[48;5;20m[38;5;255m\[0m[38;5;20m/[0m[48;5;255m[38;5;240m&[0m [38;5;20m/[0m + [38;5;199m<[38;5;118m/ [38;5;45m/[38;5;255m</[38;5;118m%[38;5;255m/[38;5;45m/[38;5;255m`[48;5;16m▓[48;5;255m[38;5;16m![48;5;240m[38;5;255m%[48;5;16m[38;5;255m▓[0m[38;5;255m%[48;5;240m[38;5;255m╣[48;5;240m[38;5;255;╣[0m[38;5;255mW[0m[38;5;250mY<Y)[48;5;255m[38;5;16my&[0m[38;5;255m/`[48;5;240m\[0m + [38;5;20m/ [38;5;199m/ [38;5;199m%[38;5;255m/%[38;5;118m/[38;5;45m/[38;5;255m<[38;5;118m/[38;5;199m%[38;5;45m/[38;5;20m/[48;5;240m[38;5;255m\[38;5;16m[48;5;255mi7; ╠N[0m[38;5;246m>[38;5;255m)VY>[48;5;240m[38;5;255m7[0m[38;5;255m; [38;5;255m[48;5;240m\[0m[38;5;255m_[0m [38;5;255mUNIX IS VERY SIMPLE [38;5;45mIT JUST NEEDS A[0m + [38;5;20m/ [38;5;255m/[38;5;118m<[38;5;255m/ [38;5;45m/[38;5;255m/<[38;5;199m/[38;5;20m/[38;5;199m/[38;5;20m<[38;5;255m_/%\[38;5;255m[48;5;16m▓[48;5;255m[38;5;16m V[0m[38;5;255m%[48;5;255m[38;5;16mW[0m[38;5;255m%£)XY[0m [38;5;240m_/%[38;5;255m‾\_,[0m [38;5;45mGENIUS TO UNDERSTAND ITS SIMPLICITY[38;5;255m[0m + [38;5;199m/ [38;5;255m/ [38;5;199m/[38;5;255m/[38;5;118m%[38;5;199m/[48;5;240m[38;5;255m_,=-[48;5;20m-^[0m[38;5;255m/%/%%[48;5;255m[38;5;16m\¾%[0m[38;5;255m¶[0m[48;5;255m[38;5;16m%[0m[38;5;255m%}[0m [38;5;240m/%%%[38;5;20m%%[38;5;240m%;\,[0m + [38;5;45m%[38;5;20m/[38;5;199m< [38;5;20m/[48;5;20m[38;5;255m_/[48;5;240m [0m[38;5;255m%%%[38;5;240m%%[38;5;20m;[38;5;255mX[38;5;240m%[38;5;20m%[38;5;255m\%[38;5;240m%;, _/%%%;[38;5;20m,[38;5;240m \[0m + [38;5;118m/ [38;5;20m/ [38;5;240m%[38;5;20m%%%%[38;5;240m%;, [38;5;255m\[38;5;240m%[38;5;20m%[38;5;255ml[38;5;240m%%;// _/[38;5;20m%;,[0m [38;5;234mdmr[0m + [38;5;20m/ [38;5;240m%[38;5;20m%%;,[0m [38;5;255m<[38;5;20m;[38;5;240m\-=-/ /[0m + [38;5;20m;,[0m [38;5;240ml[0m +eof diff --git a/.local/bin/web/fpl b/.local/bin/web/fpl new file mode 100755 index 0000000..0398770 --- /dev/null +++ b/.local/bin/web/fpl @@ -0,0 +1,39 @@ +#!/bin/sh + +# You can pass any text file containing a list of video titles. +# An fzf prompt will shown to select a video title. +# The script will then try to find a video file whose name fuzzy matches the +# selected title. + +[ -z "$1" ] && { echo "fzf-playlist: browse a list of video titles +USAGE: fpl <PLAYLIST_FILE>" >&2; exit 1; } + +if [ "$OPENFLAG" = 1 ]; then + + if [ -z "$OPENWITH" ]; then + files="$(find "${PWD%/*}")" + else + files="$(find "${PWD%/*}" -name '*.webm' -or -name '*.mkv' -or -name '*.mp4' -or \ + -name '*.mp3' -or -name '*.ogg')" + fi + + if [ -z "$OPENWITH" ]; then + for title in "$@"; do echo "$files" | + fzf --filter "$(printf '%s\n' "$title" | sed 's/[^A-Za-z0-9]*//g')" + echo; done + else + for title in "$@"; do $OPENWITH "$(echo "$files" | + fzf --filter "$(printf '%s\n' "$title" | sed 's/[^A-Za-z0-9]*//g')" | + head -1)"; echo; done + fi + + exit +fi + +file="$(readlink -f "$1")" +cd "${file%/*}" || exit +fzf --multi --reverse \ + --header="Playlist: ${file##*/}" --header-first \ + --bind 'enter:become(OPENFLAG=1 fpl {+})' \ + --bind 'ctrl-o:execute(OPENFLAG=1 OPENWITH=mpv fpl {})' < "$file" + diff --git a/.local/bin/web/savesite b/.local/bin/web/savesite new file mode 100755 index 0000000..206a633 --- /dev/null +++ b/.local/bin/web/savesite @@ -0,0 +1,35 @@ +#!/bin/sh + +[ "$#" -lt 1 ] && { echo "savesite - save local copy of a website +USAGE: savesite <URL> [DEST_DIR]"; exit 1; } + +url="$1" +site="${2:-"$(echo "$url" | sed 's|\(https\?://\)\?\([A-Za-z0-9.-]*\)/.*|\2|')"}" +WGETLOGS="${3:-.logs/$site.log}" +started="$(date)" + +touch "$WGETLOGS" || exit +printf ":: Downloading site: %s\n" "$site" +printf ":: Logging to: %s\n" "$WGETLOGS" + +{ + setsid wget \ + --continue \ + --recursive \ + --no-clobber \ + --page-requisites \ + --html-extension \ + --convert-links \ + --restrict-file-names=windows \ + --domains "$site" \ + --no-parent \ + --output-file "$WGETLOGS" \ + "$url" + + [ -n "$DISPLAY" ] && notify-send "savesite: finished downloading" "$site" + printf "%s\n" ":: Finished downloading site: $site" \ + ":: Started at: $started" \ + ":: Finished at: $(date)" >> "$WGETLOGS" +} & + +tail -f "$WGETLOGS" diff --git a/.local/bin/web/w3mman b/.local/bin/web/w3mman new file mode 100755 index 0000000..5013fbd --- /dev/null +++ b/.local/bin/web/w3mman @@ -0,0 +1,335 @@ +#!/bin/bash + +# w3m-man +# +# Use wget, w3m and less to download and view man pages. +# +# Homepage: https://github.com/sc0ttj/w3m-man +# +# Supports using $MANPAGER, $HTMLPAGER, $TERM_BROWSER, and +# falls back to w3m and less if these are not set. +# +# How it works: +# +# - saves manpage from online sources to $HOME/.w3m-manpages/ +# - not proper man pages, just plain text output of websites +# - prettifies them a bit (removes junk headers, links, messages) +# +# Usage: +# +# man <command> # view man page in plain text in $PAGER +# man -H <command> # view man page as HTML in $BROWSER +# man <command> --url # print the URL of the man page to STDOUT + +# TODO: +# +# - Display the path searched for manpages: +# +# man --path +# +# - Display the location of a manpage rather than the manpage itself: +# +# man -w command +# +# - Search for manpages containing a search string: +# +# man -k "search_string" +# + +if [ "$1" = "--help" ];then + + echo "# man (w3m-man) +# Use wget, w3m and less to download and view man pages +# See https://github.com/sc0ttj/w3m-man + +Usage: + + man <command> # (download and) print the man page + + man <command> --url # print the URL from which the man + # page was/would be downloaded + + man --help # print this help info + +Where <command> is the command name you want to read about. + +Examples: + + man diff # view 'diff' command (section 1) + + man mount.8 # view 'mount' in section 8 (config stuff) + + man 8 mount # same as above, but doesn't work with -H + + man -H mount # view 'mount' man page as HTML using $BROWSER + + man <command> --url # only print the URL from which the man page + # was/would be downloaded + +Man pages are divided into sections, as follows: + + 1. User: most user commands and programs. + + 2. System: calls by the Linux kernel. + + 3. Library: documents provided by the standard C library. + + 4. Devices: documents various devices, most of which reside in /dev. + + 5. Files: describes various file formats and filesystems and proc(5). + + 7. Overviews, conventions, and miscellaneous. + + 8. Superuser and system administration commands. + +Checks the following URLs: + +the Ubuntu or Debian man pages, also: + +http://man.he.net/?topic=\${command}§ion=\${section} +http://manpages.org/\${command}/\${section} +https://linux.die.net/man/\${section}/\${command} +https://www.mankier.com/\${section}/\${command} +https://man7.org/linux/man-pages/man\${section}/\${command}.\${section}.html +http://manpages.org/\${command} +http://man.he.net/?topic=\${command}§ion=all +https://ss64.com/bash/\${command}.html +" + exit 0 +fi + +old_man="$(command -v man)" +unset man + +command="$1" +section="1" + +DISTRO_COMPAT_VERSION="latest" +if [ -f /etc/DISTRO_SPECS ];then + source /etc/DISTRO_SPECS +fi + + +# support GNU man -H option (to view as HTML) +if [ "$1" = "-H" ];then + command="$2" +fi + +# support GNU man syntax `man 1 mount` +re='^[1-8]+$' +if [[ $1 =~ $re ]] ; then + command="${2}.$1" + section="$1" +fi + +# support GNU man syntax `man mount.1`, `man mount.2`, etc +section="${command//*\./}" +command="${command//\.*/}" +if [ "$command" = "$section" ];then + section=1 +fi + +manpage_file="$HOME/.w3m-manpages/$command.$section" + +# support env var $MANPAGER +pager=${MANPAGER:-$PAGER} +pager=${pager:-less -XR} +w3m='w3m -o auto_image=false -o display_image=false' +browser=${TERM_BROWSER:-$TERMBROWSER} +browser=${browser:-$w3m} +htmlpager=${HTMLPAGER:-w3m -dump} + +# Remove some junk from the plain text files generated by w3m, +# such as headers, links to adverts, etc +function prettifier { + url="$1" + case "$url" in + + *'ubuntu.com'*|*'debian.org'*) + sed \ + -e '1,5d' \ + -e 's/ bug$//' \ + -e 's/ / /g' + ;; + + *'linux.die.net'*) + sed -e '1d' -e 's/\[INS::INS\]//g' -e 's/ \[ \]//g' \ + -e 's/Site Search//g' 2>/dev/null | head -n -12 + ;; + + *mankier*) + grep -vEi ' • [A-Z]| □ [A-Z]' | sed -e '1,7d' -e 's/tldr.sh//g' \ + -e "s/$command /$command($section) /g" + ;; + + *ss64*com*) + sed '1,5d' 2>/dev/null + ;; + + *'man7.org'*) + sed -e '1,4d' -e '8,13d' -e 's/ top/ /g' \ + | grep -vE 'StatCounter' | head -n -15 + ;; + + *manpages*org*) + sed -e '1,3d' \ + | head -n -14 + ;; + + *man*he*net*) cat - ;; + + *) cat - ;; + esac +} + +# create the config dir, if needed +[ ! -d $HOME/.w3m-manpages ] && mkdir -p $HOME/.w3m-manpages + +# if we already have a proper man page, just print it and exit +if [ ! -z "$MANPATH" ] && [ "$(which groff)" != "" ] && [ "$1" != "-H" ] && [ "$2" != "--url" ];then + usegroff=false + groff_file='' + zipped=false + paths=$(echo "${MANPATH}" | tr ':' '\n') + # for each path + for dir in ./ $paths + do + zipped=false + # let's find the man page file + groff_file=$dir/man${section}/${command}.${section} + # it might be gzipped + [ ! -f $groff_file ] && groff_file=$dir/man${section}/${command}.${section}.gz && zipped=true + # it might be in the current directory + [ -f ./${command}.${section} ] && groff_file="./${command}.${section}" + [ -f ./${command}.${section}.gz ] && groff_file="./${command}.${section}.gz" && zipped=true + # if we found the file + if [ -f $groff_file ];then + # unpack it, if needed + [ $zipped = true ] && zcat $groff_file > /tmp/unzipped && groff_file=/tmp/unzipped + # now lets read the man page and exit + groff -T utf8 -man $groff_file | $pager && exit 0 + fi + done +fi + +# if we already have the man page as plain text, just print it and exit +[ "$1" != "-H" ] && [ "$2" != "--url" ] && [ -f "$manpage_file" ] && cat "$manpage_file" | $pager && exit 0 + +# set a list of urls to check: + +# these man pages cover the correct versions of the program you have installed, +# for the OS you're actually using (if using an Ubuntu or Debian based pup) +if [ "$DISTRO_BINARY_COMPAT" = "ubuntu" ];then + URLS="https://manpages.ubuntu.com/manpages/${DISTRO_COMPAT_VERSION}/man${section}/${command}.${section}.html" +elif [ "$DISTRO_BINARY_COMPAT" = "debian" ];then + URLS="https://manpages.debian.org/${DISTRO_COMPAT_VERSION}/${command}/${command}.${section}.en.html" +fi + +# add the rest +URLS="$URLS +http://man.he.net/?topic=${command}§ion=${section} +http://manpages.org/${command}/${section} +https://linux.die.net/man/${section}/${command} +https://www.mankier.com/${section}/${command} +https://man7.org/linux/man-pages/man${section}/${command}.${section}.html +http://manpages.org/${command} +http://man.he.net/?topic=${command}§ion=all +https://ss64.com/bash/${command}.html +" +# for each url in the list +for url in ${URLS} +do + # skip any empty urls + [ "$url" != "" ] || continue + [ "$url" != " " ] || continue + + # crawl the url + wget --timeout=2 --spider -S -o /tmp/"$command".html "$url" + + # get the status code + grep -m1 'HTTP/[1-3].[0-9] [0-9][0-9][0-9]' /tmp/"$command".html | grep -E '200 OK' > /tmp/response + + # if HTTP status not 200, skip this url + grep -q -m1 "200" /tmp/response || continue + + # print the URL if --url given + [ "$2" = "--url" ] && echo "$url" && exit 0 + + # grab the URL contents as plain text, put it into a file + timeout 2 $htmlpager "$url" | prettifier "$url" > "$manpage_file" + + # if file is empty, remove it, skip this url + [ ! -s "$manpage_file" ] && rm "$manpage_file" && continue + + # check if we if we got a "not found" page + notfound=false + grep -qiE "^Couldn|Hmmm|Invalid characters|No matches for \"|t found manual page under category" "$manpage_file" && notfound=true + + # if we DID get a "not found" page, delete the man page, skip this url + [ "$notfound" = true ] && rm "$manpage_file" && continue + + # if man page not a file, skip this url + [ ! -f "$manpage_file" ] && continue + + # if -H was given, print it out as HTML (like GNU man) + if [ "$1" = "-H" ] ;then + $browser "$url" + fi + + # + # add a footer to the man page + # + echo >> "$manpage_file" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" >> "$manpage_file" + echo >> "$manpage_file" + echo "Generated by https://github.com/sc0ttj/w3m-manpage" >> "$manpage_file" + echo >> "$manpage_file" + echo "Source URL $url" >> "$manpage_file" + echo >> "$manpage_file" + + # man page created, dont need to do another url + break +done + +# if we still did not _create_ a file, see if we have local +# matching ones, in a different section +if [ ! -f "$manpage_file" ];then + local_pages=$(ls $HOME/.w3m-manpages | grep "${command}.") + if [ "$local_pages" != "" ];then + if [ $(echo "$local_pages" | wc -l) = 1 ];then + echo + echo "Loading $local_pages" | tr -d '\n' + echo + sleep 2 + manpage_file="$HOME/.w3m-manpages/$local_pages" + elif [ $(echo "$local_pages" | wc -l) -ge 2 ];then + echo + echo "Did you mean any of these?" + echo + echo "$local_pages" + exit 1 + fi + fi +fi + +# if we have a man page, and didnt already print the html, print it here +[ "$1" != "-H" ] && [ -f "$manpage_file" ] \ + && cat "$manpage_file" | $pager && exit 0 + +# if _still_ nothing, try download it online from the next section +if [ ! -f "$manpage_file" ];then + if [ -f /tmp/man_loopcount ] && [ $(wc -l /tmp/man_loopcount | cut -f1 -d' ') -ge 8 ];then + rm /tmp/man_loopcount + exit 1 + fi + next_section=$(($section + 1)) + [ $next_section -eq 9 ] && next_section=1 + echo -n "." + echo "." >> /tmp/man_loopcount + exec $0 $next_section $command + retval=$? + [ $retval -eq 0 ] && rm /tmp/manprogress + echo +fi + +man="$old_man" diff --git a/.local/bin/web/ytf b/.local/bin/web/ytf new file mode 100755 index 0000000..57b4af2 --- /dev/null +++ b/.local/bin/web/ytf @@ -0,0 +1,10 @@ +#!/bin/sh + +case "$1" in + '') echo "ytf - download media using youtube config file\nUSAGE: ytf <FILE> [OPTION]..." >&2; exit 1 ;; + *.ytd) yt-dlp --config "$@" --config ~/.config/yt-dlp/videos.conf ;; + *.ytp) yt-dlp --config "$@" --config ~/.config/yt-dlp/playlist.conf ;; + *.ytps) yt-dlp --config "$@" --config ~/.config/yt-dlp/sequenced-playlist.conf ;; + *.ytc) yt-dlp --config "$@" --config ~/.config/yt-dlp/channel.conf ;; + *) echo "ytf: $1: config file not understood"; exit 1 ;; +esac diff --git a/.local/bin/web/ytplaylist b/.local/bin/web/ytplaylist new file mode 100755 index 0000000..7bc9026 --- /dev/null +++ b/.local/bin/web/ytplaylist @@ -0,0 +1,34 @@ +#!/bin/sh + +# Useful when creating a directory of videos sequenced as per a youtube +# playlist. +# Run this script from from the root of a directory that contains all the media +# and metadata files. +# The playlist file is expected to be in 'playlist' directory within the root +# with .pl.txt extension. (playlist/PLAYLIST_NAME.pl.txt) +# The new playlist directory will be created in the current directory i.e. the +# root if no other destination is passed as the second argument. + +case "$1" in + '') echo "ytplaylist - build a directory of sequenced videos using a playlist file\n +USAGE:\n\tytplaylist <PLAYLIST_FILE> [DESTINATION_DIR] " >&2; exit ;; + playlist/*.pl.txt) ;; + *) + printf "%s" "Unconventional file path, contniue? [y/N] " + read -r ans + case "$ans" in y) ;; *) exit 1 ;; esac + ;; +esac + +playlist="$(readlink -f $1)" +i=1 +fpl "$playlist" | while read -r file; do + if [ -z "$file" ]; then + i=$(( $i + 1 )) + continue + fi + dir="$(dirname "$file")" + base="$(basename "$file")" + rsync -Pru --mkpath "$file" \ + "${2:-$(basename "${playlist%.pl.txt}")}/${dir#$(readlink -f "$PWD")}/$(printf "%02d" "$i") $base" +done diff --git a/.local/bin/web/ytv b/.local/bin/web/ytv new file mode 100755 index 0000000..c6e9eec --- /dev/null +++ b/.local/bin/web/ytv @@ -0,0 +1,3 @@ +#!/bin/sh + +yt-dlp "$@" --config ~/.config/yt-dlp/videos.conf |