Skip to content
This repository has been archived by the owner on Feb 20, 2021. It is now read-only.

Latest commit

 

History

History
1023 lines (933 loc) · 26 KB

zshrc.org

File metadata and controls

1023 lines (933 loc) · 26 KB

zsh Configuration

1 Introduction

  • Note taken on [2012-01-30 Mo 11:53]
    tangle to the correct locations; use logbook drawer
  • Note taken on [2012-01-29 So 01:15]
    Git functions added; prompt added; html export style

This is a literate programming zsh configuration written in org-mode/org-babel.

1.1 History

Up until January 2012 I used oh-my-zsh to configure my shell environment. It contains a lot of good ideas and a plethora of tools but, it also contains many errors and small mistakes; the code-quality overall is lousy.

After discovering the emacs starter kit I thought a lot about a good project to start to learn about and use org-babel for a literate programming adventure.

I’m usualy slow to take action, considering a lot, thinking ahead as many paths as I can – think of. Since, as of january 3d, oh-my-zsh get’s on my nerves for a couple of weeks now instead of making my day, taking on my first LP project wasn’t such a long process after all.

The first version considered complete enough to replace oh-my-zsh, finaly ridden of the command substitution bug, was finished <2012-01-10 Tue 13:21>.

2 zshrc

<<variables>>
<<modules>>
<<aliases>>
<<functions>>
<<options>>
<<gnuglobal>>
<<keybindings>>
<<command_completion>>
<<commandline_editing>>
<<history>>
<<dired>>
<<hooks>>
<<terminal>>
<<prompt>>
<<groovy>>
<<git>>
<<packages>>

2.1 Variables

2.1.1 Emacs setup

On different systems emacs 24 will be installed in different locations; I set EMACS_BASE here; aliases etc. later will use it.

if [ -z "${EMACS_BASE}" ]; then
    EMACS_BASE="/usr/local"
    export EMACS_BASE
fi

2.1.1.1 Emacs cask

# emacs cask package/dev managment
export PATH="$HOME/.cask/bin:$PATH"

2.1.2 Coloring for standard commands

Use green for matches, not red.

export GREP_COLORS="mt=01;32:ms=01;32:mc=01;32:sl=:cx=:fn=35:ln=32:bn=32:se=36"

2.1.3 Pager

export PAGER='less'

2.1.4 Characterset

export LC_CTYPE=$LANG

2.1.5 Path/Fpath

Newest GNU R in ~/opt

path=( ~/opt/bin $path )

Haskell development.

path=( ~/.cabal/bin $path )

This should always be the last part of path tinkering, as I’m used to be able to override any executable by putting a replacement or wrapper in my ~/bin.

path=( ~/bin $path )

Finaly adjust the fpath; a lot of the stuff following is tangled into files autoloadable, and I use wd for easier filesystem navigation

fpath=( ~/bin/wd.zsh $fpath)
fpath=( ~/.zsh.d/functions $fpath )

2.1.5.1 wd function

wd() {
    . ~/bin/wd.zsh/wd.sh
}

#

2.1.5.2 Ruby

2.1.5.2.1 rvm
# Add RVM to PATH for scripting
PATH=$PATH:$HOME/.rvm/bin

2.1.6 Bashlibs

export BASH_LIBS_DIR=~/lib/bash

2.1.7 Editor

export EDITOR="${EMACS_BASE}/bin/emacsclient -nw -c"

2.1.8 Java and tiling WMs

export _JAVA_AWT_WM_NONREPARENTING=1

2.1.9 Vagrant

export WEBDEV_ROOT="~/Projekte/devserver/"

2.1.10 Arduino / Kaleidoscope

export ARDUINO_PATH=/usr/share/arduino
export SKETCHBOOK_DIR=${HOME}/Arduino

2.1.11 Desktop Keyring variables

export $( dex /etc/xdg/autostart/gnome-keyring-ssh.desktop )

2.2 Modules

2.2.1 colors

autoload colors; colors

2.3 Aliases

2.3.1 Coloring for standard commands

A few standard aliases to deal with colored output in terminals.

[ ! -L ~/bin/ls ] && alias ls='/opt/coreutils/bin/ls --color=auto'
alias grep='grep --color=auto'
alias less='less -R'

2.3.2 Emacs

My emacs installation is sometimes in special locations; the aliases defined here reflect that.

alias emacs="${EMACS_BASE}/bin/emacs"
alias emc="${EMACS_BASE}/bin/emacsclient -c -nw"  

2.3.3 Desktop

I use awesome and don’t want nautilus to take over my desktop. Defining this alias prevents the nautilus started by gnome-session to automaticaly take over.

alias nautilus='nautilus --no-desktop'  

2.3.4 vagrant ssh

alias vssh="pushd ${WEBDEV_ROOT} && docker exec -it devserver /bin/bash; popd"

2.3.5 tmux update-env

alias tue="tmux update-environment"

2.3.6 system log with lnav

alias syslog="journalctl -f -o json | lnav"

2.4 Functions

2.4.1 Archives

2.4.1.1 Extract

function extract() {
    unset REMOVE_ARCHIVE
    
    if test "$1" = "-r"; then
        REMOVE_ARCHIVE=1
        shift
    fi
    if [[ -f $1 ]]; then
        case $1 in
            *.tar.bz2) tar xvjf $1;;
            *.tar.gz) tar xvzf $1;;
            *.tar.xz) tar xvJf $1;;
            *.tar.lzma) tar --lzma -xvf $1;;
            *.bz2) bunzip $1;;
            *.rar) unrar x $1;;
            *.gz) gunzip $1;;
            *.tar) tar xvf $1;;
            *.tbz2) tar xvjf $1;;
            *.tgz) tar xvzf $1;;
            *.zip) unzip $1;;
            *.Z) uncompress $1;;
            *.7z) 7z x $1;;
            *) echo "'$1' cannot be extracted via >extract<";;
        esac

        if [[ $REMOVE_ARCHIVE -eq 1 ]]; then
            echo removing "$1";
            /bin/rm "$1";
        fi

    else
        echo "'$1' is not a valid file"
    fi
}  

2.4.2 Source bash scripts

bash_source() {
    alias shopt=':'
    alias _expand=_bash_expand
    alias _complete=_bash_comp
    emulate -L sh
    setopt kshglob noshglob braceexpand
    
    source "$@"
}

2.4.3 Date from unix timestamp

function fromut() {
    echo `perl -e "print scalar(localtime(${1})),\"\n\";"`
}

2.4.4 SSH host keys

function remove_host_keys() {
    host="${1}"
    if [ -n "${host}" ]; then
        ssh-keygen -f "${HOME}/.ssh/known_hosts" -R "${host}"
    else
        echo "remove_host_keys {IP|HOST}" > /dev/stderr
    fi
}

2.4.5 phpunit

function phpunit() {
    command phpunit ${@}
    printf '\xb1�0m'
}

2.4.6 Compress jpeg-Files via convert

function compress_jpeg() {
    for pic in "${@}"; do 
        convert -strip -interlace Plane -gaussian-blur 0.05 -quality 85% "${pic}" "${pic}"
    done
}

2.4.7 Check for null-bytes

function check_zero_bytes() {
    status=0
    for arg in "${@}"; do
        perl -ne '/\000/ and print' "${arg}"
        status=1
    done
    return $status
}

2.5 Options

setopt extended_glob \
    glob_complete \
    function_arg_zero \
    hash_cmds \
    hash_dirs \
    multios \
    re_match_pcre

2.6 Keybindings

2.6.1 Emacs style keybindings!

bindkey -e

2.7 Command completion

2.7.1 compinit

autoload -Uz compinit; compinit

2.7.2 Options

unsetopt menu_complete \
    flowcontrol

setopt auto_menu \
    complete_in_word \
    always_to_end

2.7.3 complist module

zmodload -i zsh/complist

2.7.4 .zshrc

zstyle :compinstall filename "$HOME/.zshrc"

2.7.5 Bashcompletion

autoload -Uz bashcompinit; bashcompinit

2.7.6 Case sensitive, partial word and substring completion

zstyle ':completion:*' matcher-list 'r:|[._-]=* r:|=*' 'l:|=* r:|=*'

2.7.7 Colors/Menu

zstyle ':completion:*' list-colors ''     
zstyle ':completion:*:*:*:*:*' menu select

2.7.8 Keybindings

bindkey -M menuselect '^o' accept-and-infer-next-history  

2.7.9 Process completion

Menu of own processes for kill.

zstyle ':completion:*:*:kill:*:processes' list-colors '=(#b) #([0-9]#) ([0-9a-z-]#)*=01;34=0=01'
zstyle ':completion:*:*:*:*:processes' command "ps -u $(whoami) -o pid,user,comm -w -w"     

2.7.10 Hostnames

[ -r /etc/ssh/ssh_known_hosts ] && _global_ssh_hosts=(${${${${(f)"$(</etc/ssh/ssh_known_hosts)"}:#[\|]*}%%\ *}%%,*}) || _ssh_hosts=()
[ -r ~/.ssh/known_hosts ] && _ssh_hosts=(${${${${(f)"$(<$HOME/.ssh/known_hosts)"}:#[\|]*}%%\ *}%%,*}) || _ssh_hosts=()
[ -r /etc/hosts ] && : ${(A)_etc_hosts:=${(s: :)${(ps:\t:)${${(f)~~"$(</etc/hosts)"}%%\#*}##[:blank:]#[^[:blank:]]#}}} || _etc_hosts=()       

hosts=(
    "$_global_ssh_hosts[@]"
    "$_ssh_hosts[@]"
    "$_etc_hosts[@]"
    `hostname`
    localhost
)
zstyle ':completion:*:hosts' hosts $hosts

2.7.11 Usernames

Ignore most system 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          

2.7.12 Caching

Some completions need caching (dpkg, …)

zstyle ':completion::complete:*' use-cache 1
zstyle ':completion::complete:*' cache-path ~/.zsh.d/cache/     

2.7.13 Devserver

if [[ -r "/usr/share/bash-completion/devserver" ]]; then
    bash_source /usr/share/bash-completion/devserver
fi  

2.8 Commandline editing

2.8.1 Jump to beginning/end of line/word

bindkey "^[[H" beginning-of-line
bindkey "^[[1~" beginning-of-line
bindkey "^[OH" beginning-of-line
bindkey "^[[F"  end-of-line
bindkey "^[[4~" end-of-line
bindkey "^[OF" end-of-line
bindkey "^[[1;5C" forward-word
bindkey "^[[1;5D" backward-word

2.8.2 Deletion

bindkey '^?' backward-delete-char
bindkey "^[[3~" delete-char
bindkey "^[3;5~" delete-char
bindkey "\e[3~" delete-char
bindkey \^U backward-kill-line

2.8.3 Insert the last shell word again

bindkey "^[m" copy-prev-shell-word

2.8.4 URLs

autoload -U url-quote-magic
zle -N self-insert url-quote-magic

2.8.5 Options

setopt no_beep \
    rm_star_wait

2.8.6 sudo

run-with-sudo () { LBUFFER="sudo $LBUFFER" }
zle -N run-with-sudo
bindkey '^Xs' run-with-sudo  

2.8.7 Empty ^I lists directory

complete-or-list() {
    [[ $#BUFFER != 0 ]] && { zle complete-word ; return 0 }
    echo
    ls
    zle reset-prompt
}
zle -N complete-or-list
bindkey '^I' complete-or-list

2.8.8 Pipe to

typeset -Ag abbreviations
abbreviations=(
    "Il"    "| less"
    "Ia"    "| awk"
    "Ig"    "| grep"
    "Ieg"   "| egrep"
    "Iag"   "| agrep"
    "Ih"    "| head"
    "Ik"    "| keep"
    "It"    "| tail"
    "Is"    "| sort"
    "Iv"    "| ${VISUAL:-${EDITOR}}"
    "Iw"    "| wc"
    "Ix"    "| xargs"
)

magic-abbrev-expand() {
    local MATCH
    LBUFFER=${LBUFFER%%(#m)[_a-zA-Z0-9]#}
    LBUFFER+=${abbreviations[$MATCH]:-$MATCH}
    zle self-insert
}
        
no-magic-abbrev-expand() {
    LBUFFER+=' '
}
        
zle -N magic-abbrev-expand
zle -N no-magic-abbrev-expand
bindkey " " magic-abbrev-expand
bindkey "^x " no-magic-abbrev-expand
bindkey -M isearch " " self-insert

2.9 History

2.9.1 Variables

HISTFILE=~/.histfile
HISTSIZE=10000
SAVEHIST=10000

2.9.2 Options

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
setopt hist_fcntl_lock 
setopt hist_ignore_all_dups

2.9.3 Aliases

lh is short for load history, fc is a zsh-builtin to access the history. -R rereads the history - in this case from the standard history file. -I only appends new entries from this file to the current active history of the shell process.

	 alias lh='fc -RI'  

2.9.4 Functions

function zsh_stats() {
  history | awk '{print $2}' | sort | uniq -c | sort -rn | head
}  

2.9.5 Keybindings

bindkey '^r' history-incremental-search-backward
bindkey "^[[5~" up-line-or-history
bindkey "^[[6~" down-line-or-history
bindkey '�OA' up-line-or-search
bindkey '�OB' down-line-or-search
bindkey '^P' up-line-or-search
bindkey '^N' down-line-or-search

2.10 Jobcontrol

2.10.1 Options

setopt long_list_jobs

2.11 Autocorrection

I use autocorrection, but define a couple of aliases for commands for which I don’t want correction.

2.11.1 Options

setopt correct \
    correct_all 

2.11.2 Aliases

alias man='nocorrect man'
alias mv='nocorrect mv'
alias mkdir='nocorrect mkdir'
alias gist='nocorrect gist'
alias ebuild='nocorrect ebuild'

2.12 Directory traversal and manipulation

2.12.1 Options

setopt auto_name_dirs
setopt auto_pushd
setopt auto_cd
setopt pushd_ignore_dups
setopt pushd_silent

2.12.2 Aliases

alias ..='cd ..'
alias cd..='cd ..'
alias cd...='cd ../..'
alias cd....='cd ../../..'
alias cd.....='cd ../../../..'
alias cd/='cd /'

alias md='mkdir -p'
alias rd=rmdir
alias d='dirs -v'  

2.12.3 Functions

cd () {
  if   [[ "x$*" == "x..." ]]; then
    cd ../..
  elif [[ "x$*" == "x...." ]]; then
    cd ../../..
  elif [[ "x$*" == "x....." ]]; then
    cd ../../..
  elif [[ "x$*" == "x......" ]]; then
    cd ../../../..
  else
    builtin cd "$@"
  fi
}
function mcd() { 
  mkdir -p "$1" && cd "$1"; 
}    

2.13 Hooks

I use hooks in my prompt setup
autoload -U add-zsh-hook 

2.14 Terminal

2.14.1 Colors

eval $(dircolors)

2.14.2 Title

In omz_termsupport_preexec $( and % are escaped in the second argument to function title(); this is to prevent multiple execution of the $() command – prompt substitution as used in title (option -P to print) would execute the command at least once, and confusion of % tags to commands like date with prompt % tags.

function title {
  [ "$DISABLE_AUTO_TITLE" != "true" ] || return
  if [[ "$TERM" == screen* ]]; then
    print -Pn "\ek$1:q\e\\" #set screen hardstatus, usually truncated at 20 chars
  elif [[ "$TERM" == xterm* ]] || [[ $TERM == rxvt* ]] || [[ "$TERM_PROGRAM" == "iTerm.app" ]]; then
   print -Pn "\e]2;$2:q\a" #set window name
   print -Pn "\e]1;$1:q\a" #set icon (=tab) name (will override window name on broken terminal)
  fi
}

ZSH_THEME_TERM_TAB_TITLE_IDLE="%15<..<%~%<<" #15 char left truncated PWD
ZSH_THEME_TERM_TITLE_IDLE="%n@%m: %~"

#Appears when you have the prompt
function omz_termsupport_precmd {
  title $ZSH_THEME_TERM_TAB_TITLE_IDLE $ZSH_THEME_TERM_TITLE_IDLE
}

#Appears at the beginning of (and during) of command execution
function omz_termsupport_preexec {
  emulate -L zsh
  setopt no_extended_glob
  local CMD_1=${1[(wr)^(*=*|sudo|ssh|-*)]} #cmd name only, or if this is sudo or ssh, the next cmd
  local CMD_2=${2//\$\(/\\\$(} # ')}
  CMD_1=${CMD_1//\%/%%}          
  CMD_2=${CMD_2//\%/%%}          
  #
  title "${CMD_1}" "%100>...>${CMD_2}%<<"
}

add-zsh-hook precmd  omz_termsupport_precmd
add-zsh-hook preexec omz_termsupport_preexec

2.14.3 tmux

tmux wrapper that adds new commands to update environment variables in running panes/windows

function tmux() {
    case "$1" in
        update-environment|update-env|env-update)
            local v
            command tmux show-environment | while read v; do
                if [[ "$v" == -* ]]; then
                    unset ${v/#-/}
                else
                    # Add quotes around the argument
                    v=${v/=/\=\"}
                    v=${v/%/\"}
                    eval export $v
                fi
            done 
            ;;
        *)
            command tmux "$@"
            ;;
    esac
}

2.15 Prompt

2.15.1 Module

autoload -U promptinit; promptinit
autoload -Uz vcs_info
zstyle ':vcs_info:*' enable git svn
precmd() {
    vcs_info
}
setopt prompt_subst

2.15.2 Configure theme

2.15.2.1 Load all the icons…

if [ -f ~/.local/share/icons-in-terminal/icons_bash.sh ]; then
	. ~/.local/share/icons-in-terminal/icons_bash.sh
elif [ -f /usr/share/icons-in-terminal/icons_bash.sh ]; then
	. /usr/share/icons-in-terminal/icons_bash.sh
fi

2.15.2.2 php block

Do not show the nodejs block, show our new shiny php block instead.

  BLOX_BLOCK__PHP_SYMBOL="${BLOX_BLOCK__PHP_SYMBOL:-${file_php:-php} }"
  BLOX_BLOCK__PHP_COLOR="${BLOX_BLOCK__PHP_COLOR:-green}"
  function blox_block__php() {
	  if [ -n "$(find_root "$PWD" RoboFile.php)" ]; then
		  PHPV=$(php --version | head -n 1 | cut -d- -f1 | sed 's/PHP //' | cut -d\  -f1)
		  blox_helper__build_block \
			  "${BLOX_BLOCK__PHP_COLOR}" \
			  "${BLOX_BLOCK__PHP_SYMBOL}${PHPV}"
	  fi
  }
export BLOX_SEG__UPPER_RIGHT=( bgjobs php pyenv virtualenv time )

2.16 GNU global

export GTAGSCONF=/usr/local/share/gtags/gtags.conf
export GTAGSLABEL=pygments

2.17 Groovy

source ~/.gvm/bin/gvm-init.sh

2.18 Git

2.18.1 Prompt

If there is on thing I had to name, that made me crave for oh-my-zsh it was the right site prompt stating repository state; here are the functions I ripped from it…

function git_prompt_info() {
    ref=$(git symbolic-ref HEAD 2> /dev/null) || return
    echo "$ZSH_THEME_GIT_PROMPT_PREFIX${ref#refs/heads/}$(parse_git_dirty)$ZSH_THEME_GIT_PROMPT_SUFFIX"
}

function parse_git_dirty() {
    if [[ -n $(git status -s --ignore-submodules=dirty 2> /dev/null) ]]; then
        echo "$ZSH_THEME_GIT_PROMPT_DIRTY"
    else
        echo "$ZSH_THEME_GIT_PROMPT_CLEAN"
    fi
}

function git_prompt_ahead() {
    if $(echo "$(git log origin/$(current_branch)..HEAD 2> /dev/null)" | grep '^commit' &> /dev/null); then
        echo "$ZSH_THEME_GIT_PROMPT_AHEAD"
    fi
}

function git_prompt_short_sha() {
    SHA=$(git rev-parse --short HEAD 2> /dev/null) && echo "$ZSH_THEME_GIT_PROMPT_SHA_BEFORE$SHA$ZSH_THEME_GIT_PROMPT_SHA_AFTER"
}

function git_prompt_long_sha() {
    SH A=$(git rev-parse HEAD 2> /dev/null) && echo "$ZSH_THEME_GIT_PROMPT_SHA_BEFORE$SHA$ZSH_THEME_GIT_PROMPT_SHA_AFTER"
}

function git_prompt_status() {
    INDEX=$(git status --porcelain 2> /dev/null)
    STATUS=""
    if $(echo "$INDEX" | grep '^?? ' &> /dev/null); then
        STATUS="$ZSH_THEME_GIT_PROMPT_UNTRACKED$STATUS"
    fi
    if $(echo "$INDEX" | grep '^A  ' &> /dev/null); then
        STATUS="$ZSH_THEME_GIT_PROMPT_ADDED$STATUS"
    elif $(echo "$INDEX" | grep '^M  ' &> /dev/null); then
        STATUS="$ZSH_THEME_GIT_PROMPT_ADDED$STATUS"
    fi
    if $(echo "$INDEX" | grep '^ M ' &> /dev/null); then
        STATUS="$ZSH_THEME_GIT_PROMPT_MODIFIED$STATUS"
    elif $(echo "$INDEX" | grep '^AM ' &> /dev/null); then
        STATUS="$ZSH_THEME_GIT_PROMPT_MODIFIED$STATUS"
    elif $(echo "$INDEX" | grep '^ T ' &> /dev/null); then
        STATUS="$ZSH_THEME_GIT_PROMPT_MODIFIED$STATUS"
    fi
    if $(echo "$INDEX" | grep '^R  ' &> /dev/null); then
        STATUS="$ZSH_THEME_GIT_PROMPT_RENAMED$STATUS"
    fi
    if $(echo "$INDEX" | grep '^ D ' &> /dev/null); then
        STATUS="$ZSH_THEME_GIT_PROMPT_DELETED$STATUS"
    elif $(echo "$INDEX" | grep '^AD ' &> /dev/null); then
        STATUS="$ZSH_THEME_GIT_PROMPT_DELETED$STATUS"
    fi
    if $(echo "$INDEX" | grep '^UU ' &> /dev/null); then
        STATUS="$ZSH_THEME_GIT_PROMPT_UNMERGED$STATUS"
    fi
    echo $STATUS
}

2.18.2 Commands

autoload -Uz gitaliasinit; gitaliasinit
autoload -Uz find_root

2.19 Build packages

autoload -Uz stumpdeb

3 zlogin

# Load RVM into a shell session *as a function
[[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm"
if [ "$0" = "/usr/sbin/lightdm-session" -a "$DESKTOP_SESSION" = "i3" ]; then
  export $(gnome-keyring-daemon -s)
fi

4 Library

4.1 Plugins

4.1.1 Write plugin list

yardnsm/blox-zsh-theme
hlissner/zsh-autopair
zsh-users/zsh-completions
zsh-users/zsh-autosuggestions
zsh-users/zsh-history-substring-search
zsh-users/zsh-syntax-highlighting

4.1.2 source the generated shell-file

[ -f ~/.zsh.d/plugins.sh ] && source ~/.zsh.d/plugins.sh

4.2 Git

4.2.1 Init

_GITALIAS_DIR=${:-~/.zsh.d/functions/git}
gitaliasinit() {
    fpath=($_GITALIAS_DIR $fpath)
    for gitalias in $_GITALIAS_DIR/*; do
        if [[ -r $gitalias ]]; then
            name=$gitalias:t
            autoload -Uz $name
        fi
    done
}

[[ -o kshautoload ]] || gitaliasinit "$@"

4.2.2 Add

git add "${argv[@]}"

4.2.3 Commit

git commit "${argv[@]}"

4.2.4 Diff

git diff "${argv[@]}"

4.2.5 Log

git log "${argv[@]}"

4.2.6 Stat

git status "${argv[@]}"

4.2.7 TODO Pull

The normal git pull

git pull "${argv[@]}"

Update a local branch from updated master

checkout master && pull && checkout local && git merge master

Update org-mode from maint, not master

checkout maint && pull && checkout local && git merge maint

4.2.8 Push

git push "${argv[@]}"

4.2.9 Checkout

git checkout "${argv[@]}"

4.2.10 Clone

git clone "${argv[@]}"

4.3 Installation/Packaging

4.3.1 stumpwm

pushd ~/Projekte/stumpwm-contrib/
git pull
popd
pushd ~/Projekte/stumpwm
mkdir -p usr/local/bin
mkdir -p usr/local/share/stumpwm/lisp
mkdir -p usr/local/share/info
cp stumpwm usr/local/bin
find ~/Projekte/stumpwm-contrib -maxdepth 1 -mindepth 1 -name '[a-z]*' -type d -print0 | xargs -0 -ILISP cp -a LISP usr/local/share/stumpwm/lisp/
cp stumpwm.info usr/local/share/info/
gzip usr/local/share/info/stumpwm.info
fpm -t deb -s dir -n stumpwm -v $(date +"%Y%m%d") -d sbcl usr/
popd

4.4 Project tools

4.4.1 find project root

local look_from=${1:-$PWD}
local look_for=${2:-}
local look_until=${${3:-/}:A}

# Manually look in parent dirs. An extended Zsh glob should use Y1 for
#   # performance reasons, which is only available in zsh-5.0.5-146-g9381bb6.
local last
local parent_dir="$look_from"
local abs_parent_dir
while true; do
	abs_parent_dir=${parent_dir:A}
	if [[ $abs_parent_dir == $last ]]; then
		break
	fi
	local parent_file="${parent_dir}/${look_for}"

	if [[ -f $parent_file ]]; then
		if [[ ${parent_file[1,2]} == './' ]]; then
			echo ${parent_file#./}
		else
			echo ${parent_file:a}
		fi
		break
	fi

	if [[ $abs_parent_dir == $look_until ]]; then
		break
	fi
	last=$abs_parent_dir
	parent_dir="${parent_dir}/.."
done