# # ~/.zshrc # ZSH configuration file # # Credits: # [1] https://github.com/spicycode/ze-best-zsh-config # [2] Zsh Configuration from the Ground Up # http://zanshin.net/2013/02/02/zsh-configuration-from-the-ground-up/ # [3] GRML Zsh # http://grml.org/zsh/ # # References: # [1] The Unix Shell's Humble if # https://robots.thoughtbot.com/the-unix-shells-humble-if # # # OS checks # OS=$(uname -s) if [[ "${OS}" = 'Linux' ]]; then IS_LINUX=1 elif [[ "${OS}" = 'Darwin' ]]; then IS_MAC=1 elif [[ "${OS}" = 'DragonFly' ]] || [[ "${OS}" =~ '.*BSD' ]]; then IS_BSD=1 fi # # Zsh Parameters # See zshparam(1) # # Ask only if the top of the listing would scroll off the screen LISTMAX=0 # Report consuming time statistics if user+system greater than 60 seconds REPORTTIME=60 # Format of process time reports with the `time' keyword TIMEFMT="%J %U user %S system %P cpu %MM memory %*E total" # History HISTFILE=~/.zsh_history HISTSIZE=9000 SAVEHIST=9000 # Ignore these commands without arguments HISTIGNORE="cd:ls:ll" # # Zsh Options # See zshoptions(1) # ## Basics setopt NO_BEEP setopt AUTO_CD # make cd push the old directory onto the directory stack setopt AUTO_PUSHD # don't push multiple copies of the same directory into the directory stack setopt PUSHD_IGNORE_DUPS # exchange meanings of `+` and `-` when specifying a directory in the stack setopt PUSHD_MINUS # do not print the directory stack after `pushd` or `popd` setopt PUSHD_SILENT # treat #, ~, and ^ as part of patterns for filename generation setopt EXTENDED_GLOB # allow comments even in interactive shells (especially for Muness) setopt INTERACTIVE_COMMENTS # display PID when suspending processes as well setopt LONG_LIST_JOBS # disable output flow control via start/stop characters (^S/^Q) unsetopt FLOW_CONTROL ## History # allow multiple terminal sessions to all append to one zsh command history setopt APPEND_HISTORY # include timestamp of command and duration to history setopt EXTENDED_HISTORY # add comamnds as they are typed, don't wait until shell exit setopt INC_APPEND_HISTORY # do not write events to history that are duplicates of previous events setopt HIST_IGNORE_DUPS # remove command line from history list when it begins a space setopt HIST_IGNORE_SPACE # when searching history don't display results already cycled through twice setopt HIST_FIND_NO_DUPS # remove extra blanks from each command line being added to history setopt HIST_REDUCE_BLANKS # don't execute, just expand history setopt HIST_VERIFY ## Completion # `*' shouldn't match dotfiles. ever. setopt NO_GLOB_DOTS # allow completion from within a word/phrase setopt COMPLETE_IN_WORD # when completing from middle of a word, move cursor to the end of the word setopt ALWAYS_TO_END # show completion menu on successive tab press (needs 'unsetopt MENU_COMPLETE') setopt AUTO_MENU unsetopt MENU_COMPLETE # make the completion list compact setopt LIST_PACKED ## Correction # spelling correction for commands setopt CORRECT # spelling correction for arguments #setopt CORRECTALL # # Prompt # Credit: http://chneukirchen.org/dotfiles/.zshrc # # enable parameter expansion, command substitution, and arithmetic expansion setopt PROMPT_SUBST # remove any right prompt from display when accepting a command line setopt TRANSIENT_RPROMPT # gitpwd - format the current path with inline git branch for the # prompt; the current path is limited to $NDIR segments, # meanwhile long segments are shortened to be # ''. NDIRS=3 function gitpwd() { local -a segs splitprefix local prefix branch segs=("${(Oas:/:)${(D)PWD}}") segs=("${(@)segs/(#b)(?(#c10))??*(?(#c5))/${(j:\u2026:)match}}") if gitprefix=$(git rev-parse --show-prefix 2>/dev/null); then splitprefix=("${(s:/:)gitprefix}") if ! branch=$(git symbolic-ref -q --short HEAD); then branch=$(git name-rev --name-only HEAD 2>/dev/null) [[ $branch = *\~* ]] || branch+="~0" # distinguish detached HEAD fi if (( $#splitprefix > NDIRS )); then print -n "${segs[$#splitprefix]}@$branch " else segs[$#splitprefix]+=@$branch fi fi (( $#segs == NDIRS+1 )) && [[ $segs[-1] == "" ]] && print -n / print "${(j:/:)${(@Oa)segs[1,NDIRS]}}" } PROMPT='%S%B%F{green}[%m]%s%(?.. %F{red}%??)%(1j. %F{yellow}%j&.)%b%f $(gitpwd)%B%(!.%F{red}.%F{green})%#${SSH_CONNECTION:+%#} %b%f' RPROMPT='' SPROMPT='zsh: correct %B%F{red}%R%b%f to %B%F{green}%r%b%f [(y)es (n)o (a)bort (e)dit]? ' # # Completion # fpath=(~/.zsh.completions $fpath) autoload -U compinit && compinit zmodload -i zsh/complist # enable completion caching, use rehash to clear zstyle ':completion::complete:*' use-cache on zstyle ':completion::complete:*' cache-path ~/.cache/zsh/${HOST} # make the selection prompt friendly when there are a lot of choices zstyle ':completion:*' select-prompt '%SScrolling active: current selection at %p%s' # list of completers to use zstyle ':completion:*::::' completer _expand _complete _ignored _approximate zstyle ':completion:*' menu select=1 _complete _ignored _approximate # match uppercase from lowercase zstyle ':completion:*' matcher-list 'm:{a-z}={A-Z}' # # Functions # ## Fix terminal # Credit: https://unix.stackexchange.com/a/299922 fix() { reset stty sane tput rs1 clear echo -e "\033c" } ## Check the existence/accessibility of a command # Credit: https://stackoverflow.com/a/677212/4856091 function exists() { # 'command' is POSIX-compliant and more portable; # 'hash' only searches for commands; # while 'type' also considers builtins and keywords. type "$1" >/dev/null 2>&1 } ## Check whether the program is running function is_running() { pgrep -x -u "${USER}" "$1" >/dev/null 2>&1 } ## Interactive move/rename: making renaming long filenames less sucks # Credit: http://chneukirchen.org/dotfiles/.zshrc function imv() { local src dst for src; do [[ -e "$src" ]] || { print -u2 "$src: does not exist"; continue } dst="$src" vared dst [[ "$src" != "$dst" ]] && mkdir -p ${dst:h} && mv -n $src $dst done } ## Print pre-defined C macros # Credit: http://chneukirchen.org/dotfiles/.zshrc ccdef() { ${1:-cc} $@[2,-1] -dM -E - /dev/null 2>&1 || true } autoload -U add-zsh-hook add-zsh-hook preexec update-gpg-tty # Delete all identities from the `gpg-agent', which is similar to # `ssh-add -D`. # Credit: http://blog.mrloop.com/workflow/2017/02/09/pin-entry.html ssh-delete() { grep -o '^[A-Z0-9]*' ${HOME}/.gnupg/sshcontrol | \ xargs -I'%' rm ${HOME}/.gnupg/private-keys-v1.d/'%'.key echo "" > ${HOME}/.gnupg/sshcontrol } # # Aliases # alias zhelp='run-help' alias ..='cd ../' alias ...='cd ../../' alias ....='cd ../../../' alias cd..='cd ..' alias d='dirs -v | head -10' alias po=popd alias pu=pushd if [[ -n "${IS_LINUX}" ]]; then alias ls='ls --color=auto' elif [[ -n "${IS_BSD}" ]] || [[ -n "${IS_MAC}" ]]; then alias ls='ls -G' fi alias l='ls -lah' alias la='ls -lAh' alias ll='ls -lh' alias lsa='ls -lah' # Do not use `GREP_OPTIONS` alias grep='grep --color=auto' exists "vi" || alias vi=vim exists "safe-rm" && alias rm=safe-rm # # Evnironment variables # # NOTE: # Generic environment variables and those needing been set only once # should go to `~/.profile'. # colors for BSD ls if [[ -n "${IS_BSD}" ]]; then export CLICOLOR=1 export LSCOLORS=exfxcxdxbxegedabagacad fi # Color setup for `ls': `LS_COLORS' # NOTE: For unknown reason, the `LS_COLORS' variable get overridden when # it is set in `~/.profile'. if exists dircolors; then eval $(dircolors -b) fi # # Local configurations # [ -r ~/.zshrc.local ] && source ~/.zshrc.local || true