Add a cd wrapper that when called without arguments, moves into the root of the current repository instead of HOME. (Except when already there)
343 lines
7.9 KiB
Bash
343 lines
7.9 KiB
Bash
## Author: druckdev
|
|
## Created: 2019-08-28
|
|
|
|
## Compares two pdfs based on the result of pdftotext
|
|
pdfdiff() {
|
|
if [[ $# -eq 2 && -r "$1" && -r "$2" ]]; then
|
|
diff <(pdftotext "$1" -) <(pdftotext "$2" -)
|
|
else
|
|
echo "something went wrong" 2>&1
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
## Gets Passwd from bitwarden and copies it into the clipboard
|
|
bwpwd() {
|
|
if bw "get" "password" "$@" >/dev/null; then
|
|
bw "get" "password" "$@" | tr -d '\n' | setclip
|
|
else
|
|
bw "get" "password" "$@"
|
|
fi
|
|
}
|
|
|
|
## creates directory and changes into it
|
|
mkcd () {
|
|
# Create directory
|
|
mkdir "$@"
|
|
# shift arguments if mkdir options were used
|
|
while [[ $# -gt 1 ]]; do
|
|
shift
|
|
done
|
|
if [[ -d "$1" ]]; then
|
|
cd "$1"
|
|
pwd
|
|
fi
|
|
}
|
|
|
|
## Encode and decode qr-codes
|
|
qr() {
|
|
if [[ $# -eq 1 && -r "$1" ]]; then
|
|
zbarimg "$1"
|
|
else
|
|
qrencode "$@"
|
|
fi
|
|
}
|
|
|
|
## Edit config file
|
|
conf() {
|
|
local CONF_EDITOR
|
|
if [[ -n "$EDITOR" ]]; then
|
|
CONF_EDITOR="$EDITOR"
|
|
elif command -v vim &>/dev/null; then
|
|
CONF_EDITOR=vim
|
|
elif command -v nano &>/dev/null; then
|
|
CONF_EDITOR=nano
|
|
else
|
|
CONF_EDITOR=cat
|
|
fi
|
|
|
|
# Parse otions
|
|
while getopts "e:" opt 2>/dev/null; do
|
|
case $opt in
|
|
e) CONF_EDITOR="$OPTARG";;
|
|
*) printf "\033[1;31mUsage: $0 [-e <editor>] <program>[/subdirs] [<config_file>]\n\033[0m" >&2
|
|
return 1 ;;
|
|
esac
|
|
done
|
|
shift $(( $OPTIND - 1 ))
|
|
|
|
# conf needs an argument
|
|
if [[ $# -eq 0 ]]; then
|
|
printf "\033[1;31mPlease specify a config.\n\033[0m" >&2
|
|
return 1
|
|
fi
|
|
# search for program name in XDG_CONFIG_HOME and $HOME
|
|
local CONF_DIR="$(_get_config_dir "$1")"
|
|
if (( $? )); then
|
|
printf "\033[1;31mFalling back to $HOME.\n\033[0m" >&2
|
|
CONF_DIR="$HOME"
|
|
fi
|
|
|
|
# If specific name is given, open file.
|
|
if [[ $# -gt 1 ]]; then
|
|
"$CONF_EDITOR" "$CONF_DIR/$2"
|
|
return
|
|
fi
|
|
|
|
# possible config-file names + same but hidden
|
|
local -a CONF_PATTERNS
|
|
CONF_PATTERNS=(
|
|
"$1.conf"
|
|
"$1.config"
|
|
"${1}rc"
|
|
"config"
|
|
"conf"
|
|
"$1.yml"
|
|
"$1.yaml"
|
|
"config.ini"
|
|
"$1"
|
|
)
|
|
|
|
# check if config file exists
|
|
for config in $CONF_PATTERNS; do
|
|
if [[ -e "$CONF_DIR/$config" ]]; then
|
|
$CONF_EDITOR "$CONF_DIR/$config"
|
|
return 0
|
|
elif [[ -e "$CONF_DIR/.$config" ]]; then
|
|
$CONF_EDITOR "$CONF_DIR/.$config"
|
|
return 0
|
|
fi
|
|
done
|
|
|
|
# if no config was found in a location other than HOME, look again in HOME.
|
|
# (For cases like default vim with ~/.vim/ and ~/.vimrc)
|
|
if [[ "$CONF_DIR" != "$HOME" ]];then
|
|
for config in $CONF_PATTERNS; do
|
|
# Only look for hidden files
|
|
if [[ -e "$HOME/.$config" ]]; then
|
|
$CONF_EDITOR "$HOME/.$config"
|
|
return 0
|
|
fi
|
|
done
|
|
fi
|
|
|
|
printf "\033[1;31mCould not find config file.\n\033[0m" >&2
|
|
return 1
|
|
}
|
|
|
|
## Change into config dir
|
|
c() {
|
|
CONF_DIR="$(_get_config_dir $*)"
|
|
if [[ $? -eq 0 ]]; then
|
|
cd "$CONF_DIR"
|
|
else
|
|
printf "$CONF_DIR" >&2
|
|
return 1
|
|
fi
|
|
}
|
|
## Get config directory
|
|
_get_config_dir() {
|
|
if [[ $# -gt 1 ]]; then
|
|
printf "\033[1;31mPlease specify one config.\n\033[0m" >&2
|
|
return 1
|
|
elif [[ $# -eq 0 ]]; then
|
|
echo "${XDG_CONFIG_HOME:-$HOME/.config}"
|
|
elif [[ -d "${XDG_CONFIG_HOME:-$HOME/.config}/$1" ]]; then
|
|
echo "${XDG_CONFIG_HOME:-$HOME/.config}/$1"
|
|
elif [[ -d "$HOME/.$1" ]]; then
|
|
echo "$HOME/.$1"
|
|
else
|
|
printf "\033[1;31mCould not find config home.\n\033[0m" >&2
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
## Function that resolves a command to the end
|
|
resolve() {
|
|
# TODO: comment!!
|
|
# In script mode only the result and its arguments are printed
|
|
# The result can then be used directly by other scripts without further
|
|
# manipulation
|
|
typeset SCRIPT_MODE VERBOSE_MODE 1>&2
|
|
while getopts "sv" opt 2>/dev/null; do
|
|
case $opt in
|
|
s) SCRIPT_MODE=1;;
|
|
v) VERBOSE_MODE=1;;
|
|
*) echo "Unknown flag!" >&2
|
|
return 1;;
|
|
esac
|
|
done
|
|
shift $(( $OPTIND - 1 ))
|
|
|
|
if (( $SCRIPT_MODE )) && (( $VERBOSE_MODE )); then
|
|
echo "Script and verbose mode do no work together." >&2
|
|
return 1
|
|
fi
|
|
|
|
typeset THIS THIS_COMMAND THIS_ARGUMENTS 1>&2
|
|
# When receiving a command with arguments, do not differ between
|
|
# one and multiple arguments.
|
|
THIS="$*"
|
|
THIS_COMMAND="${THIS%% *}"
|
|
# ${THIS%%* } would result in THIS_COMMAND when no arguements are specified.
|
|
# We want an empty string in this case.
|
|
THIS_ARGUMENTS="${THIS#${THIS_COMMAND}}"
|
|
|
|
# Resolve all aliases
|
|
while [[ "$(which $THIS_COMMAND | head -n1)" =~ "^${THIS_COMMAND}: aliased to " ]]; do
|
|
if (( $VERBOSE_MODE )); then
|
|
echo $THIS_COMMAND$THIS_ARGUMENTS
|
|
fi
|
|
THIS="$(which "$THIS_COMMAND" | cut -d' ' -f4-)"
|
|
THIS_COMMAND="${THIS%% *}"
|
|
THIS_ARGUMENTS="${THIS#${THIS_COMMAND}}$THIS_ARGUMENTS"
|
|
|
|
done
|
|
|
|
command_type="$(type $THIS_COMMAND)"
|
|
if [[ "$command_type" =~ "^$THIS_COMMAND is a shell function from " ]]; then
|
|
if (( $SCRIPT_MODE )); then
|
|
echo -n "$THIS_COMMAND$THIS_ARGUMENTS"
|
|
return 0
|
|
elif (( $VERBOSE_MODE )); then
|
|
echo "$THIS_COMMAND$THIS_ARGUMENTS"
|
|
else
|
|
echo "$* is resolved to:\n$THIS_COMMAND$THIS_ARGUMENTS"
|
|
fi
|
|
echo -n "${command_type}:"
|
|
from_file="$(echo $command_type | cut -d' ' -f7-)"
|
|
# from_file=${command_type##* }
|
|
grep -En -m1 "(function[ \t]+${THIS_COMMAND}[ \t]*(\(\)|)[ \t]*{|${THIS_COMMAND}[ \t]*\(\)[ \t]*{)" "$from_file" \
|
|
| cut -d: -f1
|
|
else
|
|
if (( $VERBOSE_MODE )); then
|
|
echo "$THIS_COMMAND$THIS_ARGUMENTS"
|
|
fi
|
|
THIS_COMMAND="$(which $THIS_COMMAND)"
|
|
if [[ $? -ne 0 ]]; then
|
|
echo "${THIS_COMMAND%% *} not found." >&2
|
|
return 1
|
|
fi
|
|
if (( $VERBOSE_MODE )); then
|
|
echo -n "$THIS_COMMAND"
|
|
NEXT_STEP="$(file -bh $THIS_COMMAND | cut -d' ' -f4-)"
|
|
if [[ "${NEXT_STEP:0:1}" != '/' ]]; then
|
|
NEXT_STEP="${THIS_COMMAND%/*}/$NEXT_STEP"
|
|
fi
|
|
while [[ "$(file -bh $THIS_COMMAND)" =~ "^symbolic link to" && "$NEXT_STEP" != "$THIS_COMMAND" ]]; do
|
|
THIS_COMMAND=$NEXT_STEP
|
|
NEXT_STEP="$(file -bh $THIS_COMMAND | cut -d' ' -f4-)"
|
|
if [[ "${NEXT_STEP:0:1}" != '/' ]]; then
|
|
NEXT_STEP="${THIS_COMMAND%/*}/$NEXT_STEP"
|
|
fi
|
|
|
|
echo -n "\n$THIS_COMMAND"
|
|
done
|
|
echo $THIS_ARGUMENTS
|
|
return 0
|
|
fi
|
|
THIS_COMMAND="$(realpath $THIS_COMMAND)"
|
|
if (( $SCRIPT_MODE )); then
|
|
echo -n "$THIS_COMMAND$THIS_ARGUMENTS"
|
|
return 0
|
|
fi
|
|
echo "$* is resolved to:\n$THIS_COMMAND$THIS_ARGUMENTS"
|
|
fi
|
|
}
|
|
|
|
## Grep a keyword at the beginning of a line (ignoring whitespace) in a man page
|
|
mangrep() {
|
|
if [[ $# -lt 2 ]]; then
|
|
printf "usage: mangrep <man page> <pattern> [<man flags>]\n" >&2
|
|
printf "example: mangrep bash \"(declare|typeset)\"\n" >&2
|
|
return 1
|
|
fi
|
|
local page="$1" pattern="$2"
|
|
shift 2
|
|
man -P "less -p \"^ *${pattern}\"" "$@" "${file}"
|
|
}
|
|
|
|
safe-remove() {
|
|
[[ $# -gt 0 ]] || return 1
|
|
[[ -e "$1" ]] || return 1
|
|
|
|
sync
|
|
if ! udisksctl unmount -b "$1"; then
|
|
lsof "$1"
|
|
return 1
|
|
fi
|
|
udisksctl power-off -b "/dev/$(lsblk -no pkname "$1")"
|
|
}
|
|
|
|
crypt-mount() {
|
|
[[ $# -gt 0 ]] || return 1
|
|
[[ -e "$1" ]] || return 1
|
|
|
|
sudo cryptsetup open "$1" crypt_"${1##*/}" || return 1
|
|
udisksctl mount -b /dev/mapper/crypt_"${1##*/}"
|
|
}
|
|
|
|
crypt-umount() {
|
|
[[ $# -gt 0 ]] || return 1
|
|
[[ -e "$1" ]] || return 1
|
|
|
|
sync
|
|
if ! udisksctl unmount -b /dev/mapper/crypt_"${1##*/}"; then
|
|
lsof /dev/mapper/crypt_"${1##*/}"
|
|
return 1
|
|
fi
|
|
if ! sudo cryptsetup close crypt_"${1##*/}"; then
|
|
sudo cryptsetup status crypt_"${1##*/}"
|
|
return 1
|
|
fi
|
|
udisksctl power-off -b "$1"
|
|
}
|
|
|
|
## List items in trash if no argument is specified
|
|
trash() {
|
|
if (( ! $# )); then
|
|
command trash-list
|
|
else
|
|
command trash "$@"
|
|
fi
|
|
}
|
|
|
|
## Open nemo in current directory if no argument is specified
|
|
nemo() {
|
|
if (( ! $# )); then
|
|
command nemo .
|
|
else
|
|
command nemo "$@"
|
|
fi
|
|
}
|
|
|
|
## Move a file but keep a symlink to the new location.
|
|
mvln() {
|
|
# DST will not exist if `mv` is used for renaming.
|
|
[[ -e $1 ]] && [[ -d $2 || -d "$(dirname "$2")" ]] || return 1
|
|
|
|
mv "$1" "$2" || return
|
|
if [[ -d $2 ]]; then
|
|
ln -s "${2:A}/$(basename "$1")" "$1"
|
|
else
|
|
ln -s "${2:A}" "$1"
|
|
fi
|
|
}
|
|
|
|
## cd wrapper that when called without arguments, moves into the root of the
|
|
## current repo instead of HOME. (Except when already there)
|
|
cd() {
|
|
if [[ $# -gt 0 ]]; then
|
|
builtin cd "$@"
|
|
return
|
|
fi
|
|
|
|
local toplevel
|
|
toplevel="$(git rev-parse --show-toplevel 2>/dev/null)"
|
|
if (( $? )) || [[ $PWD = $toplevel ]]; then
|
|
builtin cd
|
|
else
|
|
builtin cd "$toplevel"
|
|
fi
|
|
}
|