diff --git a/.aliases.zsh b/.aliases.zsh index f2a6205..96da7eb 100644 --- a/.aliases.zsh +++ b/.aliases.zsh @@ -32,6 +32,7 @@ alias gdm='git diff master..HEAD' alias gci='git commit' alias gme='git merge' alias grb='git rebase' +alias grbm='git fetch && git rebase origin/master' alias gls='git ls' alias gld='git ld' diff --git a/.autopair.zsh b/.autopair.zsh new file mode 100644 index 0000000..2cff2e9 --- /dev/null +++ b/.autopair.zsh @@ -0,0 +1,164 @@ +#!/usr/bin/env zsh + +# A widget that auto-inserts matching pairs in ZSH. + +AUTOPAIR_INHIBIT_INIT=${AUTOPAIR_INHIBIT_INIT:-} +AUTOPAIR_BETWEEN_WHITESPACE=${AUTOPAIR_BETWEEN_WHITESPACE:-} + +typeset -gA AUTOPAIR_PAIRS +AUTOPAIR_PAIRS=('`' '`' "'" "'" '"' '"' '{' '}' '[' ']' '(' ')') + +typeset -gA AUTOPAIR_LBOUNDS +AUTOPAIR_LBOUNDS=('`' '`') +AUTOPAIR_LBOUNDS[all]='[.:/\!]' +AUTOPAIR_LBOUNDS[quotes]='[]})a-zA-Z0-9]' +AUTOPAIR_LBOUNDS[braces]='' +AUTOPAIR_LBOUNDS['"']='"' +AUTOPAIR_LBOUNDS["'"]="'" + +typeset -gA AUTOPAIR_RBOUNDS +AUTOPAIR_RBOUNDS[all]='[[{(<,.:?/%$!a-zA-Z0-9]' +AUTOPAIR_RBOUNDS[quotes]='[a-zA-Z0-9]' +AUTOPAIR_RBOUNDS[braces]='' + +#### + +ap-get-pair() { + if [[ -n "$1" ]]; then + echo "${AUTOPAIR_PAIRS[$1]}" + elif [[ -n "$2" ]]; then + local i + for i in ${(@k)AUTOPAIR_PAIRS}; do + [[ "$2" == "${AUTOPAIR_PAIRS[$i]}" ]] && echo "$i" && break + done + fi +} + +ap-boundary-p() { + [[ -n "$1" && "$LBUFFER" =~ "$1$" ]] || [[ -n "$2" && "$RBUFFER" =~ "^$2" ]] +} +ap-next-to-boundary-p() { + local -a groups + groups=(all) + case "$1" in + \'|\"|\`) groups+=quotes ;; + \{|\[|\(|\<) groups+=braces ;; + esac + groups+="$1" + local group + for group in $groups; do + ap-boundary-p "$AUTOPAIR_LBOUNDS[$group]" "$AUTOPAIR_RBOUNDS[$group]" && return 0 + done + return 1 +} + +# If provided pair is balanced in the buffer +ap-balanced-p() { + local lbuf="${LBUFFER//\\$1}" + local rbuf="${RBUFFER//\\$2}" + local llen="${#lbuf//[^$1]}" + local rlen="${#rbuf//[^$2]}" + (( $rlen == 0 && $llen == 0 )) && return 0 + if [[ "$1" == "$2" ]]; then + (( $llen == $rlen || ($llen + $rlen) % 2 == 0 )) && return 0 + else + local l2len="${#lbuf//[^$2]}" + local r2len="${#rbuf//[^$1]}" + local ltotal=$(( $llen - $l2len )) + local rtotal=$(( $rlen - $r2len )) + + (( $ltotal < 0 )) && ltotal=0 + (( $ltotal < $rtotal )) && return 1 + return 0 + fi + return 1 +} + +ap-can-pair-p() { + local rchar=$(ap-get-pair "$KEYS") + + # Don't pair if pair doesn't exist + [[ -z "$rchar" ]] && return 1 + + # Force pair if surrounded by space/[BE]OL, regardless of boundaries/balance + [[ -n "$AUTOPAIR_BETWEEN_WHITESPACE" && \ + "$LBUFFER" =~ "(^|[ ])$" && \ + "$RBUFFER" =~ "^($|[ ])" ]] && return 0 + + # Don't pair quotes if the delimiters are unbalanced + ! ap-balanced-p "$KEYS" "$rchar" && return 1 + + # Don't pair when in front of characters that likely signify the start of a string + # or path (i.e. boundary characters) + ap-next-to-boundary-p "$KEYS" "$rchar" && return 1 + + return 0 +} + +ap-can-skip-p() { + ! [[ -n "$2" && "$RBUFFER[1]" == "$2" && "$LBUFFER[-1]" != '\' ]] && return 1 + [[ "$1" == "$2" ]] && ! ap-balanced-p "$1" "$2" && return 1 + return 0 +} + +ap-can-delete-p() { + local lchar="$LBUFFER[-1]" + local rchar=$(ap-get-pair "$lchar") + ! [[ -n "$rchar" && "$RBUFFER[1]" == "$rchar" ]] && return 1 + [[ "$lchar" == "$rchar" ]] && ! ap-balanced-p "$lchar" "$rchar" && return 1 + return 0 +} + +autopair-self-insert() { + LBUFFER+="$1$2" + zle backward-char +} + +autopair-insert() { + local rchar=$(ap-get-pair "$KEYS") + if [[ "$KEYS" == (\'|\"|\`) ]] && ap-can-skip-p "$KEYS" "$rchar"; then + zle forward-char + elif ap-can-pair-p; then + autopair-self-insert "$KEYS" "$rchar" + else + zle self-insert + fi +} + +autopair-close() { + if ap-can-skip-p $(ap-get-pair "" "$KEYS") "$KEYS" + then zle forward-char + else zle self-insert + fi +} + +autopair-delete() { + ap-can-delete-p && zle .delete-char + zle backward-delete-char +} + +# Initialization +autopair-init() { + zle -N autopair-insert + zle -N autopair-close + zle -N autopair-delete + + local i + for i in ${(@k)AUTOPAIR_PAIRS}; do + bindkey "$i" autopair-insert + bindkey -M isearch "$i" self-insert + done + + local -a l + l=(')' '}' ']') + for i in $l; do + bindkey "$i" autopair-close + bindkey -M isearch "$i" self-insert + done + + bindkey "^?" autopair-delete + bindkey "^h" autopair-delete + bindkey -M isearch "^?" backward-delete-char + bindkey -M isearch "^h" backward-delete-char +} +[[ -z "$AUTOPAIR_INHIBIT_INIT" ]] && autopair-init diff --git a/.completion.zsh b/.completion.zsh index 1c5036c..4881d02 100644 --- a/.completion.zsh +++ b/.completion.zsh @@ -62,3 +62,143 @@ zstyle ':filter-select' max-lines -10 # use $LINES - 10 for filter-select zstyle ':filter-select' rotate-list yes # enable rotation for filter-select zstyle ':filter-select' case-insensitive yes # enable case-insensitive search zstyle ':filter-select' extended-search no # see below + +__zic_fzf_prog() { + [ -n "$TMUX_PANE" ] && [ "${FZF_TMUX:-0}" != 0 ] && [ ${LINES:-40} -gt 15 ] \ + && echo "fzf-tmux -d${FZF_TMUX_HEIGHT:-40%}" || echo "fzf" +} + +__zic_matched_subdir_list() { + local dir length seg starts_with_dir + if [[ "$1" == */ ]]; then + dir="$1" + if [[ "$dir" != / ]]; then + dir="${dir: : -1}" + fi + length=$(echo -n "$dir" | wc -c) + if [ "$dir" = "/" ]; then + length=0 + fi + find -L "$dir" -mindepth 1 -maxdepth 1 -type d 2>/dev/null \ + | cut -b $(( ${length} + 2 ))- | sed '/^$/d' | while read -r line; do + if [[ "${line[1]}" == "." ]]; then + continue + fi + echo "$line" + done + else + dir=$(dirname -- "$1") + length=$(echo -n "$dir" | wc -c) + if [ "$dir" = "/" ]; then + length=0 + fi + seg=$(basename -- "$1") + starts_with_dir=$( \ + find -L "$dir" -mindepth 1 -maxdepth 1 -type d \ + 2>/dev/null | cut -b $(( ${length} + 2 ))- | sed '/^$/d' \ + | while read -r line; do + if [[ "${seg[1]}" != "." && "${line[1]}" == "." ]]; then + continue + fi + if [[ "$line" == "$seg"* ]]; then + echo "$line" + fi + done + ) + if [ -n "$starts_with_dir" ]; then + echo "$starts_with_dir" + else + find -L "$dir" -mindepth 1 -maxdepth 1 -type d \ + 2>/dev/null | cut -b $(( ${length} + 2 ))- | sed '/^$/d' \ + | while read -r line; do + if [[ "${seg[1]}" != "." && "${line[1]}" == "." ]]; then + continue + fi + if [[ "$line" == *"$seg"* ]]; then + echo "$line" + fi + done + fi + fi +} + +_zic_list_generator() { + __zic_matched_subdir_list "${(Q)@[-1]}" | sort +} + +_zic_complete() { + setopt localoptions nonomatch + local l matches fzf tokens base + + l=$(_zic_list_generator $@) + + if [ -z "$l" ]; then + zle ${__zic_default_completion:-expand-or-complete} + return + fi + + fzf=$(__zic_fzf_prog) + + if [ $(echo $l | wc -l) -eq 1 ]; then + matches=${(q)l} + else + matches=$(echo $l \ + | FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} \ + --reverse $FZF_DEFAULT_OPTS $FZF_COMPLETION_OPTS \ + --bind 'shift-tab:up,tab:down'" ${=fzf} \ + | while read -r item; do + echo -n "${(q)item} " + done) + fi + matches=${matches% } + if [ -n "$matches" ]; then + tokens=(${(z)LBUFFER}) + base="${(Q)@[-1]}" + if [[ "$base" != */ ]]; then + if [[ "$base" == */* ]]; then + base="$(dirname -- "$base")" + if [[ ${base[-1]} != / ]]; then + base="$base/" + fi + else + base="" + fi + fi + LBUFFER="${tokens[1]} " + if [ -n "$base" ]; then + base="${(q)base}" + if [ "${tokens[2][1]}" = "~" ]; then + base="${base/#$HOME/~}" + fi + LBUFFER="${LBUFFER}${base}" + fi + LBUFFER="${LBUFFER}${matches}/" + fi + zle redisplay + typeset -f zle-line-init >/dev/null && zle zle-line-init +} +zic-completion() { + setopt localoptions noshwordsplit noksh_arrays noposixbuiltins + local tokens cmd + tokens=(${(z)LBUFFER}) + cmd=${tokens[1]} + if [[ "$LBUFFER" =~ "^\ *cd$" ]]; then + zle ${__zic_default_completion:-expand-or-complete} + elif [ "$cmd" = cd ]; then + _zic_complete ${tokens[2,${#tokens}]/#\~/$HOME} + else + zle ${__zic_default_completion:-expand-or-complete} + fi +} +[ -z "$__zic_default_completion" ] && { + binding=$(bindkey '^I') + # $binding[(s: :w)2] + # The command substitution and following word splitting to determine the + # default zle widget for ^I formerly only works if the IFS parameter contains + # a space via $binding[(w)2]. Now it specifically splits at spaces, regardless + # of IFS. + [[ $binding =~ 'undefined-key' ]] || __zic_default_completion=$binding[(s: :w)2] + unset binding +} +zle -N zic-completion +bindkey '^I' zic-completion diff --git a/.functions.zsh b/.functions.zsh index b8bcff0..8da7085 100644 --- a/.functions.zsh +++ b/.functions.zsh @@ -47,3 +47,10 @@ fe() { file=$(fzf --query="$1" --select-1 --exit-0) [ -n "$file" ] && ${EDITOR:-vim} "$file" } + +go() { + local branches branch + branches=$(git branch -vv) && + branch=$(echo "$branches" | fzf +m) && + git checkout $(echo "$branch" | awk '{print $1}' | sed "s/.* //") +} diff --git a/.nvimrc b/.nvimrc index b612378..72fa53f 100644 --- a/.nvimrc +++ b/.nvimrc @@ -177,7 +177,7 @@ set undofile " Save undo's after file closes set undodir=~/.vim/undo " where to save undo histories set undolevels=1000 " How many undos set undoreload=10000 " number of lines to save for undo -set winwidth=80 +" set winwidth=80 set splitright set timeoutlen=500 set fillchars+=vert:\ " there is a single space after '\ ' diff --git a/.zshrc b/.zshrc index ad87889..03a6cde 100644 --- a/.zshrc +++ b/.zshrc @@ -1,5 +1,6 @@ source ~/.dotfiles/.oh-my-zsh.zsh source ~/.dotfiles/.aliases.zsh +source ~/.dotfiles/.autopair.zsh source ~/.dotfiles/.colors.zsh source ~/.dotfiles/.completion.zsh source ~/.dotfiles/.functions.zsh @@ -16,4 +17,5 @@ test -e ${HOME}/.iterm2_shell_integration.zsh && source ${HOME}/.iterm2_shell_in export NVM_DIR="/Users/mikekreeki/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" # This loads nvm + [ -f ~/.fzf.zsh ] && source ~/.fzf.zsh diff --git a/mikekreeki.zsh-theme b/mikekreeki.zsh-theme index c650169..e3e3f67 100644 --- a/mikekreeki.zsh-theme +++ b/mikekreeki.zsh-theme @@ -1,7 +1,7 @@ PROMPT='(%{$fg_bold[cyan]%}${PWD/#$HOME/~}%{$reset_color%}$(git_prompt_info)) ' ZSH_THEME_GIT_PROMPT_PREFIX=" on %{$fg[red]%}" -ZSH_THEME_GIT_PROMPT_SUFFIX="%{$fg_bold[yellow]%}$(work_in_progress)%{$reset_color%}" +ZSH_THEME_GIT_PROMPT_SUFFIX="%{%{$reset_color%}" ZSH_THEME_GIT_PROMPT_DIRTY="%{$fg[yellow]%} ~" ZSH_THEME_GIT_PROMPT_UNTRACKED="%{$fg[yellow]%}+" ZSH_THEME_GIT_PROMPT_CLEAN=""