aboutsummaryrefslogtreecommitdiff
path: root/scripts/bin
diff options
context:
space:
mode:
authorAkshay Nair <phenax5@gmail.com>2020-12-24 00:06:27 +0530
committerAkshay Nair <phenax5@gmail.com>2020-12-24 00:06:27 +0530
commit865728068c965e066d0f8971c5b5ba26e12e7dce (patch)
treec16195f0a04cf7d004fe5b396255734f4d60bb00 /scripts/bin
parent649ef5f225039e498358c3d056dfd7fcbc56f014 (diff)
downloadnixos-config-865728068c965e066d0f8971c5b5ba26e12e7dce.tar.gz
nixos-config-865728068c965e066d0f8971c5b5ba26e12e7dce.zip
Adds scripts and links scripts and wallpapers
Diffstat (limited to '')
-rwxr-xr-xscripts/bin/color-pick17
-rwxr-xr-xscripts/bin/dsudo4
-rwxr-xr-xscripts/bin/ecmd28
-rwxr-xr-xscripts/bin/escript16
-rwxr-xr-xscripts/bin/extract-urls8
-rwxr-xr-xscripts/bin/file-manager3
l---------scripts/bin/help1
-rwxr-xr-xscripts/bin/macho26
-rwxr-xr-xscripts/bin/open70
-rwxr-xr-xscripts/bin/search12
-rwxr-xr-xscripts/bin/swallow7
-rwxr-xr-xscripts/bin/tmpmail293
-rwxr-xr-xscripts/bin/torque66
-rwxr-xr-xscripts/bin/tst3
-rwxr-xr-xscripts/bin/upload-file19
-rwxr-xr-xscripts/bin/vimv38
-rwxr-xr-xscripts/bin/vman3
-rwxr-xr-xscripts/bin/web4
-rwxr-xr-xscripts/bin/with_zsh4
19 files changed, 622 insertions, 0 deletions
diff --git a/scripts/bin/color-pick b/scripts/bin/color-pick
new file mode 100755
index 0000000..249a20c
--- /dev/null
+++ b/scripts/bin/color-pick
@@ -0,0 +1,17 @@
+#!/usr/bin/env bash
+
+notify_content() {
+ echo "Copied $1 to clipboard";
+ sleep 1;
+}
+
+show_color() {
+ notify_content "$1" | popcorn --bg "$1" --fg "#ffffff";
+}
+
+color=$(grabc);
+
+echo "$color" | xclip -selection clipboard -i;
+
+show_color "$color" & disown;
+
diff --git a/scripts/bin/dsudo b/scripts/bin/dsudo
new file mode 100755
index 0000000..f4d19dc
--- /dev/null
+++ b/scripts/bin/dsudo
@@ -0,0 +1,4 @@
+#!/usr/bin/env bash
+
+SUDO_ASKPASS="$HOME/scripts/password_prompt.sh" sudo -A "$@";
+
diff --git a/scripts/bin/ecmd b/scripts/bin/ecmd
new file mode 100755
index 0000000..bc04a6d
--- /dev/null
+++ b/scripts/bin/ecmd
@@ -0,0 +1,28 @@
+#!/usr/bin/env zsh
+
+source ~/.config/zshconf/paths.zsh;
+
+cd $COMMANDS_DIR;
+
+selected=`fzf +i --print-query -e`;
+[[ -z "$selected" ]] && exit 0;
+
+query=`echo -e "$selected" | head -n 1`;
+selected=`echo -e "$selected" | tail -n 1`;
+
+if [[ "$1" == "rm" ]]; then
+ [[ ! -f $selected ]] && echo "Cant remove $selected. File not found" && exit 1;
+ # TODO: Add confirmation here maybe
+ rm $selected;
+ echo "Removed $selected";
+ exit 0;
+fi;
+
+if (echo "$query" | grep -e '^:') && [[ ! -f "$query" ]]; then
+ escript "$COMMANDS_DIR/$query";
+ echo "Added new command $query";
+else
+ escript "$COMMANDS_DIR/$selected" || echo "$selected command not found";
+ echo "Edited command $query";
+fi;
+
diff --git a/scripts/bin/escript b/scripts/bin/escript
new file mode 100755
index 0000000..a0373dd
--- /dev/null
+++ b/scripts/bin/escript
@@ -0,0 +1,16 @@
+#!/usr/bin/env bash
+
+dir="";
+[[ -z "$1" ]] && return 1;
+if [[ ! -f "$1" ]]; then
+ dir=$(dirname "$1");
+ [[ ! -d "$dir" ]] && mkdir -p "$dir";
+
+ touch "$1";
+ echo -e "#!/usr/bin/env bash\n" > "$1";
+fi;
+
+chmod u+x "$1";
+
+sensible-editor "$1";
+
diff --git a/scripts/bin/extract-urls b/scripts/bin/extract-urls
new file mode 100755
index 0000000..b925e86
--- /dev/null
+++ b/scripts/bin/extract-urls
@@ -0,0 +1,8 @@
+#!/usr/bin/env bash
+
+REGEX="(https?://|www\\.)[\.A-Za-z0-9\-]+\\.[a-zA-Z]{2,4}(/[^ ]*)?"
+
+while read line; do echo "$line"; done | \
+ egrep -o "$REGEX" | \
+ awk '!seen[$0]++';
+
diff --git a/scripts/bin/file-manager b/scripts/bin/file-manager
new file mode 100755
index 0000000..467d346
--- /dev/null
+++ b/scripts/bin/file-manager
@@ -0,0 +1,3 @@
+#!/usr/bin/env bash
+
+sensible-terminal -d "$1" -e lf
diff --git a/scripts/bin/help b/scripts/bin/help
new file mode 120000
index 0000000..1fb83de
--- /dev/null
+++ b/scripts/bin/help
@@ -0,0 +1 @@
+vman \ No newline at end of file
diff --git a/scripts/bin/macho b/scripts/bin/macho
new file mode 100755
index 0000000..93b8f8f
--- /dev/null
+++ b/scripts/bin/macho
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+export FZF_DEFAULT_OPTS='
+--height=30%
+--layout=reverse
+--prompt="Manual: "
+--preview="echo {1} | sed -E \"s/^\((.+)\)/\1/\" | xargs -I{S} man -Pcat {S} {2} 2>/dev/null"';
+
+while getopts ":s:" opt; do
+ case $opt in
+ s ) SECTION=$OPTARG; shift; shift;;
+ \?) echo "Invalid option: -$OPTARG" >&2; exit 1;;
+ : ) echo "Option -$OPTARG requires an argument" >&2; exit 1;;
+ esac;
+done;
+
+manual=$(apropos -s ${SECTION:-''} ${@:-.} | \
+ grep -v -E '^.+ \(0\)' |\
+ awk '{print $2 " " $1}' | \
+ sort | \
+ fzf | \
+ sed -E 's/^\((.+)\)/\1/');
+
+[ -z "$manual" ] && exit 0;
+man $manual;
+
diff --git a/scripts/bin/open b/scripts/bin/open
new file mode 100755
index 0000000..9daa34a
--- /dev/null
+++ b/scripts/bin/open
@@ -0,0 +1,70 @@
+#!/usr/bin/env bash
+
+srun() { setsid -f "$@"; }
+run() { srun "$@" > /dev/null 2> /dev/null; }
+run_async() { run "$@" & disown; }
+
+open_by_mimetype() {
+ local file="$1";
+ local mime=`file "$file" --mime-type -bL`;
+
+ local is_opened=1;
+
+ echo "Opening $file ($mime)...";
+
+ case "$mime" in
+ inode/directory) lf "$file" ;;
+
+ application/x-bittorrent) ~/scripts/torrent.sh torrent "$file" ;;
+
+ text/*) sensible-editor "$file" ;;
+ application/javascript) sensible-editor "$file" ;;
+ application/json) sensible-editor "$file" ;;
+ application/xml) sensible-editor "$file" ;;
+ application/x-*) sensible-editor "$file" ;;
+ *pdf) run_async zathura "$file" ;;
+
+ video/*|image/gif) run_async mpv "$file" ;;
+ image/*) run_async sxiv "$file" ;;
+ audio/*)
+ mpc insert "file://$(readlink -e "$file")" && mpc play && \
+ echo "Adding song to queue";
+ ;;
+
+ *) is_opened=0 ;;
+ esac;
+
+ [[ "$is_opened" == 1 ]] && exit 0;
+}
+
+open_by_path() {
+ local file="$1";
+
+ # Magnet torrent url
+ if [[ "$file" =~ ^magnet: ]]; then
+ echo "opening magnet link...";
+ ~/scripts/torrent.sh magnet "$file";
+ exit 0;
+ fi;
+
+ # Https? and file urls
+ if [[ "$file" =~ ^https?:// ]] || [[ "$file" =~ ^file?:// ]]; then
+ echo "opening url $file...";
+ run_async sensible-browser "$file";
+ exit 0;
+ fi;
+}
+
+
+filepath="$1";
+[[ -z "$filepath" ]] && exit 1;
+
+open() {
+ open_by_path "$filepath";
+ open_by_mimetype "$filepath";
+
+ # If it doesn't exit out, it couldn't open the file
+ echo "Couldn't open file. Add rule to opener."; exit 1;
+}
+open;
+
diff --git a/scripts/bin/search b/scripts/bin/search
new file mode 100755
index 0000000..b443ad8
--- /dev/null
+++ b/scripts/bin/search
@@ -0,0 +1,12 @@
+#!/usr/bin/env bash
+
+AG_PREFIX="ag --noheading --color --smart-case "
+
+export FZF_DEFAULT_COMMAND="$AG_PREFIX '.'";
+
+# TODO: Add preview
+filename=$(fzf --bind "change:reload:$AG_PREFIX {q} || true" --ansi --phony | cut -d':' -f1);
+
+[[ ! -z "$filename" ]] && [[ -f "$filename" ]] && \
+ open "$filename";
+
diff --git a/scripts/bin/swallow b/scripts/bin/swallow
new file mode 100755
index 0000000..0d10523
--- /dev/null
+++ b/scripts/bin/swallow
@@ -0,0 +1,7 @@
+#!/usr/bin/env bash
+
+wid=$(xdo id);
+
+xdo hide && "$@";
+
+xdo show "$wid";
diff --git a/scripts/bin/tmpmail b/scripts/bin/tmpmail
new file mode 100755
index 0000000..27b474a
--- /dev/null
+++ b/scripts/bin/tmpmail
@@ -0,0 +1,293 @@
+#!/usr/bin/env bash
+#
+# by Siddharth Dushantha 2020
+#
+# Dependencies: jq, curl, w3m
+#
+
+export LC_CTYPE=C
+export LANG=C
+
+VERSION=1.0.0
+
+# By default 'tmpmail' uses 'w3m' as it's web browser to render
+# the HTML of the email
+BROWSER="w3m"
+
+# If the value is set to 'true' tmpmail will convert the HTML email
+# to raw text and send that to stdout
+RAW_TEXT=false
+
+# Everything related to 'tmpmail' will be stored in /tmp/tmpmail
+# so that the old emails and email addresses get cleared after
+# restarting the computer
+TMPMAIL_DIR="/tmp/tmpmail/"
+
+# TMPMAIL_EMAIL_ADDRESS is where we store the temporary email address
+# that gets generated. This prevents the user from providing
+# the email address everytime they run tmpmail
+TMPMAIL_EMAIL_ADDRESS="$TMPMAIL_DIR/email_address"
+TMPMAIL_HTML_EMAIL="$TMPMAIL_DIR/tmpmail.html"
+
+
+usage(){
+ # Using 'cat << EOF' we can easily output a multiline text. This is much
+ # better than using 'echo' for each line or using '\n' to create a new line.
+ cat << EOF
+usage: tmpmail [-h] [--generate] [--browser BROWSER] [--recent] ID
+
+optional arguments:
+-h, --help Show this help message
+ --version Print version
+-g, --generate Generate a new email address
+-r, --recent View the most recent email
+-t, --text View the email as raw text, where all the HTML tags are removed
+-b, --browser Change the browser that is used to render the HTML of the email (default: w3m)
+EOF
+}
+
+
+generate_email_address(){
+ # There are 2 ways which this function is called in this script.
+ # [1] The user wants to generate a new email and runs 'tmpmail --generate'
+ # [2] The user runs 'tmpmail' to check the inbox , but /tmp/tmpmail/email_address
+ # is empty or nonexistant. Therefore a new email gets automatically
+ # generated before showing the inbox. But of course the inbox will
+ # be empty as the newly generated email address has not been
+ # sent any emails.
+ #
+ # When the function 'generate_email()' is called with the arguement
+ # 'true', it means that the function was called because the user
+ # ran 'tmpmail --generate'.
+ #
+ # We need this variable so we can know whether or not we need to show the user
+ # what the email was. <-- More about this can be found further down in this function.
+ EXTERNALLY=${1:-false}
+
+ # Generate a random email address.
+ # This function is called whenever the user wants to generate a new email
+ # address by running 'tmpmail --generate' or when the user runs 'tmpmail'
+ # but /tmp/tmpmail/email_address is empty or nonexistent.
+ #
+ # We create a random username by taking the first 10 lines from /dev/random
+ # and delete all the characters which are *not* lower case letters from A to Z.
+ # So charcters such as dashes, periods, underscore, and numbers are all deleted,
+ # giving us a text which only contains lower case letters form A to Z. We then take
+ # the first 10 characters, which will be the username of the email address
+ USERNAME=$(head /dev/urandom | tr -dc a-z | cut -c1-11)
+
+ # This is an array of the valid TLDS which 1secmail provides.
+ TLDS=(com net org)
+
+ # Randomly pick one of the TLDS mentiond above.
+ # This is done by first echoing all the TLDS into 'tr' which then
+ # replaces the white spaces with a new line. This is done because we use
+ # 'sort' to put the TLDS in a random order, but 'sort' requires the TLDS to
+ # be on seperate lines. After the randomizing is done we take the first line
+ # which is one of the TLDS
+ TLD=$(echo "${TLDS[@]}" | tr " " "\n" | sort -R | head -n 1)
+
+ # Save the generated email address to the $TMPMAIL_EMAIL_ADDRESS file
+ # so that it can be whenever 'tmpmail' is run
+ echo "$USERNAME@1secmail.$TLD" > "$TMPMAIL_EMAIL_ADDRESS"
+
+ # If this function was called because the user wanted to generate a new
+ # email address, show them the email address
+ [ "$EXTERNALLY" = true ] && cat "$TMPMAIL_EMAIL_ADDRESS"
+}
+
+
+get_email_address(){
+ # This function is only called once and that is when this script
+ # get executed. The output of this function gets stored in $EMAIL_ADDRESS
+ #
+ # If the file that contains the email address is empty,
+ # that means we do not have an email address, so generate one.
+ [ ! -s "$TMPMAIL_EMAIL_ADDRESS" ] && generate_email_address
+
+ # Output the email address by getting the first line of $TMPMAIL_EMAIL
+ head -n 1 "$TMPMAIL_EMAIL_ADDRESS"
+}
+
+
+list_emails(){
+ # List all the received emails in a nicely formatted order
+ #
+ # Fetch the email data using 1secmail's API
+ DATA=$(curl -sL "http://1secmail.$TLD/api/v1/?action=getMessages&login=$USERNAME&domain=1secmail.$TLD")
+
+ # Using 'jq' we get the length of the JSON data. From this we can determine whether or not
+ # the email address has gotten any emails
+ DATA_LENGTH=$(jq length <<< "$DATA")
+
+ # We are showing what email address is currently being used
+ # in case the user has forgotten what the email address was.
+ echo -e "[ Inbox for $EMAIL_ADDRESS ]\n"
+
+ # If the length of the data we got is 0, that means the email address
+ # has not received any emails yet.
+ [ "$DATA_LENGTH" -eq 0 ] && echo "No new mail" && exit
+
+ # This is where we store all of our emails, which is then
+ # displayed using 'column'
+ INBOX=""
+
+ # This for loop goes through each mail that have been received.
+ #
+ # Since we need to go through all the data, we need to tell our for loop
+ # to loop from 1 to X, where X is legnth of the $DATA which contains all
+ # the emails.
+ #
+ # Normally to loop from 1 to 5, we would use shell expansion and write:
+ # for index in {1..5}; do
+ # do_something
+ # done
+ #
+ # But we a minor issue. We dont know what the final number is, and we are not allowed
+ # use to variables in shell expansions like this:
+ # {1..$X}
+ #
+ # where $X is the length of the $DATA.
+ #
+ # To fix this issue, we can use 'seq' which will allow us to create a sequence
+ # from X to Y.
+ # Example:
+ # $ seq 1 5
+ # 1
+ # 2
+ # 3
+ # 4
+ # 5
+ #
+ # We can then put those results into the foor loop
+ for index in $(seq 1 "$DATA_LENGTH"); do
+ # Since arrays in JSON data start at 0, we must subtract
+ # the value of $index by 1 so that we dont miss one of the
+ # emails in the array
+ MAIL_DATA=$(jq -r ".[$index-1]" <<< "$DATA")
+
+ ID=$(jq -r ".id" <<< "$MAIL_DATA")
+ FROM=$(jq -r ".from" <<< "$MAIL_DATA")
+ SUBJECT=$(jq -r ".subject" <<< "$MAIL_DATA")
+
+ # The '||' are used as a divideder for 'column'. 'column' will use this divider as
+ # a point of reference to create the division. By default 'column' uses a blank space
+ # but that would not work in our case as the email subject could have multiple white spaces
+ # and 'column' would split the words that are seperated by white space, in different columns.
+ #
+ # Yes, there a double quote all by it self on the line under this one.
+ # This serves as a new line. So that the 'column' command works properly.
+ # I know I could have used '\n' but 'column' does not intepret it as a new line.
+ INBOX+="$ID ||$FROM ||$SUBJECT
+"
+ done
+
+ # Show the emails cleanly
+ column -t -s "||" <<< "$INBOX"
+}
+
+
+view_email(){
+ # View an email by providing it's ID
+ #
+ # The first argument provided to this function will be the ID of the email
+ # that has been received
+ EMAIL_ID="$1"
+ DATA=$(curl -sL "http://www.1secmail.$TLD/api/v1/?action=readMessage&login=$USERNAME&domain=1secmail.$TLD&id=$EMAIL_ID")
+
+ # After the data is retrieved using the API, we have to check if we got any emails.
+ # Luckly 1secmail's API is not complicated and returns 'Message not found' as plain text
+ # if our email address as not received any emails.
+ # If we the error message from the API just quit because there is nothing to do
+ [[ "$DATA" == "Message not found" ]] && echo "Message not found" && exit 1
+
+ # We pass the $DATA to 'jq' which extracts the values
+ FROM=$(jq -r ".from" <<< "$DATA")
+ SUBJECT=$(jq -r ".subject" <<< "$DATA")
+ HTML_BODY=$(jq -r ".htmlBody" <<< "$DATA")
+
+ # Create the HTML with all the information that is relevant and then
+ # assigning that HTML to the variable HTML_MAIL. This is the best method
+ # to create a multiline variable
+ read -r -d '' HTML_MAIL << EOF
+<pre><b>To: </b>$EMAIL_ADDRESS
+<b>From: </b>$FROM
+<b>Subject: </b>$SUBJECT</pre>
+$HTML_BODY
+EOF
+ # Save the $HTML_MAIL into $TMPMAIL_HTML_EMAIL
+ echo "$HTML_MAIL" > "$TMPMAIL_HTML_EMAIL"
+
+ # If the '--text' flag is used, then use 'w3m' to convert the HTML of
+ # the email to pure text by removing all the HTML tags
+ [ "$RAW_TEXT" = true ] && w3m -dump "$TMPMAIL_HTML_EMAIL" && exit
+
+ # Open up the HTML file using $BROWSER. By default,
+ # this will be 'w3m'.
+ $BROWSER "$TMPMAIL_HTML_EMAIL"
+
+}
+
+
+view_recent_email(){
+ # View the most recent email.
+ #
+ # This is done by listing all the received email like you
+ # normally see on the terminal when running 'tmpmail'.
+ # We then use 'awk' to grab the ID of the most recent
+ # email, which the first line.
+ MAIL_ID=$(list_emails | awk 'NR==3{print $1}')
+ view_email "$MAIL_ID"
+}
+
+
+main(){
+ # Iterate of the array of dependencies and check if the user has them installed
+ dependencies=(jq w3m curl)
+ for dependency in "${dependencies[@]}"; do
+ type -p "$dependency" &>/dev/null || {
+ echo "error: Could not find '${dependency}', is it installed?" >&2
+ exit 1
+ }
+ done
+
+ # Create the $TMPMAIL_DIR directory and dont throw any errors
+ # if it already exists
+ mkdir -p "$TMPMAIL_DIR"
+
+ # Get the email address and save the value to the EMAIL_ADDRESS variable
+ EMAIL_ADDRESS="$(get_email_address)"
+
+ # ${VAR#PATTERN} Removes shortest match of pattern from start of a string.
+ # In this case, it takes the EMAIL_ADDRESS and removed everything after
+ # the '@' symbol which gives us the username.
+ USERNAME=${EMAIL_ADDRESS%@*}
+
+ # ${VAR%PATTERN} Remove shortest match of pattern from end of a string.
+ # In this case, it takes the EMAIL_ADDRESS and removes everything until the
+ # period '.' which gives us the TLD
+ TLD=${EMAIL_ADDRESS#*.}
+
+ # If no arguments are provided just the emails
+ [[ $# -eq 0 ]] && list_emails && exit
+
+ while [[ "$1" ]]; do
+ case "$1" in
+ --help|-h) usage && exit ;;
+ --generate|-g) generate_email_address true && exit;;
+ --browser|-b) BROWSER="$2" ;;
+ --text|-t) RAW_TEXT=true ;;
+ --version) echo "$VERSION" && exit;;
+ --recent|-r) view_recent_email && exit;;
+ # If the user provides number as an argument,
+ # assume its the ID of an email and try getting
+ # the email that belongs to the ID
+ *[0-9]*) view_email "$1" && exit;;
+ -*) echo "error: option $1 does not exist"
+ esac
+ shift
+ done
+}
+
+
+main "$@"
diff --git a/scripts/bin/torque b/scripts/bin/torque
new file mode 100755
index 0000000..b63b594
--- /dev/null
+++ b/scripts/bin/torque
@@ -0,0 +1,66 @@
+#!/usr/bin/env bash
+#
+# Torque - minimal tui for transmission-daemon.
+
+refresh() {
+ printf '\e[?7l\e[?25l\e[2J\e[H'
+ shopt -s checkwinsize; (:;:)
+ [[ -z "$LINES" ]] && read -r LINES COLUMNS < <(stty size)
+ ((j=(LINES-2)/3))
+}
+
+status() {
+ printf '\e[2m\e[%s;H%s\e[m' "$((LINES-1))" "$1"
+}
+
+get_torrents() {
+ IFS=$'\n' read -d "" -ra t < <(transmission-remote -l)
+ unset 't[0]' 't[-1]' 2>/dev/null
+
+ t=("${t[@]//[0-9] [a-z][a-z][a-z]?/.}")
+ t=("${t[@]//Up & Down/Active}")
+ t=("${t[@]//Downloading/Active}")
+ t=("${t[@]// None/0 MB}")
+
+ for((i=${k:=0};i<(j=j>${#t[@]}?${#t[@]}:j);i++));{ t_print "${t[i]/n\/a/0}";}
+ status "[s]tart [p]ause [r]emove [o]pen [j/k] [q]uit scroll ($j/${#t[@]})"$'\e[H'
+}
+
+t_print() {
+ IFS=" %" read -r num perc have unit _ up down _ stat name <<< "$1"
+
+ ((size=perc!=0?${have/.*}*100/perc:0,c=perc==100?33271340:31000000))
+
+ printf '\e[K\e[2m%s\e[m \e[1m\e[%s%b%s\e[m\n' \
+ "$num:" "${c:0:2}m" "\\u${c:2:4}\\${c:6}" "$name"
+ printf '\e[K\e7%s\e8\e[14C%s\e8\e[32C%s\e8\e[42C%s\e8\e[52C%s\n\e[K\n' \
+ " $stat: " "$have / $size $unit" "(${perc}%)" "⇣ $down" "⇡ $up"
+}
+
+prompt() {
+ send() { transmission-remote "$@" >/dev/null; }
+ status $'\e[B\e[?25h'
+
+ case "$1" in
+ s) read -rp "start torrent: #"; send -t "$REPLY" -s ;;
+ p) read -rp "pause torrent: #"; send -t "$REPLY" -S ;;
+ r) read -rp "remove torrent: #"; send -t "$REPLY" -r; k=0 ;;
+ o) read -rp "load magnet: "; send -a "$REPLY"; k=0 ;;
+ j) ((j==${#t[@]}))||((k=k>=j?k:++k,j=j<${#t[@]}?++j:j)) ;;
+ k) ((k==0))||((k=k<=j?k>0?--k:0:j,j=j>0?--j:j)) ;;
+ q) exit 0 ;;
+ esac
+
+ [[ "$1" =~ (j|k) ]] || refresh && printf '\e[?25l\e[H'
+}
+
+main() {
+ refresh
+
+ trap $'printf \e[?25h\e[?7h\e[999B' EXIT
+ trap 'refresh; k=0' SIGWINCH
+
+ for ((;;)); { get_torrents; read -rsN1 -t1 && prompt "$REPLY"; }
+}
+
+main
diff --git a/scripts/bin/tst b/scripts/bin/tst
new file mode 100755
index 0000000..bf2778d
--- /dev/null
+++ b/scripts/bin/tst
@@ -0,0 +1,3 @@
+#!/usr/bin/env bash
+
+tabbed -c -r 2 st -w '' "$@";
diff --git a/scripts/bin/upload-file b/scripts/bin/upload-file
new file mode 100755
index 0000000..c095e51
--- /dev/null
+++ b/scripts/bin/upload-file
@@ -0,0 +1,19 @@
+#!/usr/bin/env bash
+
+if [ $# -eq 0 ]; then
+ echo -e "No arguments specified. Usage:\necho transfer /tmp/test.md\ncat /tmp/test.md | transfer test.md";
+ return 1;
+fi
+
+tmpfile=$( mktemp -t transferXXX );
+
+if tty -s; then
+ basefile=$(basename "$1" | sed -e 's/[^a-zA-Z0-9._-]/-/g');
+ curl --progress-bar --upload-file "$1" "https://transfer.sh/$basefile" >> $tmpfile;
+else
+ curl --progress-bar --upload-file "-" "https://transfer.sh/$1" >> $tmpfile ;
+fi;
+
+cat $tmpfile;
+rm -f $tmpfile;
+
diff --git a/scripts/bin/vimv b/scripts/bin/vimv
new file mode 100755
index 0000000..3c78afb
--- /dev/null
+++ b/scripts/bin/vimv
@@ -0,0 +1,38 @@
+#!/bin/bash
+
+# Lists the current directory's files in Vim, so you can edit it and save to rename them
+# USAGE: vimv [file1 file2]
+# https://github.com/thameera/vimv
+
+declare -r FILENAMES_FILE="$(mktemp --tmpdir vimv.XXX)"
+
+trap '{ rm -f "${FILENAMES_FILE}" ; }' EXIT
+
+if [ $# -ne 0 ]; then
+ src=( "$@" )
+else
+ IFS=$'\r\n' GLOBIGNORE='*' command eval 'src=($(ls))'
+fi
+
+for ((i=0;i<${#src[@]};++i)); do
+ echo "${src[i]}" >> "${FILENAMES_FILE}"
+done
+
+${EDITOR:-vi} "${FILENAMES_FILE}"
+
+IFS=$'\r\n' GLOBIGNORE='*' command eval 'dest=($(cat "${FILENAMES_FILE}"))'
+
+count=0
+for ((i=0;i<${#src[@]};++i)); do
+ if [ "${src[i]}" != "${dest[i]}" ]; then
+ mkdir -p "`dirname "${dest[i]}"`"
+ if git ls-files --error-unmatch "${src[i]}" > /dev/null 2>&1; then
+ git mv "${src[i]}" "${dest[i]}"
+ else
+ mv "${src[i]}" "${dest[i]}"
+ fi
+ ((count++))
+ fi
+done
+
+echo "$count" files renamed.
diff --git a/scripts/bin/vman b/scripts/bin/vman
new file mode 100755
index 0000000..cb78e4d
--- /dev/null
+++ b/scripts/bin/vman
@@ -0,0 +1,3 @@
+#!/usr/bin/env bash
+
+man -f "$@" >/dev/null 2>&1 && nvim -R +":set ft=man" <(man "$@");
diff --git a/scripts/bin/web b/scripts/bin/web
new file mode 100755
index 0000000..958e844
--- /dev/null
+++ b/scripts/bin/web
@@ -0,0 +1,4 @@
+#!/usr/bin/env bash
+
+w3m -o imgdisplay=/usr/lib/w3m/w3mimgdisplay "$@";
+
diff --git a/scripts/bin/with_zsh b/scripts/bin/with_zsh
new file mode 100755
index 0000000..0da2d95
--- /dev/null
+++ b/scripts/bin/with_zsh
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+zsh -c "source ~/.zshrc && $@";
+