aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.config/zsh/user/aliases.zsh85
-rw-r--r--.config/zsh/user/bindings.zsh39
-rw-r--r--.config/zsh/user/completion.zsh157
-rw-r--r--.config/zsh/user/functions.zsh780
-rw-r--r--.config/zsh/user/options.zsh50
-rw-r--r--.config/zsh/user/prompt.zsh202
6 files changed, 1313 insertions, 0 deletions
diff --git a/.config/zsh/user/aliases.zsh b/.config/zsh/user/aliases.zsh
new file mode 100644
index 0000000..48ea618
--- /dev/null
+++ b/.config/zsh/user/aliases.zsh
@@ -0,0 +1,85 @@
+########## Aliases ##########
+
+### Dotfiles
+alias config='git --git-dir=$HOME/.cfg --work-tree=$HOME'
+cfg_files=$(config ls-tree --name-only -r HEAD)
+
+export CFG_FILES="$cfg_files"
+
+# Define alias for nvim/vim (fallback to vim)
+if command -v nvim > /dev/null; then
+ alias vi='nvim'
+else
+ alias vi='vim'
+fi
+
+# Confirmation #
+alias mv='mv -i'
+alias cp='cp -i'
+alias ln='ln -i'
+
+# Disable 'rm'
+alias rm='function _rm() { echo -e "\033[0;31mrm\033[0m is disabled, use \033[0;32mtrash\033[0m or \033[0;32mdel \033[0m\033[0;33m$1\033[0m"; }; _rm'
+alias del='/bin/rm'
+
+alias ls='ls --color=auto --group-directories-first'
+alias lsd="lsd --group-directories-first"
+alias grep='grep --colour=auto'
+alias egrep='egrep --colour=auto'
+alias fgrep='fgrep --colour=auto'
+
+# List upto last 10 visited directories using "d" and quickly cd into any specific one
+alias d="dirs -v | head -10"
+
+# Using just a number from "0" to "9"
+alias 0="cd +0"
+alias 1="cd +1"
+alias 2="cd +2"
+alias 3="cd +3"
+alias 4="cd +4"
+alias 5="cd +5"
+alias 6="cd +6"
+alias 7="cd +7"
+alias 8="cd +8"
+alias 9="cd +9"
+
+alias sudo='sudo ' # zsh: elligible for alias expansion/fix syntax highlight
+alias sedit='sudoedit'
+alias se='sudoedit'
+
+alias sc="systemctl"
+alias jc="journalctl xe"
+#alias suspend='systemctl suspend && betterlockscreen -l' # Suspend(sleep) and lock screen if using systemctl
+alias suspend='systemctl suspend' # Suspend(sleep) and lock screen if using systemctl
+alias hibernate='systemctl hibernate' # Hibernate
+alias lock='DISPLAY=:0 xautolock -locknow' # Lock my workstation screen from my phone
+alias oports="sudo lsof -i -P -n | grep -i 'listen'" # List open ports
+alias keyname="xev | sed -n 's/[ ]*state.* \([^ ]*\)).*/\1/p'"
+alias wget=wget --hsts-file="$XDG_CACHE_HOME/wget-hsts" # wget does not support environment variables
+alias pp='getlast 2>&1 |&tee -a output.txt'
+alias lg='la | grep'
+alias pg='ps aux | grep'
+alias py='python'
+alias py3='python3'
+alias sha256='shasum -a 256'
+alias rgf='rg -F'
+alias weather='curl wttr.in/durban'
+alias wifi='nmcli dev wifi show-password'
+alias ddg='w3m lite.duckduckgo.com'
+alias rss='newsboat'
+alias vpn='protonvpn'
+alias yt-dl="yt-dlp -f 'bestvideo[ext=mp4]+bestaudio[ext=m4a]/mp4' --restrict-filename"
+
+# Time aliases
+alias utc='TZ=Africa/Johannesburg date'
+alias ber='TZ=Europe/Berlin date'
+alias nyc='TZ=America/New_York date'
+alias sfo='TZ=America/Los_Angeles date'
+alias utc='TZ=Etc/UTC date'
+
+alias src='source ~/.zshrc'
+alias p=proxy
+
+alias cheat='~/.scripts/cheat.sh ~/documents/notes/cheatsheets'
+# Alias for android-studio
+alias android-studio='/opt/android-studio/bin/studio.sh'
diff --git a/.config/zsh/user/bindings.zsh b/.config/zsh/user/bindings.zsh
new file mode 100644
index 0000000..ce8451b
--- /dev/null
+++ b/.config/zsh/user/bindings.zsh
@@ -0,0 +1,39 @@
+########## Vi mode ##########
+bindkey -v
+#bindkey -M viins '^?' backward-delete-char
+#local WORDCHARS='*?_-.[]~=&;!#$%^(){}<>'
+backward-kill-dir () {
+ local WORDCHARS=${WORDCHARS/\/}
+ zle backward-kill-word
+ zle -f kill
+}
+zle -N backward-kill-dir
+bindkey '^[^?' backward-kill-dir
+bindkey "^W" backward-kill-dir
+bindkey -M viins '^[[3~' delete-char
+bindkey -M vicmd '^[[3~' delete-char
+bindkey -v '^?' backward-delete-char
+bindkey -r '\e/'
+bindkey -s jk '\e'
+#bindkey "^W" backward-kill-word
+bindkey "^H" backward-delete-char # Control-h also deletes the previous char
+bindkey "^U" backward-kill-line
+bindkey "^[j" history-search-forward # or you can bind it to the down key "^[[B"
+bindkey "^[k" history-search-backward # or you can bind it to Up key "^[[A"
+
+# Define the 'autosuggest-execute' and 'autosuggest-accept' ZLE widgets
+autoload -Uz autosuggest-execute autosuggest-accept
+zle -N autosuggest-execute
+zle -N autosuggest-accept
+bindkey '^X' autosuggest-execute
+bindkey '^Y' autosuggest-accept
+
+# Edit line in vim with alt-e
+autoload edit-command-line; zle -N edit-command-line
+bindkey '^e' edit-command-line
+bindkey '^[e' edit-command-line # alt + e
+
+# Allow CTRL+D to exit zsh with partial command line (non empty line)
+exit_zsh() { exit }
+zle -N exit_zsh
+bindkey '^D' exit_zsh
diff --git a/.config/zsh/user/completion.zsh b/.config/zsh/user/completion.zsh
new file mode 100644
index 0000000..7837a04
--- /dev/null
+++ b/.config/zsh/user/completion.zsh
@@ -0,0 +1,157 @@
+#!/bin/zsh
+
+########## Completion(s) ##########
+
+autoload -Uz compinit
+_comp_path="${XDG_CACHE_HOME:-$HOME/.cache}/zcompdump"
+
+# Expands globs in conditional expressions
+if [[ $_comp_path(#qNmh-20) ]]; then
+ # -C (skip function check) implies -i (skip security check).
+ compinit -C -d "$_comp_path"
+else
+ mkdir -p "$_comp_path:h"
+ compinit -i -d "$_comp_path"
+ # Keep $_comp_path younger than cache time even if it isn't regenerated.
+ touch "$_comp_path"
+fi
+unset _comp_path
+
+# Accept completion with <tab> or Ctrl+i and go to next/previous suggestions with Vi like keys: Ctrl+n/p
+zmodload -i zsh/complist
+accept-and-complete-next-history() {
+ zle expand-or-complete-prefix
+}
+zle -N accept-and-complete-next-history
+bindkey -M menuselect '^i' accept-and-complete-next-history
+bindkey '^n' expand-or-complete
+bindkey '^p' reverse-menu-complete
+bindkey -M menuselect '^[' undo
+
+#zstyle ':completion:*' menu select=1
+#zstyle ':completion:*:directory-stack' list-colors '=(#b) #([0-9]#)*( *)==95=38;5;12'
+
+# Options
+setopt COMPLETE_IN_WORD # Complete from both ends of a word.
+setopt ALWAYS_TO_END # Move cursor to the end of a completed word.
+setopt PATH_DIRS # Perform path search even on command names with slashes.
+setopt AUTO_MENU # Show completion menu on a successive tab press.
+setopt AUTO_LIST # Automatically list choices on ambiguous completion.
+setopt AUTO_PARAM_SLASH # If completed parameter is a directory, add a trailing slash.
+setopt EXTENDED_GLOB # Needed for file modification glob modifiers with compinit.
+unsetopt MENU_COMPLETE # Do not autoselect the first completion entry.
+unsetopt FLOW_CONTROL # Disable start/stop characters in shell editor.
+
+# Variables
+LS_COLORS=${LS_COLORS:-'di=34:ln=35:so=32:pi=33:ex=31:bd=36;01:cd=33;01:su=31;40;07:sg=36;40;07:tw=32;40;07:ow=33;40;07:'}
+
+# Styles
+# Defaults.
+zstyle ':completion:*:default' list-colors ${(s.:.)LS_COLORS}
+zstyle ':completion:*:default' list-prompt '%S%M matches%s'
+
+# Use caching to make completion for commands such as dpkg and apt usable.
+zstyle ':completion::complete:*' use-cache on
+zstyle ':completion::complete:*' cache-path "${XDG_CACHE_HOME:-$HOME/.cache}/zcompcache"
+
+
+# Group matches and describe.
+zstyle ':completion:*:*:*:*:*' menu select
+zstyle ':completion:*:matches' group 'yes'
+zstyle ':completion:*:options' description 'yes'
+zstyle ':completion:*:options' auto-description '%d'
+zstyle ':completion:*:corrections' format ' %F{green}-- %d (errors: %e) --%f'
+zstyle ':completion:*:descriptions' format ' %F{yellow}-- %d --%f'
+zstyle ':completion:*:messages' format ' %F{purple} -- %d --%f'
+zstyle ':completion:*:warnings' format ' %F{red}-- no matches found --%f'
+zstyle ':completion:*' format ' %F{yellow}-- %d --%f'
+zstyle ':completion:*' group-name ''
+zstyle ':completion:*' verbose yes
+
+# Fuzzy match mistyped completions.
+zstyle ':completion:*' completer _complete _match _approximate
+zstyle ':completion:*:match:*' original only
+zstyle ':completion:*:approximate:*' max-errors 1 numeric
+
+# Increase the number of errors based on the length of the typed word. But make
+# sure to cap (at 7) the max-errors to avoid hanging.
+zstyle -e ':completion:*:approximate:*' max-errors 'reply=($((($#PREFIX+$#SUFFIX)/3>7?7:($#PREFIX+$#SUFFIX)/3))numeric)'
+
+# Don't complete unavailable commands.
+zstyle ':completion:*:functions' ignored-patterns '(_*|pre(cmd|exec))'
+
+# Array completion element sorting.
+zstyle ':completion:*:*:-subscript-:*' tag-order indexes parameters
+
+# Directories
+zstyle ':completion:*:*:cd:*' tag-order local-directories directory-stack path-directories
+zstyle ':completion:*:*:cd:*:directory-stack' menu yes select
+zstyle ':completion:*:-tilde-:*' group-order 'named-directories' 'path-directories' 'users' 'expand'
+zstyle ':completion:*' squeeze-slashes true
+
+# History
+zstyle ':completion:*:history-words' stop yes
+zstyle ':completion:*:history-words' remove-all-dups yes
+zstyle ':completion:*:history-words' list false
+zstyle ':completion:*:history-words' menu yes
+
+# Environment Variables
+zstyle ':completion::*:(-command-|export):*' fake-parameters ${${${_comps[(I)-value-*]#*,}%%,*}:#-*-}
+
+# Populate hostname completion. But allow ignoring custom entries from static
+# */etc/hosts* which might be uninteresting.
+zstyle -a ':completion:*:hosts' etc-host-ignores '_etc_host_ignores'
+
+zstyle -e ':completion:*:hosts' hosts 'reply=(
+ ${=${=${=${${(f)"$(cat {/etc/ssh/ssh_,~/.ssh/}known_hosts(|2)(N) 2> /dev/null)"}%%[#| ]*}//\]:[0-9]*/ }//,/ }//\[/ }
+ ${=${(f)"$(cat /etc/hosts(|)(N) <<(ypcat hosts 2> /dev/null))"}%%(\#${_etc_host_ignores:+|${(j:|:)~_etc_host_ignores}})*}
+ ${=${${${${(@M)${(f)"$(cat ~/.ssh/config 2> /dev/null)"}:#Host *}#Host }:#*\**}:#*\?*}}
+)'
+
+# Don't complete uninteresting users...
+zstyle ':completion:*:*:*:users' ignored-patterns \
+ adm amanda apache avahi beaglidx bin cacti canna clamav daemon \
+ dbus distcache dovecot fax ftp games gdm gkrellmd gopher \
+ hacluster haldaemon halt hsqldb ident junkbust ldap lp mail \
+ mailman mailnull mldonkey mysql nagios \
+ named netdump news nfsnobody nobody nscd ntp nut nx openvpn \
+ operator pcap postfix postgres privoxy pulse pvm quagga radvd \
+ rpc rpcuser rpm shutdown squid sshd sync uucp vcsa xfs '_*'
+
+# ... unless we really want to.
+zstyle '*' single-ignored show
+
+# Ignore multiple entries.
+zstyle ':completion:*:(rm|kill|diff):*' ignore-line other
+zstyle ':completion:*:rm:*' file-patterns '*:all-files'
+
+# Kill
+zstyle ':completion:*:*:*:*:processes' command 'ps -u $LOGNAME -o pid,user,command -w'
+zstyle ':completion:*:*:kill:*:processes' list-colors '=(#b) #([0-9]#) ([0-9a-z-]#)*=01;36=0=01'
+zstyle ':completion:*:*:kill:*' menu yes select
+zstyle ':completion:*:*:kill:*' force-list always
+zstyle ':completion:*:*:kill:*' insert-ids single
+
+# Man
+zstyle ':completion:*:manuals' separate-sections true
+zstyle ':completion:*:manuals.(^1*)' insert-sections true
+
+# Media Players
+zstyle ':completion:*:*:mpg123:*' file-patterns '*.(mp3|MP3):mp3\ files *(-/):directories'
+zstyle ':completion:*:*:mpg321:*' file-patterns '*.(mp3|MP3):mp3\ files *(-/):directories'
+zstyle ':completion:*:*:ogg123:*' file-patterns '*.(ogg|OGG|flac):ogg\ files *(-/):directories'
+zstyle ':completion:*:*:mocp:*' file-patterns '*.(wav|WAV|mp3|MP3|ogg|OGG|flac):ogg\ files *(-/):directories'
+
+# Mutt
+if [[ -s "$HOME/.mutt/aliases" ]]; then
+ zstyle ':completion:*:*:mutt:*' menu yes select
+ zstyle ':completion:*:mutt:*' users ${${${(f)"$(<"$HOME/.mutt/aliases")"}#alias[[:space:]]}%%[[:space:]]*}
+fi
+
+# SSH/SCP/RSYNC
+zstyle ':completion:*:(ssh|scp|rsync):*' tag-order 'hosts:-host:host hosts:-domain:domain hosts:-ipaddr:ip\ address *'
+zstyle ':completion:*:(scp|rsync):*' group-order users files all-files hosts-domain hosts-host hosts-ipaddr
+zstyle ':completion:*:ssh:*' group-order users hosts-domain hosts-host users hosts-ipaddr
+zstyle ':completion:*:(ssh|scp|rsync):*:hosts-host' ignored-patterns '*(.|:)*' loopback ip6-loopback localhost ip6-localhost broadcasthost
+zstyle ':completion:*:(ssh|scp|rsync):*:hosts-domain' ignored-patterns '<->.<->.<->.<->' '^[-[:alnum:]]##(.[-[:alnum:]]##)##' '*@*'
+zstyle ':completion:*:(ssh|scp|rsync):*:hosts-ipaddr' ignored-patterns '^(<->.<->.<->.<->|(|::)([[:xdigit:].]##:(#c,2))##(|%*))' '127.0.0.<->' '255.255.255.255' '::1' 'fe80::*'
diff --git a/.config/zsh/user/functions.zsh b/.config/zsh/user/functions.zsh
new file mode 100644
index 0000000..eea66c7
--- /dev/null
+++ b/.config/zsh/user/functions.zsh
@@ -0,0 +1,780 @@
+
+# Set bare dotfiles repository git environment variables dynamically
+function set_git_env_vars() {
+ # Check if the current command is a package manager command
+ if [[ "${(%)${(z)history[1]}}" =~ ^(pacman|yay|apt|dnf|brew|npm|pip|gem|go|cargo) ]]; then
+ return
+ fi
+ local git_dir="$(git rev-parse --git-dir -C . 2>/dev/null)"
+ if [[ -n "$git_dir" ]]; then
+ local is_bare="$(git -C "$git_dir" rev-parse --is-bare-repository 2>/dev/null)"
+ if [[ "$is_bare" == "true" ]]; then
+ export GIT_DIR="$HOME/.cfg"
+ export GIT_WORK_TREE=$(realpath $(eval echo ~))
+ else
+ unset GIT_DIR
+ unset GIT_WORK_TREE
+ fi
+ else
+ local root_dir="$(git rev-parse --show-toplevel 2>/dev/null)"
+ if [[ -n "$root_dir" ]]; then
+ unset GIT_DIR
+ export GIT_WORK_TREE="$root_dir"
+ else
+ export GIT_DIR="$HOME/.cfg"
+ export GIT_WORK_TREE=$(realpath $(eval echo ~))
+ fi
+ fi
+}
+
+# Define an auto_cd hook to automatically update Git environment variables
+function chpwd() {
+ set_git_env_vars
+}
+# Call the function to set Git environment variables when the shell starts up
+set_git_env_vars
+
+
+function gsp() {
+ # Config file for subtrees
+ #
+ # Format:
+ # <prefix>;<remote address>;<remote branch>
+ # # Lines starting with '#' will be ignored
+ GIT_SUBTREE_FILE="$PWD/.gitsubtrees"
+
+ if [ ! -f "$GIT_SUBTREE_FILE" ]; then
+ echo "Nothing to do - file <$GIT_SUBTREE_FILE> does not exist."
+ return
+ fi
+
+ if ! command -v config &> /dev/null; then
+ echo "Error: 'config' command not found. Make sure it's available in your PATH."
+ return
+ fi
+
+ OLD_IFS=$IFS
+ IFS=$'\n'
+ for LINE in $(cat "$GIT_SUBTREE_FILE"); do
+
+ # Skip lines starting with '#'.
+ if [[ $LINE = \#* ]]; then
+ continue
+ fi
+
+ # Parse the current line.
+ PREFIX=$(echo "$LINE" | cut -d';' -f 1)
+ REMOTE=$(echo "$LINE" | cut -d';' -f 2)
+ BRANCH=$(echo "$LINE" | cut -d';' -f 3)
+
+ # Pull from the remote.
+ echo "Executing: git subtree pull --prefix=$PREFIX $REMOTE $BRANCH"
+ if git subtree pull --prefix="$PREFIX" "$REMOTE" "$BRANCH"; then
+ echo "Subtree pull successful for $PREFIX."
+ else
+ echo "Error: Subtree pull failed for $PREFIX."
+ fi
+ done
+
+ IFS=$OLD_IFS
+}
+
+# Print previous command into a file
+getlast () {
+ fc -nl $((HISTCMD - 1))
+}
+
+# Enter directory and list contents
+cd() {
+ if [ -n "$1" ]; then
+ builtin cd "$@" && ls -pvA --color=auto --group-directories-first
+ else
+ builtin cd ~ && ls -pvA --color=auto --group-directories-first
+ fi
+}
+
+# cd using "up n" as a command up as many directories, example "up 3"
+up() {
+ # default parameter to 1 if non provided
+ declare -i d=${@:-1}
+ # ensure given parameter is non-negative. Print error and return if it is
+ (( $d < 0 )) && (>&2 echo "up: Error: negative value provided") && return 1;
+ # remove last d directories from pwd, append "/" in case result is empty
+ cd "$(pwd | sed -E 's;(/[^/]*){0,'$d'}$;;')/";
+}
+
+# cd into $XDG_CONFIG_HOME/$1 directory
+c() {
+ local root=${XDG_CONFIG_HOME:-~/.config}
+ local dname="$root/$1"
+ if [[ ! -d "$dname" ]]; then
+ return
+ fi
+ cd "$dname"
+}
+
+# Make and cd into directory and any parent directories
+mkcd () {
+ if [[ -z "$1" ]]; then
+ echo "Usage: mkcd <dir>" 1>&2
+ return 1
+ fi
+ mkdir -p "$1"
+ cd "$1"
+}
+back() {
+ for file in "$@"; do
+ cp "$file" "$file".bak
+ done
+}
+reposize() {
+ url=`echo $1 \
+ | perl -pe 's#(?:https?://github.com/)([\w\d.-]+\/[\w\d.-]+).*#\1#g' \
+ | perl -pe 's#git\@github.com:([\w\d.-]+\/[\w\d.-]+)\.git#\1#g'
+ `
+ printf "https://github.com/$url => "
+ curl -s https://api.github.com/repos/$url \
+ | jq '.size' \
+ | numfmt --to=iec --from-unit=1024
+}
+
+# Launch a program in a terminal without getting any output,
+# and detache the process from terminal
+# (can then close the terminal without terminating process)
+-echo() {
+ "$@" &> /dev/null & disown
+}
+
+# Reload shell
+function reload() {
+ local compdump_files="$ZDOTDIR/.zcompdump*"
+
+ if ls $compdump_files &> /dev/null; then
+ rm -f $compdump_files
+ fi
+
+ exec $SHELL -l
+}
+
+#pom() {
+# local -r HOURS=${1:?}
+# local -r MINUTES=${2:-0}
+# local -r POMODORO_DURATION=${3:-25}
+#
+# bc <<< "(($HOURS * 60) + $MINUTES) / $POMODORO_DURATION"
+#}
+
+#mnt() {
+# local FILE="/mnt/external"
+# if [ ! -z $2 ]; then
+# FILE=$2
+# fi
+#
+# if [ ! -z $1 ]; then
+# sudo mount "$1" "$FILE" -o rw
+# echo "Device in read/write mounted in $FILE"
+# fi
+#
+# if [ $# = 0 ]; then
+# echo "You need to provide the device (/dev/sd*) - use lsblk"
+# fi
+#}
+#
+#umnt() {
+# local DIRECTORY="/mnt"
+# if [ ! -z $1 ]; then
+# DIRECTORY=$1
+# fi
+# MOUNTED=$(grep $DIRECTORY /proc/mounts | cut -f2 -d" " | sort -r)
+# cd "/mnt"
+# sudo umount $MOUNTED
+# echo "$MOUNTED unmounted"
+#}
+
+mntmtp() {
+ local DIRECTORY="$HOME/mnt"
+ if [ ! -z $2 ]; then
+ local DIRECTORY=$2
+ fi
+ if [ ! -d $DIRECTORY ]; then
+ mkdir $DIRECTORY
+ fi
+
+ if [ ! -z $1 ]; then
+ simple-mtpfs --device "$1" "$DIRECTORY"
+ echo "MTPFS device in read/write mounted in $DIRECTORY"
+ fi
+
+ if [ $# = 0 ]; then
+ echo "You need to provide the device number - use simple-mtpfs -l"
+ fi
+}
+
+umntmtp() {
+ local DIRECTORY="$HOME/mnt"
+ if ; then
+ DIRECTORY=$1
+ fi
+ cd $HOME
+ umount $DIRECTORY
+ echo "$DIRECTORY with mtp filesystem unmounted"
+}
+duckduckgo() {
+ lynx -vikeys -accept_all_cookies "https://lite.duckduckgo.com/lite/?q=$@"
+}
+
+wikipedia() {
+ lynx -vikeys -accept_all_cookies "https://en.wikipedia.org/wiki?search=$@"
+}
+#function filesize() {
+# # Check if 'du' supports the -b option, which provides sizes in bytes.
+# if du -b /dev/null > /dev/null 2>&1; then
+# local arg=-sbh; # If supported, use -sbh options for 'du'.
+# else
+# local arg=-sh; # If not supported, use -sh options for 'du'.
+# fi
+#
+# # Check if no arguments are provided.
+# if [ "$#" -eq 0 ]; then
+# # Calculate and display sizes for all files and directories in cwd.
+# du $arg ./*
+# else
+# # Calculate and display sizes for the specified files and directories.
+# du $arg -- "$@"
+# fi
+#}
+#
+
+fgl() {
+ git log --graph --color=always \
+ --format="%C(auto)%h%d %s %C(black)%C(bold)%cr" "$@" |
+ fzf --ansi --no-sort --reverse --tiebreak=index --bind=ctrl-s:toggle-sort \
+ --bind "ctrl-m:execute:
+ (grep -o '[a-f0-9]\{7\}' | head -1 |
+ xargs -I % sh -c 'git show --color=always % | less -R') << 'FZF-EOF'
+ {}
+FZF-EOF"
+}
+
+fgb() {
+ local branches branch
+ branches=$(git --no-pager branch -vv) &&
+ branch=$(echo "$branches" | fzf +m) &&
+ git checkout $(echo "$branch" | awk '{print $1}' | sed "s/.* //")
+}
+
+# +--------+
+# | Pacman |
+# +--------+
+
+# TODO can improve that with a bind to switch to what was installed
+fpac() {
+ pacman -Slq | fzf --multi --reverse --preview 'pacman -Si {1}' | xargs -ro sudo pacman -S
+}
+
+fyay() {
+ yay -Slq | fzf --multi --reverse --preview 'yay -Si {1}' | xargs -ro yay -S
+}
+
+# +------+
+# | tmux |
+# +------+
+
+fmux() {
+ prj=$(find $XDG_CONFIG_HOME/tmuxp/ -execdir bash -c 'basename "${0%.*}"' {} ';' | sort | uniq | nl | fzf | cut -f 2)
+ echo $prj
+ [ -n "$prj" ] && tmuxp load $prj
+}
+
+# ftmuxp - propose every possible tmuxp session
+ftmuxp() {
+ if [[ -n $TMUX ]]; then
+ return
+ fi
+
+ # get the IDs
+ ID="$(ls $XDG_CONFIG_HOME/tmuxp | sed -e 's/\.yml$//')"
+ if [[ -z "$ID" ]]; then
+ tmux new-session
+ fi
+
+ create_new_session="Create New Session"
+
+ ID="${create_new_session}\n$ID"
+ ID="$(echo $ID | fzf | cut -d: -f1)"
+
+ if [[ "$ID" = "${create_new_session}" ]]; then
+ tmux new-session
+ elif [[ -n "$ID" ]]; then
+ # Change name of urxvt tab to session name
+ printf '\033]777;tabbedx;set_tab_name;%s\007' "$ID"
+ tmuxp load "$ID"
+ fi
+}
+
+# ftmux - help you choose tmux sessions
+ftmux() {
+ if [[ ! -n $TMUX ]]; then
+ # get the IDs
+ ID="`tmux list-sessions`"
+ if [[ -z "$ID" ]]; then
+ tmux new-session
+ fi
+ create_new_session="Create New Session"
+ ID="$ID\n${create_new_session}:"
+ ID="`echo $ID | fzf | cut -d: -f1`"
+ if [[ "$ID" = "${create_new_session}" ]]; then
+ tmux new-session
+ elif [[ -n "$ID" ]]; then
+ printf '\033]777;tabbedx;set_tab_name;%s\007' "$ID"
+ tmux attach-session -t "$ID"
+ else
+ : # Start terminal normally
+ fi
+ fi
+}
+
+# +-------+
+# | Other |
+# +-------+
+
+# List install files for dotfiles
+fdot() {
+ file=$(find "$DOTFILES/install" -exec basename {} ';' | sort | uniq | nl | fzf | cut -f 2)
+ [ -n "$file" ] && "$EDITOR" "$DOTFILES/install/$file"
+}
+
+# List projects
+fwork() {
+ result=$(find ~/workspace/* -type d -prune -exec basename {} ';' | sort | uniq | nl | fzf | cut -f 2)
+ [ -n "$result" ] && cd ~/workspace/$result
+}
+
+# Open pdf with Zathura
+fpdf() {
+ result=$(find -type f -name '*.pdf' | fzf --bind "ctrl-r:reload(find -type f -name '*.pdf')" --preview "pdftotext {} - | less")
+ [ -n "$result" ] && nohup zathura "$result" &> /dev/null & disown
+}
+
+# Open epubs with Zathura
+fepub() {
+ result=$(find -type f -name '*.epub' | fzf --bind "ctrl-r:reload(find -type f -name '*.epub')")
+ [ -n "$result" ] && nohup zathura "$result" &> /dev/null & disown
+}
+
+# Search and find directories in the dir stack
+fpop() {
+ # Only work with alias d defined as:
+
+ # alias d='dirs -v'
+ # for index ({1..9}) alias "$index"="cd +${index}"; unset index
+
+ d | fzf --height="20%" | cut -f 1 | source /dev/stdin
+}
+
+
+function ip() {
+ network=`current_networkservice`
+ networksetup -getinfo $network | grep '^IP address' | awk -F: '{print $2}' | sed 's/ //g'
+}
+
+ssh-create() {
+ if [ ! -z "$1" ]; then
+ ssh-keygen -f $HOME/.ssh/$1 -t rsa -N '' -C "$1"
+ chmod 700 $HOME/.ssh/$1*
+ fi
+}
+
+historystat() {
+ history 0 | awk '{print $2}' | sort | uniq -c | sort -n -r | head
+}
+
+promptspeed() {
+ for i in $(seq 1 10); do /usr/bin/time zsh -i -c exit; done
+}
+
+#matrix () {
+# local lines=$(tput lines)
+# cols=$(tput cols)
+#
+# awkscript='
+# {
+# letters="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@#$%^&*()"
+# lines=$1
+# random_col=$3
+# c=$4
+# letter=substr(letters,c,1)
+# cols[random_col]=0;
+# for (col in cols) {
+# line=cols[col];
+# cols[col]=cols[col]+1;
+# printf "\033[%s;%sH\033[2;32m%s", line, col, letter;
+# printf "\033[%s;%sH\033[1;37m%s\033[0;0H", cols[col], col, letter;
+# if (cols[col] >= lines) {
+# cols[col]=0;
+# }
+# }
+# }
+# '
+#
+# echo -e "\e[1;40m"
+# clear
+#
+# while :; do
+# echo $lines $cols $(( $RANDOM % $cols)) $(( $RANDOM % 72 ))
+# sleep 0.05
+# done | awk "$awkscript"
+#}
+
+matrix() {
+ local lines=$(tput lines)
+ cols=$(tput cols)
+
+ # Check if tmux is available
+ if command -v tmux > /dev/null; then
+ # Save the current status setting
+ local status_setting=$(tmux show -g -w -v status)
+
+ # Turn off tmux status
+ tmux set -g status off
+ else
+ echo "tmux is not available. Exiting."
+ return 1
+ fi
+
+ # Function to restore terminal state
+ restore_terminal() {
+ # Clear the screen
+ clear
+
+ # Bring back tmux status to its original setting
+ if command -v tmux > /dev/null; then
+ tmux set -g status "$status_setting"
+ fi
+ }
+
+ trap 'restore_terminal' INT
+
+ awkscript='
+ {
+ letters="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@#$%^&*()"
+ lines=$1
+ random_col=$3
+ c=$4
+ letter=substr(letters,c,1)
+ cols[random_col]=0;
+ for (col in cols) {
+ line=cols[col];
+ cols[col]=cols[col]+1;
+ printf "\033[%s;%sH\033[2;32m%s", line, col, letter;
+ printf "\033[%s;%sH\033[1;37m%s\033[0;0H", cols[col], col, letter;
+ if (cols[col] >= lines) {
+ cols[col]=0;
+ }
+ }
+ }
+ '
+
+ echo -e "\e[1;40m"
+ clear
+
+ while :; do
+ echo $lines $cols $(( $RANDOM % $cols)) $(( $RANDOM % 72 ))
+ sleep 0.05
+ done | awk "$awkscript"
+
+ # Restore terminal state
+ restore_terminal
+}
+# Follow this page to avoid enter password
+# http://apple.stackexchange.com/questions/236806/prevent-networksetup-from-asking-for-password
+function proxy() {
+ network=`current_networkservice`
+ if [ -z network ]; then
+ echo "Unrecognized network"
+ return 1
+ fi
+
+ case "$1" in
+ on)
+ networksetup -setwebproxystate $network on;
+ networksetup -setsecurewebproxystate $network on;
+ networksetup -setwebproxy $network 127.0.0.1 8888;
+ networksetup -setsecurewebproxy $network 127.0.0.1 8888;
+ networksetup -setautoproxystate $network off;
+ networksetup -setsocksfirewallproxystate $network off;
+ ;;
+ g)
+ networksetup -setwebproxystate $network off;
+ networksetup -setsecurewebproxystate $network off;
+ networksetup -setautoproxystate $network off;
+ networksetup -setsocksfirewallproxy "$network" localhost 14179
+ ;;
+ off)
+ networksetup -setwebproxystate $network off;
+ networksetup -setsecurewebproxystate $network off;
+ networksetup -setautoproxystate $network off;
+ networksetup -setsocksfirewallproxystate $network off;
+ ;;
+ s)
+ socks_status=$(networksetup -getsocksfirewallproxy $network | head -n 3;)
+ socks_enable=$(echo $socks_status | head -n 1 | awk '{print $2}')
+ socks_ip=$(echo $socks_status | head -n 2 | tail -n 1 | awk '{print $2}')
+ socks_port=$(echo $socks_status | tail -n 1 | awk '{print $2}')
+
+ if [ "$socks_enable" = "Yes" ]; then
+ echo -e "${green}Socks: ✔${NC}" $socks_ip ":" $socks_port
+ else
+ echo -e "${RED}Socks: ✘${NC}" $socks_ip ":" $socks_port
+ fi
+
+ http_status=$(networksetup -getwebproxy $network | head -n 3)
+ http_enable=$(echo $http_status | head -n 1 | awk '{print $2}')
+ http_ip=$(echo $http_status | head -n 2 | tail -n 1 | awk '{print $2}')
+ http_port=$(echo $http_status | tail -n 1 | awk '{print $2}')
+
+ if [ "$http_enable" = "Yes" ]; then
+ echo -e "${green}HTTP : ✔${NC}" $http_ip ":" $http_port
+ else
+ echo -e "${RED}HTTP : ✘${NC}" $http_ip ":" $http_port
+ fi
+
+ https_status=$(networksetup -getsecurewebproxy $network | head -n 3)
+ https_enable=$(echo $https_status | head -n 1 | awk '{print $2}')
+ https_ip=$(echo $https_status | head -n 2 | tail -n 1 | awk '{print $2}')
+ https_port=$(echo $https_status | tail -n 1 | awk '{print $2}')
+
+ if [ "$https_enable" = "Yes" ]; then
+ echo -e "${green}HTTPS: ✔${NC}" $https_ip ":" $https_port
+ else
+ echo -e "${RED}HTTPS: ✘${NC}" $https_ip ":" $https_port
+ fi
+ ;;
+ *)
+ echo "Usage: p {on|off|g|s}"
+ echo "p on : Set proxy to Charles(port 8888)"
+ echo "p off: Reset proxy to system default"
+ echo "p g : Set proxy to GoAgentx(port 14179)"
+ echo "p s : Show current network proxy status"
+ echo "p * : Show usage"
+ ;;
+ esac
+}
+## Enable/Disable proxy
+function proxyon() {
+ # local host_port='127.0.0.1:8080'
+ export all_proxy="socks5://127.0.0.1:7891"
+ export http_proxy=$all_proxy
+ export https_proxy=$all_proxy
+ git config --global http.proxy $https_proxy
+ git config --global https.proxy $https_proxy
+ echo "proxy = \"$all_proxy\"" >! $HOME/.config/curl/config
+}
+
+function proxyoff() {
+ export all_proxy=''
+ export http_proxy=''
+ export https_proxy=''
+ git config --global http.proxy ''
+ git config --global https.proxy ''
+ echo '' >! $HOME/.config/curl/config
+}
+## Reload shell
+function reload() {
+ local compdump_files="$ZDOTDIR/.zcompdump*"
+
+ if ls $compdump_files &> /dev/null; then
+ rm -f $compdump_files
+ fi
+
+ exec $SHELL -l
+}
+## Generate a secure password
+function passgen() {
+ LC_ALL=C tr -dc ${1:-"[:graph:]"} < /dev/urandom | head -c ${2:-20}
+}
+## Encode/Decode string using base64
+function b64e() {
+ echo "$@" | base64
+}
+
+function b64d() {
+ echo "$@" | base64 -D
+}
+# Search through all man pages
+function fman() {
+ man -k . | fzf -q "$1" --prompt='man> ' --preview $'echo {} | tr -d \'()\' | awk \'{printf "%s ", $2} {print $1}\' | xargs -r man' | tr -d '()' | awk '{printf "%s ", $2} {print $1}' | xargs -r man
+}
+# Back up a file. Usage "backupthis <filename>"
+backupthis() {
+ cp -riv $1 ${1}-$(date +%Y%m%d%H%M).backup;
+}
+
+# Spawn a clone of current terminal
+putstate () {
+ declare +x >~/environment.tmp
+ declare -x >>~/environment.tmp
+ echo cd "$PWD" >>~/environment.tmp
+}
+
+getstate () {
+ . ~/environment.tmp
+}
+
+# use ctrl-z to toggle in and out of bg
+function toggle_fg_bg() {
+ if [[ $#BUFFER -eq 0 ]]; then
+ BUFFER="fg"
+ zle accept-line
+ else
+ BUFFER=""
+ zle clear-screen
+ fi
+}
+zle -N toggle_fg_bg
+bindkey '^Z' toggle_fg_bg
+
+# Tmux layout
+openSession () {
+ tmux split-window -h -t
+ tmux split-window -v -t
+ tmux resize-pane -U 5
+}
+
+# Extract with one command
+extract () {
+ if [ -f $1 ] ; then
+ case $1 in
+ *.tar.bz2) tar xjf $1 ;;
+ *.tar.gz) tar xzf $1 ;;
+ *.bz2) bunzip2 $1 ;;
+ *.rar) rar x $1 ;;
+ *.gz) gunzip $1 ;;
+ *.tar) tar xf $1 ;;
+ *.tbz2) tar xjf $1 ;;
+ *.tgz) tar xzf $1 ;;
+ *.zip) unzip $1 ;;
+ *.Z) uncompress $1 ;;
+ *.7z) 7z x $1 ;;
+ *) echo "'$1' cannot be extracted via extract()" ;;
+ esac
+ else
+ echo "'$1' is not a valid file"
+ fi
+}
+
+ports() {
+ local result
+ result=$(sudo netstat -tulpn | grep LISTEN)
+ echo "$result" | fzf
+}
+
+trash() {
+ case "$1" in
+ --list)
+ ls -A1 ~/.local/share/Trash/files/
+ ;;
+ --empty)
+ ls -A1 ~/.local/share/Trash/files/ && \rm -rfv ~/.local/share/Trash/files/*
+ ;;
+ --restore)
+ gio trash --restore "$(gio trash --list | fzf | cut -f 1)"
+ ;;
+ --delete)
+ trash_files=$(ls -A ~/.local/share/Trash/files/ | fzf --multi); echo $trash_files | xargs -I {} rm -rf ~/.local/share/Trash/files/{}
+ ;;
+ *)
+ gio trash "$@"
+ ;;
+ esac
+}
+
+# Git
+## Use gh instead of git (fast GitHub command line client).
+#if type gh >/dev/null; then
+# alias git=gh
+# if type compdef >/dev/null 2>/dev/null; then
+# compdef gh=git
+# fi
+#fi
+#check_gh_installed() {
+# if command -v gh &> /dev/null; then
+# return 0 # gh is installed
+# else
+# return 1 # gh is not installed
+# fi
+#}
+#
+## Set alias for git to gh if gh is installed
+#if check_gh_installed; then
+# alias git=gh
+#fi
+
+# No arguments: `git status`
+# With arguments: acts like `git`
+g() {
+ if [ $# -gt 0 ]; then
+ git "$@" # If arguments are provided, pass them to git
+ else
+ git status # Otherwise, show git status
+ fi
+}
+
+# Complete g like git
+compdef g=git
+
+# Define functions for common Git commands
+ga() { g add "$@"; } # ga: Add files to the staging area
+gaw() { g add -A && g diff --cached -w | g apply --cached -R; } # gaw: Add all changes to the staging area and unstage whitespace changes
+grm() { g rm "$@"; }
+gb() { g branch "$@"; } # gb: List branches
+gbl() { g branch -l "$@"; } # gbl: List local branches
+gbD() { g branch -D "$@"; } # gbD: Delete a branch
+gbu() { g branch -u "$@"; } # gbu: Set upstream branch
+ge() { g clone "$@"; }
+gc() { g commit "$@"; } # gc: Commit changes
+gcm() { g commit -m "$@"; } # gcm: Commit with a message
+gca() { g commit -a "$@"; } # gca: Commit all changes
+gcaa() { g commit -a --amend "$@"; } # gcaa: Amend the last commit
+gcam() { g commit -a -m "$@"; } # gcam: Commit all changes with a message
+gce() { g commit -e "$@"; } # gce: Commit with message and allow editing
+gcfu() { g commit --fixup "$@"; } # gcfu: Commit fixes in the context of the previous commit
+gco() { g checkout "$@"; } # gco: Checkout a branch or file
+gcob() { g checkout -b "$@"; } # gcob: Checkout a new branch
+gcoB() { g checkout -B "$@"; } # gcoB: Checkout a new branch, even if it exists
+gcp() { g cherry-pick "$@"; } # gcp: Cherry-pick a commit
+gcpc() { g cherry-pick --continue "$@"; } # gcpc: Continue cherry-picking after resolving conflicts
+gd() { g diff "$@"; } # gd: Show changes
+#gd^() { g diff HEAD^ HEAD "$@"; } # gd^: Show changes between HEAD^ and HEAD
+gds() { g diff --staged "$@"; } # gds: Show staged changes
+gl() { g lg "$@"; } # gl: Show a customized log
+glg() { g log --graph --decorate --all "$@"; } # glg: Show a customized log with graph
+gls() { # Query `glog` with regex query.
+ query="$1"
+ shift
+ glog --pickaxe-regex "-S$query" "$@"
+}
+gdc() { g diff --cached "$@"; } # gdc: Show changes between the working directory and the index
+gu() { g pull "$@"} # gu: Pull
+gp() { g push "$@"} # gp: Push
+gpom() { g push origin main "$@"; } # gpom: Push changes to origin main
+gr() { g remote "$@"; } # gr: Show remote
+gra() { g rebase --abort "$@"; } # gra: Abort a rebase
+grb() { g rebase --committer-date-is-author-date "$@"; } # grb: Rebase with the author date preserved
+grbom() { grb --onto master "$@"; } # grbom: Rebase onto master
+grbasi() { g rebase --autosquash --interactive "$@"; } # grbasi: Interactive rebase with autosquash
+grc() { g rebase --continue "$@"; } # grc: Continue a rebase
+grs() { g restore --staged "$@"; } # grs: Restore changes staged for the next commit
+grv() { g remote -v "$@"; } # grv: Show remote URLs after each name
+grh() { g reset --hard "$@"; } # grh: Reset the repository and the working directory
+grH() { g reset HEAD "$@"; } # grH: Reset the index but not the working directory
+#grH^() { g reset HEAD^ "$@"; } # grH^: Reset the index and working directory to the state of the HEAD's first parent
+gs() { g status -sb "$@"; } # gs: Show the status of the working directory and the index
+gsd() { g stash drop "$@"; } # gsd: Drop a stash
+gsl() { g stash list --date=relative "$@"; } # gsl: List all stashes
+gsp() { g stash pop "$@"; } # gsp: Apply and remove a single stash
+gss() { g stash show "$@"; } # gss: Show changes recorded in the stash as a diff
+gst() { g status "$@"; } # gst: Show the status of the working directory and the index
+gsu() { g standup "$@"; } # gsu: Customized standup command
+gforgotrecursive() { g submodule update --init --recursive --remote "$@"; } # gforgotrecursive: Update submodules recursively
+gfp() { g commit --amend --no-edit && g push --force-with-lease "$@"; } # gfp: Amending the last commit and force-pushing
diff --git a/.config/zsh/user/options.zsh b/.config/zsh/user/options.zsh
new file mode 100644
index 0000000..0e97fed
--- /dev/null
+++ b/.config/zsh/user/options.zsh
@@ -0,0 +1,50 @@
+
+# Let FZF use ripgrep by default
+if type rg &> /dev/null; then
+ export FZF_DEFAULT_COMMAND='rg --files'
+ export FZF_DEFAULT_OPTS='-m --height 50% --border'
+fi
+
+
+# Allow nnn filemanager to cd on quit
+nnn() {
+ declare -x +g NNN_TMPFILE=$(mktemp --tmpdir $0.XXXX)
+ trap "rm -f $NNN_TMPFILE" EXIT
+ =nnn $@
+ [ -s $NNN_TMPFILE ] && source $NNN_TMPFILE
+}
+
+
+# NVM
+#nvm() {
+# local green_color
+# green_color=$(tput setaf 2)
+# local reset_color
+# reset_color=$(tput sgr0)
+# echo -e "${green_color}nvm${reset_color} $@"
+#}
+if [ -s "$NVM_DIR/nvm.sh" ]; then
+ nvm_cmds=(nvm node npm yarn)
+ for cmd in "${nvm_cmds[@]}"; do
+ alias "$cmd"="unalias ${nvm_cmds[*]} && unset nvm_cmds && . $NVM_DIR/nvm.sh && $cmd"
+ done
+fi
+
+# Kubernetes
+# kubernetes aliases
+if command -v kubectl > /dev/null; then
+ replaceNS() { kubectl config view --minify --flatten --context=$(kubectl config current-context) | yq ".contexts[0].context.namespace=\"$1\"" ; }
+ alias kks='KUBECONFIG=<(replaceNS "kube-system") kubectl'
+ alias kam='KUBECONFIG=<(replaceNS "authzed-monitoring") kubectl'
+ alias kas='KUBECONFIG=<(replaceNS "authzed-system") kubectl'
+ alias kar='KUBECONFIG=<(replaceNS "authzed-region") kubectl'
+ alias kt='KUBECONFIG=<(replaceNS "tenant") kubectl'
+
+ if command -v kubectl-krew > /dev/null; then
+ path=($XDG_CONFIG_HOME/krew/bin $path)
+ fi
+
+ rmfinalizers() {
+ kubectl get deployment "$1" -o json | jq '.metadata.finalizers = null' | kubectl apply -f -
+ }
+fi
diff --git a/.config/zsh/user/prompt.zsh b/.config/zsh/user/prompt.zsh
new file mode 100644
index 0000000..d9fc148
--- /dev/null
+++ b/.config/zsh/user/prompt.zsh
@@ -0,0 +1,202 @@
+#!/bin/zsh
+
+########## Prompt(s) ##########
+
+terminfo_down_sc=$terminfo[cud1]$terminfo[cuu1]$terminfo[sc]$terminfo[cud1]
+
+autoload -Uz vcs_info
+autoload -Uz add-zsh-hook
+autoload -U colors && colors
+
+precmd_vcs_info() { vcs_info }
+
+precmd_functions+=( precmd_vcs_info )
+
+setopt prompt_subst
+
+git_branch_test_color() {
+ local ref=$(git symbolic-ref --short HEAD 2> /dev/null)
+ if [ -n "${ref}" ]; then
+ if [ -n "$(git status --porcelain)" ]; then
+ local gitstatuscolor='%F{green}'
+ else
+ local gitstatuscolor='%F{82}'
+ fi
+ echo "${gitstatuscolor}${ref}"
+ else
+ echo ""
+ fi
+}
+
+zstyle ':vcs_info:*' check-for-changes true
+zstyle ':vcs_info:*' stagedstr ' +%F{15}staged%f'
+zstyle ':vcs_info:*' unstagedstr ' -%F{15}unstaged%f'
+zstyle ':vcs_info:*' actionformats '%F{5}%F{2}%b%F{3}|%F{1}%a%F{5}%f '
+zstyle ':vcs_info:*' formats '%F{208} '$'\uE0A0'' %f$(git_branch_test_color)%f%F{76}%c%F{3}%u%f '
+zstyle ':vcs_info:git*+set-message:*' hooks git-untracked
+zstyle ':vcs_info:*' enable git
+
++vi-git-untracked() {
+ if [[ $(git rev-parse --is-inside-work-tree 2> /dev/null) == 'true' ]] && \
+ git status --porcelain | grep '??' &> /dev/null ; then
+ hook_com[unstaged]+='%F{196} !%f%F{15}untracked%f'
+ fi
+}
+
+ssh_name() {
+ if [[ -n $SSH_CONNECTION ]]; then
+ local ssh_info
+ ssh_info="ssh:%F{green}%n$nc%f"
+ if [[ -n $SSH_CONNECTION ]]; then
+ local ip_address
+ ip_address=$(echo $SSH_CONNECTION | awk '{print $3}')
+ ssh_info="$ssh_info@%F{green}$ip_address%f"
+ fi
+ echo " ${ssh_info}"
+ fi
+}
+
+function job_name() {
+ job_name=""
+ job_length=0
+ if [ "${COLUMNS}" -gt 69 ]; then
+ job_length=$((${COLUMNS}-70))
+ [ "${job_length}" -lt "0" ] && job_length=0
+ fi
+
+ if [ "${job_length}" -gt 0 ]; then
+ local job_count=$(jobs | wc -l)
+ if [ "${job_count}" -gt 0 ]; then
+ local title_jobs="jobs:"
+ job_name="${title_jobs}"
+ job_name+="%F{green}$(jobs | grep + | tr -s " " | cut -d " " -f 4- | cut -b 1-${job_length} | sed "s/\(.*\)/\1/")%f"
+ fi
+ fi
+
+ echo "${job_name}"
+}
+
+function job_count() {
+ local job_count
+ job_count=$(jobs -s | grep -c "suspended")
+ if [ "${job_count}" -gt 0 ]; then
+ echo "(${job_count})"
+ fi
+}
+
+current_jobs=' $(job_name)$(job_count)'
+user="%n"
+at="%F{15}at%{$reset_color%}"
+machine="%F{4}%m%{$reset_color%}"
+relative_home="%F{4}%~%{$reset_color%}"
+carriage_return=""$'\n'""
+empty_line_bottom="%r"
+chevron_right=""
+color_reset="%{$(tput sgr0)%}"
+color_yellow="%{$(tput setaf 226)%}"
+color_blink="%{$(tput blink)%}"
+prompt_symbol="$"
+dollar_sign="${color_yellow}${color_blink}${prompt_symbol}${color_reset}"
+dollar="%(?:%F{2}${dollar_sign}:%F{1}${dollar_sign})"
+space=" "
+cmd_prompt="%(?:%F{2}${chevron_right} :%F{1}${chevron_right} )"
+git_info="\$vcs_info_msg_0_"
+v1="%{┌─[%}"
+v2="%{]%}"
+v3="└─["
+v4="]"
+
+function insert-mode () { echo "-- INSERT --" }
+function normal-mode () { echo "-- NORMAL --" }
+
+vi-mode-indicator () {
+ if [[ ${KEYMAP} == vicmd || ${KEYMAP} == vi-cmd-mode ]]; then
+ echo -ne '\e[1 q'
+ vi_mode=$(normal-mode)
+ elif [[ ${KEYMAP} == main || ${KEYMAP} == viins || ${KEYMAP} == '' ]]; then
+ echo -ne '\e[5 q'
+ vi_mode=$(insert-mode)
+ fi
+}
+
+function set-prompt () {
+ vi-mode-indicator
+ mode="%F{145}%{$terminfo_down_sc$vi_mode$terminfo[rc]%f%}"
+ #PS1="${relative_home}${vcs_info_msg_0_}${current_jobs} ${carriage_return}${mode}${dollar}${space}"
+ PS1="${v1}${user}${v2}${space}${relative_home}${vcs_info_msg_0_}${current_jobs}$(ssh_name) ${carriage_return}${mode}${v3}${dollar}${v4}${empty_line_bottom}"
+ #RPROMPT="$(ssh_name)"
+}
+
+precmd () {
+ print -rP
+ vcs_info
+ set-prompt
+}
+
+function update-mode-file() {
+ set-prompt
+ local current_mode=$(cat ~/.vi-mode)
+ local new_mode="$vi_mode"
+ if [[ "$new_mode" != "$current_mode" ]]; then
+ echo "$new_mode" >| ~/.vi-mode
+ fi
+ if command -v tmux &>/dev/null && [[ -n "$TMUX" ]]; then
+ tmux refresh-client -S
+ fi
+}
+
+function check-nvim-running() {
+ if pgrep -x "nvim" > /dev/null; then
+ vi_mode=""
+ update-mode-file
+ if command -v tmux &>/dev/null && [[ -n "$TMUX" ]]; then
+ tmux refresh-client -S
+ fi
+ else
+ if [[ ${KEYMAP} == vicmd || ${KEYMAP} == vi-cmd-mode ]]; then
+ vi_mode=$(normal-mode)
+ elif [[ ${KEYMAP} == main || ${KEYMAP} == viins || ${KEYMAP} == '' ]]; then
+ vi_mode=$(insert-mode)
+ fi
+ update-mode-file
+ if command -v tmux &>/dev/null && [[ -n "$TMUX" ]]; then
+ tmux refresh-client -S
+ fi
+ fi
+}
+
+function zle-line-init() {
+ zle reset-prompt
+ case "${KEYMAP}" in
+ vicmd)
+ echo -ne '\e[1 q'
+ ;;
+ main|viins|*)
+ echo -ne '\e[5 q'
+ ;;
+ esac
+}
+
+function zle-keymap-select() {
+ update-mode-file
+ zle reset-prompt
+ case "${KEYMAP}" in
+ vicmd)
+ echo -ne '\e[1 q'
+ ;;
+ main|viins|*)
+ echo -ne '\e[5 q'
+ ;;
+ esac
+}
+
+preexec () { print -rn -- $terminfo[el]; echo -ne '\e[5 q' ; }
+
+zle -N zle-line-init
+zle -N zle-keymap-select
+
+TRAPWINCH() {
+ update-mode-file
+}
+
+set-prompt