Files
dotfiles/.config/zsh/plugins/functionsPost.zsh
druckdev 253501a230 Add git-submodule-rm
Add function git-submodule-rm that deinits and removes a submodule from
a git repo.
2020-09-13 17:14:50 +02:00

440 lines
11 KiB
Bash
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## Author: druckdev
## Created: 2019-10-27 (originally 2019-08-28 as functions.zsh)
## change into dir and print accordingly
function cl() {
cd "$@" && ls
}
## Copy file and append .bkp extension
function bkp() {
for file in "$@"; do
cp -i "$file" "$file.bkp"
done
}
## Launches program and detaches it from the shell
function launch() {
# eval "$@" ## does not work with special characters?
launch_command="$1"
shift
$launch_command "$@" &>/dev/null & disown
}
## Compares two pdfs based on the result of pdftotext
function 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
function 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
function 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
}
## Send a message over telegram by using the -e flag
function msg() {
if [ $# -ge 2 ]; then
telegram-cli -W -e "msg $*" | grep -E "${${*/ /.*}//_/ }"
# | grep -E "$(echo "$*" | sed 's/ /.*/; s/_/ /g')"
else
printf "\033[1;31mPlease specify a contact and a message.\n\033[0m" >&2
fi
}
## Execute tg -e command but cuts of the uninteresting parts
function tg() {
tg="telegram-cli"
if [ "$1" = "-e" ]; then
shift
$tg -N -W -e "$@" | tail -n +9 | head -n -2
else
$tg -N -W "$@"
fi
}
## Encode and decode qr-codes
function qr() {
if [[ $# -eq 1 && -r "$1" ]]; then
zbarimg "$1"
else
qrencode "$@"
fi
}
## Edit config file
function conf() {
# default to vim if no editor is set
local CONF_EDITOR=${EDITOR:-vim}
# 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_EDITOR=( $(resolve -s $CONF_EDITOR) )
# 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 [ $? -ne 0 ]; then
printf "\033[1;31mFalling back to $HOME.\n\033[0m" >&2
CONF_DIR="$HOME"
fi
# open file with specified name if
if [ $# -gt 1 ]; then
if [ -r "$CONF_DIR/$2" ]; then
$CONF_EDITOR "$CONF_DIR/$2"
return 0
else
printf "\033[1;31mCould not find config file with that name.\n\033[0m" >&2
return 1
fi
fi
# possible config-file names + same in 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 [ -r "$CONF_DIR/$config" ]; then
$CONF_EDITOR "$CONF_DIR/$config"
return 0
elif [ -r "$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 [ -r "$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
function c() {
CONF_DIR="$(_get_config_dir $*)"
if [ $? -eq 0 ]; then
cd "$CONF_DIR"
else
printf "$CONF_DIR" >&2
return 1
fi
}
## Get config directory
function _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
function 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
function mangrep() {
mangrep_file="$1"
mangrep_pattern="$2"
shift
shift
man -P 'less -p "^ *'"${mangrep_pattern}\"" "$@" "${mangrep_file}"
unset mangrep_{file,pattern}
}
## Grep in zsh history file
function histgrep() {
grep "$@" "${HISTFILE:-$HOME/.zsh_history}"
}
function format() {
# TODO: respect manual changes made in meld
CLANG_FORMAT_FILE="$HOME/Projects/C/.clang.format"
FORMAT="{$(sed -E '/^\s*$/d' "$CLANG_FORMAT_FILE" | tr '\n' ',' | sed 's/,$//')}"
if [ $# -eq 1 ]; then
meld <(clang-format -style="$FORMAT" $1) $1
fi
echo -n "Are you happy? [yn] "
read yn
if [ $yn = "y" ]; then
clang-format -i -style="$FORMAT" $1
fi
}
function urlenc() {
python3 -c "from urllib import parse; print(parse.quote('$@'), end='')"
}
function urldec() {
python3 -c "from urllib import parse; print(parse.unquote('$@'), end='')"
}
glog() {
# Return if not in git repo
git rev-parse || return
# extendedglob is necessary for the expansion of the binds array
emulate -L zsh -o extendedglob
# One line format for fzf list view
# abbreviated commit hash (yellow), title and ref names
local formatshort='--pretty=format:%C(yellow)%h %Creset%s%C(auto)%d'
# Verbose format for the preview window on the right
# This array is stitched together with newlines later
local format=(
'--pretty=format:%C(yellow)' # newline created by this eaten by %-
'%-commit: %H%C(auto)' # yellow commit hash
'%-D%Cblue' # auto colored ref names (if any)
'Author: %aN %aE%Cred' # blue author mail
'AuthorDate: %ad%Cblue' # red author date
'Commit: %cN %cE%Cred' # blue commiter mail
'CommitDate: %cd%Creset%C(bold)' # red commit date
''
' %s%Creset' # bold white subject
' ' # space is here so that the empty line is not eaten when empty body
'%-b' # body
'--------------------------------------------------'
''
)
# Before being able to operate on the string itself we need to remove all
# ansi color escape sequences to not confuse sed. (see git show below)
local del_ansi='s/\[[0-9]{0,2}m//g'
# Ignore the graph part at the beginning, then capture the commit hash and
# throw away the rest of the line.
local commit_hash='s/^[ */\\|]*([a-z0-9]*).*$/\1/'
local dateshort='--date=format:%F' # year
local date='--date=format:%F %T %z' # year time timezone
local colors='--color=always'
local -A binds=(
'ctrl-space' 'toggle-preview'
'ctrl-alt-j' 'preview-down'
'ctrl-alt-k' 'preview-up'
)
local -a fzf_args=(
# Understand ansi color escape sequences
"--ansi"
# Expand the binds array in the format key1:value1,key2:value2
"--bind" "${(@kj:,:)binds/(#m)*/$MATCH:$binds[$MATCH]}"
# Execute git show on the commit as preview
"--preview" "
out=\"\$(echo {} | sed -Ee \"$del_ansi\" -e \"$commit_hash\")\"
if [ \"\$out\" ]; then
git show \"${(j:%n:)format}\" \"$date\" $colors \"\$out\"
fi
"
# Reverse the layout so that the newest commit is at the top
"--reverse"
)
# Display an ascii graph of the commits in the above format and pipe that
# into fzf.
commit="$(\
git log "$formatshort" --graph "$dateshort" "$colors" \
| fzf "${fzf_args[@]}"
)"
# If fzf exits successfully, put the abbreviated commit hash into the
# clipboard and write it into stdout.
if ! (( $? )); then
commit="$(sed -Ee "$del_ansi" -e "$commit_hash" <<<"$commit")"
if command -v xclip &>/dev/null; then
echo -n "$commit" | xclip -selection clip
fi
echo "$commit"
fi
}
git-submodule-rm() {
# Exit if not in git repo
local toplevel="$(git rev-parse --show-toplevel)" || return
# Exit if no arguements were given
[ $# -gt 0 ] || return
local separator=""
for arg in "$@"; do
printf "$separator"
# argument relative from git toplevel
local arg_from_git="${${arg:A}##$toplevel/}"
# argument has to exist
[ -e "$arg" ] || continue
# argument has to exist in repo
[ -e "$toplevel/$arg_from_git" ] || continue
# has to be a submodule
[ -e "$toplevel/.git/modules/$arg_from_git" ] || continue
git submodule deinit -f "$arg"
echo "command rm -rf \"$toplevel/.git/modules/$arg_from_git\""
command rm -rf "$toplevel/.git/modules/$arg_from_git"
git rm -f "$arg"
separator="\n"
done
}
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")"
}