Skip to content

Instantly share code, notes, and snippets.

@andrewelkins
Last active February 14, 2020 21:28
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save andrewelkins/e98fbaef9cf4ebf2392226682b42c611 to your computer and use it in GitHub Desktop.
Save andrewelkins/e98fbaef9cf4ebf2392226682b42c611 to your computer and use it in GitHub Desktop.
a zshrc configuration file
# .zshrc interactive configuration file for zsh
# Thanks to klapmuetz, caphuso, Mikachu, +chris+, zshwiki.org.
# Originally from http://leahneukirchen.org/dotfiles/.zshrc
# first revision: 26/09/2019 andrew
#
# Path to your oh-my-zsh installation.
export ZSH="/Users/$USER/.oh-my-zsh"
## Addresses bash and pre installed item
export PATH=$HOME/bin:/usr/local/bin:$PATH
# Anaconda Python/R
export PATH="/usr/local/anaconda3/bin:$PATH"
# NVM Stuff
export NVM_DIR="$HOME/.nvm"
. "$(brew --prefix nvm)/nvm.sh"
# Set name of the theme to load --- if set to "random", it will
# load a random theme each time oh-my-zsh is loaded, in which case,
# to know which specific one was loaded, run: echo $RANDOM_THEME
# See https://github.com/robbyrussell/oh-my-zsh/wiki/Themes
ZSH_THEME="robbyrussell"
#ZSH_THEME="spaceship"
#ZSH_THEME="powerlevel9k/powerlevel9k"
#ZSH_THEME="agnoster"
plugins=(
vscode
)
source $ZSH/oh-my-zsh.sh
## Addresses bash and pre installed item
#export PATH=$HOME/bin:/usr/local/bin:$PATH
# Anaconda Python/R
#export PATH="/usr/local/anaconda3/bin:$PATH"
# z fast complete
. `brew --prefix`/etc/profile.d/z.sh
# == OPTIONS
setopt NO_BEEP
setopt C_BASES
setopt OCTAL_ZEROES
setopt PRINT_EIGHT_BIT
setopt SH_NULLCMD
setopt AUTO_CONTINUE
setopt NO_BG_NICE
setopt PATH_DIRS
setopt NO_NOMATCH
setopt EXTENDED_GLOB
disable -p '^'
setopt LIST_PACKED
setopt BASH_AUTO_LIST
setopt NO_AUTO_MENU
setopt NO_CORRECT
setopt NO_ALWAYS_LAST_PROMPT
setopt NO_FLOW_CONTROL
setopt AUTO_PUSHD
setopt PUSHD_IGNORE_DUPS
setopt PUSHD_MINUS
setopt HIST_IGNORE_DUPS
setopt HIST_IGNORE_SPACE
setopt INC_APPEND_HISTORY
setopt EXTENDED_HISTORY
export HISTSIZE=1000000000
export SAVEHIST=$HISTSIZE
setopt EXTENDED_HISTORY
# save every command before it is executed
setopt inc_append_history
# read history everytime before executing history
setopt share_history
HISTFILE=~/.zsh_history
LISTMAX=0
REPORTTIME=60
TIMEFMT="%J %U user %S system %P cpu %MM memory %*E total"
MAILCHECK=0
# == PROMPT
# gitpwd - print %~, limited to $NDIR segments, with inline git branch
NDIRS=2
gitpwd() {
local -a segs splitprefix; local gitprefix 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]}}"
}
nbsp=$'\u00A0'
# == COMPLETION
zmodload zsh/complist
autoload -Uz compinit && compinit
zstyle ':completion:*' squeeze-slashes true
zstyle ':completion:*' special-dirs ..
zstyle ':completion:*' accept-exact-dirs true
zstyle ':completion:*' use-ip true
zstyle ':completion::*' insert-tab true
zstyle ':completion::complete:*' use-cache on
zstyle ':completion::complete:*' rehash true
zstyle ':completion:*:functions' ignored-patterns '_*'
zstyle ':completion:*:*:*:*:processes*' force-list always
zstyle ':completion:*:*:kill:*:processes' insert-ids single
zstyle ':completion:*:*:kill:*:processes' sort false
zstyle ':completion:*:*:kill:*:processes' command 'ps -u "$USER"'
zstyle ':completion:*:processes-names' command "ps -eo cmd= | sed 's:\([^ ]*\).*:\1:;s:\(/[^ ]*/\)::;/^\[/d'"
zstyle ':completion:*:evince::' \
file-patterns '*.(#i)(dvi|djvu|tiff|pdf|ps|xps)(|.bz2|.gz|.xz|.z) *(-/)' '*'
compdef pkill=killall
compdef ping6=ping
compdef _gnu_generic curl emacs emacsclient file head mv paste
compdef _gnu_generic tail touch scrot shred watch wc zsh
# Don't complete the same twice for kill/diff.
# 25nov2010 +chris+
zstyle ':completion:*:(kill|diff):*' ignore-line yes
# Don't complete from PATH for sh and rc.
# 27mar2018 +leah+
zstyle ':completion:*:(sh|rc):*' tag-order '! commands builtins' -
# Don't complete backup files as commands.
# 29sep2012 +chris+
zstyle ':completion:*:complete:-command-::*' ignored-patterns '*\~'
# Don't complete .pdf for less.
# 09apr2018 +leah+
zstyle ':completion:*:less:*' file-patterns '*~*.pdf'
# Lax completion for cd
# 23feb2019 +leah+
# 01mar2019 +leah+ fix uppercase completion
# 03mar2019 +leah+ use explicit tag-order
zstyle ':completion:*:cd:*' tag-order '*' '*:-case'
zstyle ':completion:*-case' matcher 'm:{a-zA-Z0-9}={A-Za-z0-9}' 'l:|=* r:|=*'
# Cycle through history completion (M-/, M-,).
# 12mar2013 +chris+
zstyle ':completion:history-words:*:history-words' stop yes
zstyle ':completion:history-words:*:history-words' list no
zstyle ':completion:history-words:*' remove-all-dups yes
# == ZLE
# Emacs keybindings have been set above.
# Disable bracketed paste.
# 31aug2015 +chris+
unset zle_bracketed_paste
# This is even better than copy-prev-shell-word, can be called repeatedly.
# 12mar2013 +chris+
autoload -Uz copy-earlier-word
zle -N copy-earlier-word
bindkey "^[m" copy-earlier-word
# Remove prompt on line paste (cf. last printed char in cnprompt6).
# 09mar2013 +chris+
bindkey -s $nbsp '^u'
# Shortcut for ' inside ' quoting
# 14mar2016 +chris+
bindkey -s "\C-x'" \''\\'\'\'
# Expand to two last commands
# 09nov2017 +leah+
bindkey -s "\C-x2" '!-2\t ; !-1\t'
# Move by physical lines, like gj/gk in vim
# 09apr2013 +chris+
_physical_up_line() { zle backward-char -n $COLUMNS }
_physical_down_line() { zle forward-char -n $COLUMNS }
zle -N physical-up-line _physical_up_line
zle -N physical-down-line _physical_down_line
bindkey "\e\e[A" physical-up-line
bindkey "\e\e[B" physical-down-line
# M-DEL should stop at /.
# 25mar2007 +chris+
# 28feb2011 +chris+
WORDCHARS="*?_-.[]~&;$%^+"
# backward-kill-default-word (with $WORDCHARS from zsh -f and :)
# 26jun2012 +chris+
_backward_kill_default_word() {
WORDCHARS='*?_-.[]~=/&:;!#$%^(){}<>' zle backward-kill-word
}
zle -N backward-kill-default-word _backward_kill_default_word
bindkey '\e=' backward-kill-default-word # = is next to backspace
# transpose-words acts on shell words
# 03mar2014 +chris+
autoload -Uz transpose-words-match
zstyle ':zle:transpose-words' word-style shell
zle -N transpose-words transpose-words-match
# History search with globs.
# 21sep2011 +chris+
# 05jun2012 +chris+ and keeping the rest of the line
# 22apr2016 +chris+ space for *
autoload -Uz narrow-to-region
_history-incremental-preserving-pattern-search-backward() {
local state
MARK=CURSOR # magick, else multiple ^R don't work
narrow-to-region -p "$LBUFFER${BUFFER:+>>}" -P "${BUFFER:+<<}$RBUFFER" -S state
zle end-of-history
zle history-incremental-pattern-search-backward
narrow-to-region -R state
}
zle -N _history-incremental-preserving-pattern-search-backward
bindkey "^R" _history-incremental-preserving-pattern-search-backward
bindkey -M isearch "^R" history-incremental-pattern-search-backward
bindkey -M isearch -s ' ' '*'
bindkey -M isearch -s ' ' '[[:blank:]]'
bindkey "^S" history-incremental-pattern-search-forward
# Quote stuff that looks like URLs automatically.
# 19jul2008 +chris+
# 02dec2014 +chris+
autoload -U url-quote-magic
zstyle ':urlglobber' url-other-schema ftp git gopher http https magnet
zstyle ':url-quote-magic:*' url-metas '*?[]^(|)~#=' # dropped { }
zle -N self-insert url-quote-magic
# Edit command line with $VISUAL.
# 26jul2010 +chris+
autoload -z edit-command-line
zle -N edit-command-line
bindkey "^X^E" edit-command-line
# Force file name completion on C-x TAB, Shift-TAB.
# 23dec2010 +chris+
# 28may2016 +chris+ also complete words already on the command line
autoload -Uz match-words-by-style
_args() {
local -a ign
match-words-by-style
[[ -z "$matched_words[3]" ]] && ign=("$matched_words[2]$matched_words[5]")
compadd -F ign -- ${(Q)${(z)BUFFER}}
}
zle -C complete-files complete-word _generic
zstyle ':completion:complete-files:*' completer _files _args
zstyle ':completion:complete-files:*' force-list always
bindkey "^X^I" complete-files
bindkey "^[[Z" complete-files
# Force menu on C-f.
# 29dec2010 +chris+
# 21sep2011 +chris+
# 04jan2013 +chris+ rewritten using menu-select
zle -C complete-menu menu-select _generic
_complete_menu() {
setopt localoptions alwayslastprompt
zle complete-menu
}
zle -N _complete_menu
bindkey '^F' _complete_menu
bindkey -M menuselect '^F' accept-and-infer-next-history
bindkey -M menuselect '/' accept-and-infer-next-history
bindkey -M menuselect '^?' undo
bindkey -M menuselect ' ' accept-and-hold
bindkey -M menuselect '*' history-incremental-search-forward
# Move to where the arguments belong.
# 24dec2010 +chris+
after-first-word() {
zle beginning-of-line
zle forward-word
}
zle -N after-first-word
bindkey "^X1" after-first-word
# Scroll up in tmux on PageUp.
# 14jan2016 +chris+
_tmux_copy_mode() { tmux copy-mode -eu }
zle -N _tmux_copy_mode
[[ $TMUX_PANE && -n $terminfo[kpp] ]] && bindkey $terminfo[kpp] _tmux_copy_mode
# fg editor on ^Z
# 27sep2011 +chris+
# 17feb2012 +chris+
foreground-vi() { fg %vi }
zle -N foreground-vi
bindkey '^Z' foreground-vi
# Allow to recover from C-c or failed history expansion (thx Mikachu).
# 26may2012 +chris+
_recover_line_or_else() {
if [[ -z $BUFFER && $CONTEXT = start && $zsh_eval_context = shfunc
&& -n $ZLE_LINE_ABORTED
&& $ZLE_LINE_ABORTED != $history[$((HISTCMD-1))] ]]; then
LBUFFER+=$ZLE_LINE_ABORTED
unset ZLE_LINE_ABORTED
else
zle .$WIDGET
fi
}
zle -N up-line-or-history _recover_line_or_else
_zle_line_finish() { ZLE_LINE_ABORTED=$BUFFER }
zle -N zle-line-finish _zle_line_finish
# Inject mkdir call to create the dirname of the current argument.
# 10mar2015 +chris+
autoload -Uz modify-current-argument
_mkdir_arg() {
local arg=
modify-current-argument '${arg:=$ARG}'
zle push-line
LBUFFER=" mkdir -p $arg:h"
RBUFFER=
}
zle -N mkdir-arg _mkdir_arg
bindkey '^[M' mkdir-arg
# Keep an archive of all commands typed.
# Initialize using:
# cat /data/dump/juno/2015<->/home/chris/.zsh_history | sort -u | grep '^:' |
# gawk -F: '{print $0 >> "chris@juno-" strftime("%Y-%m-%d", $2)}'
# 04sep2015 +chris+
# 02sep2016 +chris+ store directory
# 01sep2019 +leah+ create dir if needed
[ -d ~/.zarchive ] || mkdir -p ~/.zarchive
zshaddhistory() {
local words=( ${(z)1} )
local w1=$words[1]
(( $+aliases[$w1] )) && w1=$aliases[$w1]
if [[ -n $1 && $1 != $'\n' && $w1 != " "* ]]; then
printf ': %s:%s:0;%s' ${(%):-'%D{%s}'} ${(%):-%~} "$1" >> \
~/.zarchive/${(%):-%n@%m-'%D{%Y-%m-%d}'}
fi
}
# za WORDS... - search .zarchive for WORDS
# 04sep2015 +chris+
za() {
grep -a -r -e "${(j:.*:)@}" ~/.zarchive |
sed 's/[ \t]*$//' |
sort -r | sort -t';' -k2 -u | sort |
sed $'s,^[^:]*/,,; s,::[^;]*;,\u00A0\u00A0,'
}
alias za=' za'
# zd [WORDS...] - list last commands in PWD from .zarchive
# 02sep2016 +chris+
zd() {
grep -a -r -e :${(%):-%~}: ~/.zarchive |
sed 's/[ \t]*$//' |
sort -r | sort -t';' -k2 -u | sort |
awk -F: -v dir=${(%):-%~} '$4 == dir && $5 ~ /^0;/' |
sed $'s,^[^:]*/,,; s,::[^;]*;,\u00A0\u00A0,'
}
alias zd=' zd'
# == ALIASES
alias hsitory='history'
alias hh='history'
alias mtr='mtr -t'
alias packer='COLOR=NO packer'
alias ping6='ping -6'
alias sort='LC_ALL=C sort'
(( $+commands[vim] )) && alias vi='vim'
alias texclean='rm -f *.toc *.aux *.log *.cp *.fn *.tp *.vr *.pg *.ky *.synctex.gz'
alias em='emacsclient -n'
alias dotf='ls .[a-zA-Z0-9_]*'
alias vil='vi *(.om[1]^D)'
alias cad='cat >/dev/null'
alias d.='df -h . |sed 1d'
alias s.='du -sh .'
alias pst='ps -o tname,user,bsdtime,pid,cmd -H'
alias exzsh='zsh -is eval \ zsh --version\; echo \$ZSH_PATCHLEVEL\; PS1="%#\ "'
alias zat='zathura --fork'
for cmd (coqtop ocaml MathKernel maxima k q ${(Mk)commands:#k[67-]*})
(( $+commands[$cmd] )) && alias $cmd="rlwrap $cmd"
autoload zmv
alias zzmv='noglob zmv -W'
# 29feb2008 +chris+
# 13apr2010 +chris+ allow completion
# 18dec2012 +chris+ set work tree too
alias homegit="GIT_DIR=~/prj/dotfiles/.git GIT_WORK_TREE=~ git"
hash -d mess=~/mess/current
hash -d uni=~/uni/current
hash -d phd=~/phd/current
hash -d wwwtmp=chris@chneukirchen.org:/srv/http/chneukirchen.org/tmp
# == FUNCTIONS
# j -- search jobs
# 15oct2017 +leah+ convert from alias
j() { jobs -l | grep ${@:-.} || echo no jobs running }
# mess -- switch to current mess folder, creating it if needed
# 17may2008 +chris+
mess phd () {
set +e
DIR=~/$0/$(date +%G/%V)
[[ -d $DIR ]] || {
mkdir -p $DIR
ln -sfn $DIR ~/$0/current
echo "Created $DIR."
}
cd ~/$0/current
}
# preserve cd -
# 21feb2011 +chris+
# 12feb2012 +chris+ save full dirstack, adopted from grml
# 02feb2013 +chris+ only add $PWD to file, better for multiple shells
DIRSTACKSIZE=9
DIRSTACKFILE=~/.zdirs
touch $DIRSTACKFILE
if [[ $#dirstack -eq 0 ]]; then
dirstack=( ${(f)"$(< $DIRSTACKFILE)"} )
[[ -d $dirstack[1] ]] && cd $dirstack[1] && cd $OLDPWD
fi
chpwd_dirstack() {
local -a dirs; dirs=( "$PWD" ${(f)"$(< $DIRSTACKFILE)"} )
print -l ${${(u)dirs}[0,$DIRSTACKSIZE]} >$DIRSTACKFILE
}
# img -- display given or all images with the currently preferred viewer
# 01jun2010 +chris+
# 01apr2013 +chris+ back to feh
# 15sep2013 +chris+ back to qiv
# 30aug2017 +chris+ try pqiv
# img() { qiv -ftuNRi ${*:-.} }
img() { pqiv -flni ${*:-.} }
# h -- grep history
# 08mar2011 +chris+
# 14mar2011 +chris+
# 08dec2011 +chris+
# 19mar2014 +chris+ work without argument
h() { fc -l 0 -1 | sed -n "/${1:-.}/s/^ */!/p" | tail -n ${2:-10} }
alias h=' h'
# sucdo -- su -c like sudo without quotes
# 21mar2011 +chris+
# 29mar2016 +chris+ proper quoting
sucdo() { su -c "${(j: :)${(q)@}}" }
compdef sucdo=sudo
# zman -- easier browsing of zsh manpage
# 20sep2011 +chris+
# 16mar2015 +chris+ mdocml splits on any space in $PAGER
zman() { PAGER="less -g -s +/^\s{7}$1" man zshall }
# g -- call grep recursively with useful defaults
# 02oct2011 +chris+
# 10jan2012 +chris+ take an directory as possible last argument
# 28nov2012 +chris+ use grep -r
# 15dec2013 +chris+ use LC_ALL=C for speed and UTF-8 segfaults with -P
# 13may2015 +chris+ use directory only when more than two arguments
# 22feb2016 +chris+ line-buffered to quicker pipes
# 14aug2016 +chris+ same for git-grep
# 27sep2016 +chris+ '+ext' to expand to --include=*.ext
g() {
LC_ALL=C grep \
${${(M)@:#+*}:s/+/--include=*./} \
--exclude "*~" --exclude "*.o" --exclude "tags" \
--exclude-dir .bzr --exclude-dir .git --exclude-dir .hg --exclude-dir .svn \
--exclude-dir _build \
--line-buffered -r -P ${${@:#+*}:?regexp missing}
}
gg() {
local p=$argv[-1]
(( ARGC > 1 )) && { git rev-parse -q --verify $p >/dev/null || [ -d $p ] } &&
argv[-1]=() || p='HEAD'
LC_ALL=C git grep -P ${@:?regexp missing} $p
}
# gl -- find file names in Git
# 23sep2016 +chris+
#gl() {
# local p=$argv[-1]
# (( ARGC > 1 )) && { p=$p/; argv[-1]=(); } || p=':/'
# git ls-files --exclude-standard "$p" | egrep "${@:-.}"
#}
# d -- use g to find a definition (start of line, Go, Ocaml, Ruby, Rust)
# 07apr2014 +chris+
# 13may2015 +chris+
# 21jan2017 +leah+ ignore binary
# 10feb2018 +leah+ fix #define, better output
# 15aug2019 +leah+ revert output
d() {
g -IHn '(^|(#define|\b(func|let|let rec|class|module|def|fn))\s+)'"$@"
}
# l -- find file names, recursively
# 20jun2012 +chris+ take a directory as possible last argument
#l() {
# local p=$argv[-1]
# [[ -d $p ]] && { argv[-1]=(); } || p='.'
# find $p ! -type d | sed 's:^\./::' | egrep "${@:-.}"
#}
# 02feb2019 +leah+
# L -- l, with fzf
L() {
local p=$argv[-1]
[[ -d $p ]] && { argv[-1]=(); } || p='.'
lr -0 -t 'type != d' $p | sed -z 's:^\./::' |
fzf --read0 -0 +s -e ${@:+-q "${@:-.} "}
}
# v - vim -q from stdin
# 14aug2019 +leah+ use quickfix
# 15aug2019 +leah+
v qvim() {
vim --cmd "set efm=%f:%l:%c:%m,%f:%l:%m,%f:%s,%f" \
-q <(if (( $# )); then printf '%s\n' "$@"; else cat; fi) </dev/tty
}
# oldv -- browse list of file names (stdin or arglist) with vim
# 14jul2015 +chris+
oldv() {{
tput smcup
{ [[ $# = 0 ]] && cat || print -l -- "$@" } |
vim - '+set nomod | map <buffer><C-M> <C-W>F<C-W>_' \
'+silent g/\%^\%$/cq!' # quit on empty file
} always {
tput rmcup
}}
# this didnt understand file:line:
# vim - '+set nomod | map <buffer><C-M> :1000sp <cfile><C-M>'
# vl -- browse l with vim/v
# 25mar2015 +chris+
# 14jul2015 +chris+
# 14aug2019 +leah+
vl() { l "$@" | sort | oldv }
# lr -- a saner ls -R (using find)
# 07jun2013 +chris+
# 24oct2015 +chris+ prefer native implementation
(( $+commands[lr] )) ||
lr() {
zparseopts -D -E S=S t=t r=r h=h U=U l=l F=F d=d
local sort="sort -t/ -k2" # by name (default)
local numfmt="cat"
local long='s:[^/]* /::; s:^\./\(.\):\1:;' # strip detail
local classify=''
[[ -n $F ]] && classify='/^d/s:$:/:; /^-[^ ]*x/s:$:*:;' # dir/ binary*
[[ -n $l ]] && long='s: /\(\./\)\?: :;' # show detail
[[ -n $S ]] && sort="sort -n -k5" # by size
[[ -n $r ]] && sort+=" -r" # reverse
[[ -n $t ]] && sort="sort -k6" && { [[ -n $r ]] || sort+=" -r" } # by date
[[ -n $U ]] && sort=cat # no sort, live output
[[ -n $h ]] && numfmt="numfmt --field=5 --to=iec --padding=6" # human fmt
[[ -n $d ]] && set -- "$@" -prune # don't enter dirs
find "$@" -printf "%M %2n %u %g %9s %TY-%Tm-%Td %TH:%TM /%p -> %l\n" |
$=sort | $=numfmt |
sed '/^[^l]/s/ -> $//; '$long' '$classify
}
alias lr='lr -FGHP'
# alias L='lr -FGHPl'
(( $+commands[lr] )) && alias l1='lr -FGHPl1' ||
l1() { lr -Fl "$@" -maxdepth 1; }
(( $+commands[lr] )) &&
lc() {
lr -AFGH1s -t '!type == d || depth > 0' "$@" |git column --mode=dense --pad=2
}
# lwho - utmp-free replacement for who(1)
(( $+commands[lr] )) && lwho() {
lr -om -t 'name =~ "[0-9][0-9]*$" && uid != 0' \
-f '%u\t%p\t%CF %CR\n' /dev/pts /dev/tty*
}
# imv -- interactive rename, using vared
# 03sep2012 +chris+
# 21jul2014 +chris+
# 09dec2014 +chris+
# 24jul2019 +leah+
imv() {
local src dst
for src; do
[[ -e $src ]] || { print -u2 "$src does not exist"; continue }
dst=$src
vared -f undefined-key dst
[[ $src != $dst ]] && mkdir -p $dst:h && mv -n $src $dst &&
print -s mv -n $src:q:q $dst:q:q # save to history, thus M-. works
done
}
# ichmod -- interactive mode change, using vared
# 24jul2019 +leah+
ichmod() {
local file perm oldperm map stat; integer special
typeset -A map=( --- 0 --x 1 -w- 2 -wx 3 r-- 4 r-x 5 rw- 6 rwx 7 )
for file; do
zstat -H stat -s $file || continue
perm=$stat[mode]
oldperm=$perm
vared -i beginning-of-line -f undefined-key perm
[[ $perm = $oldperm ]] && continue
[[ $perm[1] = $oldperm[1] ]] || { print -u2 "can't change file type of $file"; continue }
special=0
[[ $perm[4] = [sS] ]] && special+=4
[[ $perm[7] = [sS] ]] && special+=2
[[ $perm[10] = [tT] ]] && special+=1
perm=${perm//[st]/x}
perm=${perm//[ST]/-}
chmod -v $special$map[$perm[2,4]]$map[$perm[5,7]]$map[$perm[8,10]] $file
done
}
# hl -- highlight regexps
# 06sep2012 +chris+
#hl() { egrep --color=always -e '' -e${^*} }
# jpid -- map job ids to pids
# 23dec2012 +chris+
jpid() {
local p
# $jobstates uses jobs.c:getjob() and can do %1 or %foo as well.
for id; p+=(${${${jobstates[$id]}#*:*:}%=*})
print $p
}
# px -- verbose pgrep
# 17aug2016 +chris+ reformat VSZ,RSS, print elapsed
px() {
# ps uwwp ${$(pgrep -d, "${(j:|:)@}"):?no matches}
ps wwp ${$(pgrep -d, "${(j:|:)@}"):?no matches} \
-o pid,user:6,%cpu,%mem,vsz:10,rss:10,bsdstart,etime:12,bsdtime,args |
sed '1s/ \(VSZ\|RSS\)/\1/g' |
numfmt --header --field 5,6 --from-unit=1024 --to=iec --format "%5f"
}
# crun -- compile and run .c program
# 24oct2017 +leah+ fix for different dirs than .
crun() {
local cprog=$1; shift
local n=$@[(i)--]
${CC:-cc} -o ${cprog%.*} $cprog $@[1,n-1] && ${${cprog%.*}:a} $@[n+1,-1]
}
# tracing -- run zsh function with tracing
# 16mar2016 +chris+ keep return code
tracing() {
local f=$1; shift
functions -t $f
$f "$@"
local r=$?
functions +t $f
return $r
}
# up [|N|pat] -- go up 1, N or until basename matches pat many directories
# just output directory when not used interactively, e.g. in backticks
# 06sep2013 +chris+
# 11oct2017 +leah+ add completion
up() {
local op=print
[[ -t 1 ]] && op=cd
case "$1" in
'') up 1;;
-*|+*) $op ~$1;;
<->) $op $(printf '../%.0s' {1..$1});;
*) local -a seg; seg=(${(s:/:)PWD%/*})
local n=${(j:/:)seg[1,(I)$1*]}
if [[ -n $n ]]; then
$op /$n
else
print -u2 up: could not find prefix $1 in $PWD
return 1
fi
esac
}
_up() { compadd -V segments -- ${(Oas:/:)PWD} }
compdef _up up
# n -- quickest note taker
# 21nov2013 +chris+
n() { [[ $# == 0 ]] && tail ~/.n || echo "$(date +'%F %R'): $*" >>~/.n }
alias n=' noglob n'
# count - count different lines
# 20jul2014 +chris+ zsh function
count() { sort "$@" | uniq -c | sort -n }
# imgur - post image to imgur.com
# 20jul2014 +chris+ zsh function
# 01apr2016 +chris+ use api v3
imgur() {
curl -H "Authorization: Client-ID 3e7a4deb7ac67da" -F image=@$1 \
https://api.imgur.com/3/upload | sed 's/.*http/http/; s/".*/\n/; s,\\/,/,g'
}
# keep - poor man's version control, make freshly numbered copies
# 20jul2014 +chris+
# 08feb2019 +leah+ err when no arguments are given
keep() {
local f v
[[ $# = 0 ]] && return 255
for f; do
f=$f:A
v=($f.<->(nOnN[1]))
if [[ -n "$v" ]] && cmp $v $f >/dev/null 2>&1; then
print -u2 $v not modified
else
cp -va $f $f.$((${${v:-.0}##*.} + 1))
fi
done
}
# zombies - list all zombies and their parents to kill
# 23jul2014 +chris+ zsh function
zombies() {
ps f -eo state,pid,ppid,comm | awk '
{ cmds[$2] = $NF }
/^Z/ { print $(NF-1) "/" $2 " zombie child of " cmds[$3] "/" $3 }'
}
# zpass - generate random password
# 01nov2014 +chris+
# 10mar2017 +leah+ default to length 12
zpass() {
LC_ALL=C tr -dc '0-9A-Za-z_@#%*,.:?!~' </dev/urandom | head -c${1:-12}
echo
}
# ltime - start and run time of last commands
# 05feb2018 +leah+ use tail -n
ltime() { fc -liDI | tail -n ${1:-10} }
# gman - format manpage using GNU troff
# 10apr2015 +chris+
gman() {
( man -w "$@" 2>/dev/null || printf '%s\n' "$@" ) |
xargs cat |
groff -t -p -I/usr/share/man -Tutf8 -mandoc | less
}
# hman - format manpage as monospace HTML
# 10feb2018 +leah+
hman() { man -T utf8 "$@" | ul | aha }
# sslcat HOST:PORT - print SSL certificate and details
sslcat() {
local cert="$(openssl s_client -connect $1 </dev/null | awk '/^--*BEGIN/,/^--*END/')"
printf '%s\n' "$cert" | openssl x509 -in /dev/stdin -text
printf '%s\n' "$cert" | openssl x509 -in /dev/stdin -noout -sha1 -fingerprint
printf '%s\n' "$cert" | openssl x509 -in /dev/stdin -noout -md5 -fingerprint
}
# clot - fill screen with garbage, as visual separator
# 17aug2015 +chris+
# 11mar2016 +chris+ print seperate lines
clot() {
head -c $((LINES*COLUMNS)) </dev/urandom |
LC_ALL=C tr '\0-\377' ${(l:256::.*o@:)} |
fold -w $COLUMNS
}
# spot - show changes compared to previous line
# 03nov2017 +leah+
spot() {
awk '{ for (i = 1; i <= length($0); i++)
printf("%c", ((l = substr($0, i, 1))!=" " && l!="\t" &&
substr(p, i, 1)==l ? "." : l))
printf("\n"); p = $0; }'
}
# suf FILENAME [SUFFIX] - replace or add suffix
# 02jan2018 +leah+
suf() { print "${1%.*}${2:+.$2}" }
# mdless - read markdown with less
mdless() { pandoc -s -f gfm -t man "$@" | man -l }
# mcal [MONTH] - show calendar for this year's MONTH
# 12dec2017 +leah+ start with Monday
mcal() { cal -m "$@" $(date +%Y) }
# padd [CMD] - allow to run CMD without being in path
typeset -A padds
padd() { padds[$1:t]=$1:A; rehash }
rehash() { local c p; builtin rehash "$@" && for c p (${(kv)padds}) hash $c=$p }
# ghkeys - display github keys
# 23jun2017 +leah+
ghkeys() { curl https://github.com/${^@}.keys }
# cdate - timestamp in my format
# 09jan2016 +chris+
cdate() { print ${(L)${(%):-'%D{%d%b%Y}'}} " +$USER+" }
# dottime - a universal convention for conveying time
# https://dotti.me/
# 31aug2019 +leah+
dottime() {
( export TZ=GMT; print -Pn $'%D{%Y-%m-%dT%H\u00B7%M}' )
print ${${(%):-%D{%z}}%00}
}
# notty - run command without controlling tty
# 29nov2017 +leah+
notty() { s6-cat | setsid -w "$@" | s6-cat }
# wrap - wrap long lines using backslashes
wrap() { perl -pe 's/.{'$(( ${COLUMNS:-80} - 1))'}/$&\\\n/g' -- "$@" }
# meowth - a better cat -vET
# 30nov2016 +chris+
meowth() {
perl -CO -MEncode -pe '
$e=0; $w=4; eval { $_ = decode("UTF-8", $_, Encode::FB_CROAK) } or $w=2;
s/[\x01-\x08\x0E-\x1F\x{80}-\x{FFFFFF}\x80-\xFF]/
sprintf "\x{29fc}%0${w}X\x{29fd}",ord $&/eg;
1 while s/\t/"\x{2014}" x ((length($&)*8 - length($`)%8)-1) . "\x{00BB}"/e;
s/\x0c$/("\x{22EF}"x78)/eg;
y/ \x00\x0b\x0c\r/\x{00B7}\x{2400}\x{240B}\x{240C}\x{240D}/;
s/\n$/\x{23CE}\n/ and $e=1;
END { $e or print "\x{2205}\n"}
' -- "$@"
}
# kcns NS - change k8s namespace for this shell session
# 06jun2019 +leah+
kcns() {
: ${KUBECONFIG:=~/.kube/config}
KUBECONFIG=${KUBECONFIG#/tmp/.kcns.$$:}
kubectl config view --minify -o json |
jq '{kind,apiVersion,"contexts":
( .contexts[0].context |= . + {"namespace":"'$1'"} ).contexts}' \
>/tmp/.kcns.$$
export KUBECONFIG=/tmp/.kcns.$$:$KUBECONFIG
}
alias kn='kubectl get nodes'
alias kp='kubectl get pods'
alias ka='kubectl apply -f'
# collect all chpwd_* hooks
chpwd_functions=( ${(kM)functions:#chpwd?*} )
# == SITE LOCAL CONFIG
[[ -e ~/.zshrc.local ]] && . ~/.zshrc.local || :
# Fix for direnv - https://github.com/direnv/direnv/wiki/Python
# 27/09/2019
show_virtual_env() {
if [[ -n "$VIRTUAL_ENV" && -n "$DIRENV_DIR" ]]; then
echo "($(basename $VIRTUAL_ENV))"
fi
}
PS1='$(show_virtual_env)'$PS1
# Hook up direnv
# 26/09/2019 andrew
eval "$(direnv hook zsh)"
#eval "$(direnv hook $0)"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment