Z shell configuration
ZDOTDIR
By default $ZDOTDIR
is set to $HOME
. I want it to be in $XDG_CONFIG_HOME
.
ZDOTDIR=$HOME/.config/zsh
Prompt
Pure
target=$XDG_CONFIG_HOME/zsh/pure [ -d $target/.git ] && exit 0 mkdir -p $target git clone https://github.com/sindresorhus/pure.git $target
fpath+=($XDG_CONFIG_HOME/zsh/pure) PURE_GIT_PULL=0 autoload -U promptinit; promptinit prompt pure prompt_newline=$(echo -n "\u200B")
TODO VCS info
Borrowed from vincentbernat, originally wrote about it on his blog.
TODO: https://medium.com/@henrebotha/how-to-write-an-asynchronous-zsh-prompt-b53e81720d32
[[ $USERNAME != "root" ]] && [[ $ZSH_NAME != "zsh-static" ]] && { # Async helpers _vbe_vcs_async_start() { async_start_worker vcs_info async_register_callback vcs_info _vbe_vcs_info_done } _vbe_vcs_info() { cd -q $1 vcs_info print ${vcs_info_msg_0_} } _vbe_vcs_info_done() { local job=$1 local return_code=$2 local stdout=$3 local more=$6 if [[ $job == '[async]' ]]; then if [[ $return_code -eq 2 ]]; then # Need to restart the worker. Stolen from # https://github.com/mengelbrecht/slimline/blob/master/lib/async.zsh _vbe_vcs_async_start return fi fi vcs_info_msg_0_=$stdout [[ $more == 1 ]] || zle reset-prompt } autoload -Uz vcs_info zstyle ':vcs_info:*' enable git () { local formats="${PRCH[branch]} %b%c%u" local actionformats="${formats}%{${fg[default]}%} ${PRCH[sep]} %{${fg[green]}%}%a" zstyle ':vcs_info:*:*' formats $formats zstyle ':vcs_info:*:*' actionformats $actionformats zstyle ':vcs_info:*:*' stagedstr "%{${fg[green]}%}${PRCH[circle]}" zstyle ':vcs_info:*:*' unstagedstr "%{${fg[yellow]}%}${PRCH[circle]}" zstyle ':vcs_info:*:*' check-for-changes true zstyle ':vcs_info:git*+set-message:*' hooks git-untracked +vi-git-untracked(){ if [[ $(git rev-parse --is-inside-work-tree 2> /dev/null) == 'true' ]] && \ git status --porcelain 2> /dev/null | grep -q '??' ; then hook_com[staged]+="%{${fg[black]}%}${PRCH[circle]}" fi } } # Asynchronous VCS status async_init _vbe_vcs_async_start add-zsh-hook precmd (){ async_job vcs_info _vbe_vcs_info $PWD } add-zsh-hook chpwd (){ vcs_info_msg_0_= } # Add VCS information to the prompt _vbe_add_prompt_vcs () { _vbe_prompt_segment cyan default ${vcs_info_msg_0_} } }
Bindings
Use Emacs keybindings
bindkey -e
Jump words
I’d like to have a word boundary at the equal =
sign, so remove it from
$WORDCHARS
.
#WORDCHARS='*?_-.[]~=/&;!#$%^(){}<>' WORDCHARS='*?_-.[]~/&;!#$%^(){}<>'
Define keys
From: https://wiki.archlinux.org/index.php/Zsh#Key_bindings
Create a zkbd compatible hash.
To add other keys to this hash, see man 5 terminfo
.
typeset -g -A key key[Home]="${terminfo[khome]}" key[End]="${terminfo[kend]}" key[Insert]="${terminfo[kich1]}" key[Backspace]="${terminfo[kbs]}" key[Delete]="${terminfo[kdch1]}" key[Up]="${terminfo[kcuu1]}" key[Down]="${terminfo[kcud1]}" key[Left]="${terminfo[kcub1]}" key[Right]="${terminfo[kcuf1]}" key[PageUp]="${terminfo[kpp]}" key[PageDown]="${terminfo[knp]}" key[Shift-Tab]="${terminfo[kcbt]}"
Set up key
accordingly.
[[ -n "${key[Home]}" ]] && bindkey -- "${key[Home]}" beginning-of-line [[ -n "${key[End]}" ]] && bindkey -- "${key[End]}" end-of-line [[ -n "${key[Insert]}" ]] && bindkey -- "${key[Insert]}" overwrite-mode [[ -n "${key[Backspace]}" ]] && bindkey -- "${key[Backspace]}" backward-delete-char [[ -n "${key[Delete]}" ]] && bindkey -- "${key[Delete]}" delete-char [[ -n "${key[Up]}" ]] && bindkey -- "${key[Up]}" up-line-or-history [[ -n "${key[Down]}" ]] && bindkey -- "${key[Down]}" down-line-or-history [[ -n "${key[Left]}" ]] && bindkey -- "${key[Left]}" backward-char [[ -n "${key[Right]}" ]] && bindkey -- "${key[Right]}" forward-char [[ -n "${key[PageUp]}" ]] && bindkey -- "${key[PageUp]}" beginning-of-buffer-or-history [[ -n "${key[PageDown]}" ]] && bindkey -- "${key[PageDown]}" end-of-buffer-or-history [[ -n "${key[Shift-Tab]}" ]] && bindkey -- "${key[Shift-Tab]}" reverse-menu-complete
Finally, make sure the terminal is in application mode, when zle
is
active. Only then are the values from $terminfo
valid.
if (( ${+terminfo[smkx]} && ${+terminfo[rmkx]} )); then autoload -Uz add-zle-hook-widget function zle_application_mode_start { echoti smkx } function zle_application_mode_stop { echoti rmkx } add-zle-hook-widget -Uz zle-line-init zle_application_mode_start add-zle-hook-widget -Uz zle-line-finish zle_application_mode_stop fi
History
Set the zsh history file (if not already set).
if [ -z "$HISTFILE" ]; then HISTFILE="$XDG_DATA_HOME"/zsh/history fi
Set the history size.
HISTSIZE=10000 SAVEHIST=10000
Create alias to print out the history with yyyy-mm-dd
timestamps.
alias history="fc -il 1"
Configure the history:
append_history
- Append instead of replacing history file.
extended_history
- Save commands with timestamp and duration.
hist_expire_dups_first
- Trim oldest history event with duplicate before unique events.
hist_ignore_dups
- Ignore if command is duplicate of the previous command.
hist_ignore_space
- Ignore command if the first character is a space.
hist_verify
- Whenever the user enters a line with history expansion, don’t execute the line directly.
inc_append_history
- Add history lines incrementally (as soon as they are entered).
share_history
- Share history with your zshells on the same host.
setopt append_history setopt extended_history setopt hist_expire_dups_first setopt hist_ignore_dups setopt hist_ignore_space setopt hist_verify setopt inc_append_history setopt share_history
History completion
When pressing up/down arrow keys find command in history beginning with what you’ve typed already.
See: https://superuser.com/a/418299/94259
From: https://wiki.archlinux.org/index.php/Zsh#History_search
autoload -Uz up-line-or-beginning-search down-line-or-beginning-search zle -N up-line-or-beginning-search zle -N down-line-or-beginning-search [[ -n "${key[Up]}" ]] && bindkey -- "${key[Up]}" up-line-or-beginning-search [[ -n "${key[Down]}" ]] && bindkey -- "${key[Down]}" down-line-or-beginning-search
Completion
Load module.
zmodload -i zsh/complist
Configure some options:
menu_complete
- Unset to not insert the first match immediately.
flowcontrol
- Unset to disable output flow control via start/stop characters (usually assigned to ^S/Q).
auto_menu
- Use menu completion by pressing the tab key repeatedly.
complete_in_word
- Do completion from both ends of the word.
always_to_end
- When full completion is inserted, the cursor is moved to the end of the word.
unsetopt menu_complete unsetopt flowcontrol setopt auto_menu setopt complete_in_word setopt always_to_end
Use menu like selection mode.
zstyle ':completion:*:*:*:*:*' menu select
When pressing Shift-Tab
move through the completion menu backwards.
if [[ "${terminfo[kcbt]}" != "" ]]; then bindkey "${terminfo[kcbt]}" reverse-menu-complete fi
Initialize completion
autoload -U compinit compinit compinit
Tools
ssh-agent
Start ssh-agent, or take over the environment variables if it is already running.
SSH_ENV="$HOME/.ssh/environment" function start_agent { echo "Initialising new SSH agent..." /usr/bin/ssh-agent | sed 's/^echo/#echo/' > "${SSH_ENV}" echo succeeded chmod 600 "${SSH_ENV}" . "${SSH_ENV}" > /dev/null /usr/bin/ssh-add; } # Source SSH settings, if applicable if [ -f "${SSH_ENV}" ]; then . "${SSH_ENV}" > /dev/null ps ${SSH_AGENT_PID} | grep ssh-agent$ > /dev/null || { start_agent; } else start_agent; fi
Mise
Configure mise
. I don’t like all the magic mise
ships with, so instead of
having mise activate
in my zshrc, I force myself to type mise use x@y
.
I also don’t want mise
to use versions from .tool-versions
, because I don’t
care if the exact same version is installed.
#eval "$($HOME/.local/bin/mise activate zsh)" export MISE_DEFAULT_TOOL_VERSIONS_FILENAME=.i-dont-want-to-use-any-tool-versions
Chruby
Currently I’m not using chruby
and use mise
instead.
Locate where the chruby
scripts are.
(seq-find 'file-accessible-directory-p '("/usr/local/share/chruby" "/usr/share/chruby"))
Load chruby, the Ruby version changer.
source nil/chruby.sh
Also automatically use the default version.
source nil/auto.sh
Run chruby
to load a Ruby.
chruby > /dev/null
Aliases
Basics
Just some simple aliases I use every day.
alias l="ls -la"
Parent dirs
Just use more dots to go further up.
alias -g ...='../..' alias -g ....='../../..' alias -g .....='../../../..'
Bundler
Short aliases for bundler. Inspired by Vendor Everything Still Applies.
alias b="bundle" alias bi="b install --path vendor/bundle" alias bil="bi --local" alias bu="b update" alias be="b exec" alias binit="bi && b package && echo 'vendor/ruby' >> .gitignore"
Emacsclient
Add a function for emacsclient
that allows to read from stdin.
Originally from EmacsWiki.
e() { if [ -z "$1" ] then local TMP; TMP="$(mktemp /tmp/emacs-stdin-XXX)" cat >$TMP emacsclient --alternate-editor=emacs --no-wait $TMP else emacsclient --alternate-editor=emacs --no-wait "$@" fi }
magit
And an alias to directly start magit in the current working directory.
alias magit='emacsclient -n -e "(progn (magit-status) (delete-other-windows))"'
git
I use git a lot, so add some easy to use aliases.
alias gst="git status" alias gco="git checkout"
GitLab
The GitLab documentation uses gitlab-rake
to run rake tasks, so
because I’m lazy I want to copy/paste the commands as-is.
alias gitlab-rake="be rake"
No littering
Some commands litter my $HOME
directory. Stop them from doing that with a few
aliases.
Units
alias units="units --history=$XDG_CACHE_HOME/units_history"
Functions
Smart chruby
Automatically guess the ruby version from:
- Given argument
Gemfile
.ruby_version
~/.ruby_version
function chrb () { if [ -n "$1" ] then chruby $@ elif [ -e Gemfile ] then chruby $(grep ^ruby Gemfile | tr -cd '[[:digit:]].') elif [ -e .ruby_version ] then chruby_auto else chruby fi # print the current ruby version env ruby --version }
Zprofile
Zprofile is only loaded on the login shell.
Profile
Load environment.
setopt allexport
source $HOME/.config/environment.d/*.conf
unsetopt allexport