# This file gets sourced by .bashrc and .zshrc. os="$(uname -s)" stty discard undef if [[ -z $THEME ]]; then if [[ -n $ITERM_PROFILE ]]; then export THEME=$ITERM_PROFILE elif [[ -n $KITTY_WINDOW_ID ]]; then export THEME=Light else export THEME=Dark fi fi if [[ $THEME = Dark ]]; then eval $(dircolors ~/.zsh/dircolors.dark) ln -fs \ ~/.config/git/config.colors.dark \ ~/.config/git/config.colors else eval $(dircolors ~/.zsh/dircolors.light) ln -fs \ ~/.config/git/config.colors.light \ ~/.config/git/config.colors fi # Prompt {{{1 if [[ -n ${ZSH_VERSION-} ]]; then _p_pink='%F{161}' _p_red='%F{9}' _p_green='%F{46}' # 77 _p_blue='%F{67}' _p_clear='%f%k%b%u' _p_bold='%B' _p_underline='%U' _p_user='%F{19}' _p_host='%F{32}' else _p_pink='\[\e[38;5;161m\]' _p_red='\[\e[38;5;9m\]' _p_green='\[\e[38;5;46m\]' _p_blue='\[\e[38;5;67m\]' _p_clear='\[\e[0m\]' _p_bold='\[\e[1m\]' _p_underline='\[\e[4m\]' _p_user='\[\e[38;5;19m\]' _p_host='\[\e[38;5;32m\]' fi [[ $THEME = Dark ]] && _p_main=$_p_green || _p_main=$_p_pink _prompt() { local exitval=$? local jobs="$(jobs | wc -l | tr -d '\n')" local gittop="$(git rev-parse --show-toplevel 2>/dev/null)" local pwd="$(pwd -P)" local p # this directory might be below a git repo but not part of it [[ -n $gittop && -z $(git ls-files) ]] && gittop= # root! [[ $UID -eq 0 ]] && p+="${_p_red}${_p_underline}ROOT${_p_clear} " # show user and host on remote systems if [[ -n $SSH_CONNECTION ]]; then [[ $UID -ne 0 ]] && p+="${_p_user}${USER}${_p_clear} " p+="${_p_host}$(hostname) " fi p+=$_p_main if [[ -z $gittop ]]; then p+="$pwd " else local parentdir="${gittop%/*}" local front="${parentdir/#${HOME}/~}" local middle="${_p_underline}${_p_bold}${gittop##*/}${_p_clear}" local back="${_p_main}${pwd#${gittop}}" p+="${front}/${middle}${back}${_p_clear} " # branch name or short SHA if detached local branch=$(git symbolic-ref --short -q HEAD || git rev-parse --short HEAD) [[ -n $branch ]] && p+="${_p_bold}${branch}" # dirty working tree git diff --no-ext-diff --quiet 2>/dev/null || p+="$_p_bold *" # staged changes git diff-index --cached --quiet HEAD 2>/dev/null || p+="$_p_bold ✓" local gitdir="${gittop}/.git" [[ -f "${gitdir}/refs/stash" ]] && p+=' [stash]' if [[ -f "${gitdir}/MERGE_HEAD" ]]; then p+=' [merge]' elif [[ -f "${gitdir}/CHERRY_PICK_HEAD" ]]; then p+=' [cherry]' elif [[ -f "${gitdir}/REVERT_HEAD" ]]; then p+=' [revert]' elif [[ -f "${gitdir}/rebase-merge/interactive" ]]; then p+=' [rebase-i]' elif [[ -d "${gitdir}/rebase-apply" ]]; then p+=' [rebase]' fi fi p+="${_p_clear}"$'\n' (( $jobs )) && p+="[${_p_blue}${_p_bold}${jobs}${_p_clear}]" (( $exitval )) && p+="[${_p_red}${_p_bold}${exitval}${_p_clear}]" PS1="${p}❯ " } # Aliases {{{1 alias d='docker' alias dc='docker-compose' alias g='git' alias m='mhi' alias t='task' alias tf='task -f' alias tn='task | head -n 1' alias pip3up="pip3 list --outdated | sed -e '1,2d; s/ .*//' | xargs pip3 --no-cache-dir install -U" alias gemup="gem update --system && gem update && gem cleanup" alias npmup="npm install npm@latest -g && npm -g update" if [[ $os = Darwin ]]; then alias brewup='brew update && brew upgrade && brew upgrade --cask --greedy && brew cleanup --prune 1' alias allup="pip3up; gemup; npmup; brewup" elif [[ $os = Linux ]]; then alias aptup='sudo apt update && sudo apt upgrade && sudo apt autoremove' alias allup="pip3up; gemup; npmup; aptup" fi alias stripcolors='sed -r "s/\x1b\[([0-9]{1,2}(;[0-9]{1,2})?)?[mGK]//g"' alias mirror='wget --mirror --no-parent --continue' alias myip='dig +short myip.opendns.com @resolver1.opendns.com' alias val='valgrind -v --leak-check=full --show-reachable=yes' alias yt2mp3='youtube-dl -x --audio-format mp3 --audio-quality 0 -o "%(title)s.%(ext)s"' alias yt2mp3-chapters='yt-dlp -x --audio-format mp3 --audio-quality 0 --split-chapters -o "%(title)s - %(chapter_number)s. %(chapter)s.%(ext)s"' alias yt2mp3-playlist='yt-dlp -x --audio-format mp3 --audio-quality 0 --yes-playlist -o "%(title)s - %(playlist_index)s. %(playlist)s.%(ext)s"' if [[ $os = FreeBSD ]]; then alias ls='gnuls --color=auto -N' else alias ls='ls --color=auto -Nv' fi alias l='ls -1h --group-directories-first' alias ll='ls -lh --group-directories-first' alias la='ll -A' alias grep='grep --color=auto' alias 1='fg %1' alias 2='fg %2' alias 3='fg %3' alias 11='bg %1' alias 22='bg %2' alias 33='bg %3' if [[ $os = Darwin ]]; then alias chrome='open -a Google\ Chrome' alias preview='open -a Preview' alias vlc='open -a VLC' alias xcode='open -a Xcode' if [[ -x /Applications/LuLu.app/Contents/Resources/Netiquette.app/Contents/MacOS/Netiquette ]]; then alias objsee-netiquette='/Applications/LuLu.app/Contents/Resources/Netiquette.app/Contents/MacOS/Netiquette -list' fi if [[ -x /Applications/FileMonitor.app/Contents/MacOS/FileMonitor ]]; then alias objsee-filemonitor='sudo /Applications/FileMonitor.app/Contents/MacOS/FileMonitor' fi if [[ -x /Applications/ProcessMonitor.app/Contents/MacOS/ProcessMonitor ]]; then alias objsee-processmonitor='sudo /Applications/ProcessMonitor.app/Contents/MacOS/ProcessMonitor' fi fi # Functions {{{1 dsf() { git diff --no-index --color "$@" | diff-so-fancy | less -RFXx2 } s() { if (( $# )); then ps -eo pid,ppid,user,%cpu,%mem,state,command | grep -i "$@" | grep -v "grep.*$@" | grep "$@" else ps -eo pid,ppid,user,%cpu,%mem,state,command fi } r() { exec $SHELL } md() { command mkdir -p $1 && builtin cd $1 } rd() { dir=$PWD builtin cd .. if command rmdir "$dir" 2>/dev/null; then echo 'Removed empty directory:' $dir else builtin cd "$dir" echo 'Directory is not empty:' ls -A fi unset dir } lookup() { open "https://sks-keyservers.net/pks/lookup?search=${*}" } oman() { open "https://man.openbsd.org/${*}" } camusedby() { echo 'Recent camera uses:' local usedby=$(lsof | grep -w "AppleCamera\|USBVDC\|iSight" | awk '{printf $2"\n"}' | xargs ps) echo $usedby } fix-perm() { [[ $1 = -h ]] && { echo 'usage: fix-perm [dirs:700] [files:600]' return 1 } 1>&2 find . -type d -exec chmod ${1-700} {} + find . -type f -exec chmod ${2-600} {} + } angband() { save_stty="$(stty --save)" # Disable flow control and delayed suspend, since we need ^S and ^Y. stty -ixon dsusp undef command angband stty "$save_stty" } _() { for file in "$@"; do if [[ ${file:0:1} = _ ]]; then mv -nv "$file" "${file:1}" else mv -nv "$file" _"$file" fi done } fsed() { [[ $# -lt 2 ]] && { echo 'usage: fsed ' 2>&1; return 1; } for file in "${@:2}"; do mv -nv "$file" "$(sed "$1" <<< "$file")"; done } asn() { (( !$# )) && { echo 'usage: asn ' 2>&1; return 1; } local ip="$1" grep ':' 1>/dev/null <<< "$ip" && ip="$(dig -x "$ip" +short)" # IPv6 to domain grep '[g-z]' 1>/dev/null <<< "$ip" && ip="$(dig "$ip" A +short)" # domain to IPv4 local rr="$(printf '%s' "$ip." | tac -s.)"origin.asn.cymru.com dig "$rr" TXT +short whois -h whois.cymru.com -- "$ip" } hex() { { echo 'obase=16'; seq "$1" "$2"; } | bc | paste -s -d ' ' } mount() { command mount | sed -e 's/^\(.*\) on \([^ ]*\)/\1\t\2\t/' | sort -t$'\t' -k2 -f | column -s$'\t' -t } # }}} # Chrome {{{1 ch() { export CONF_COLS=$[ COLUMNS/2 ] export CONF_SEP='{::}' cp -f ~/Library/Application\ Support/Google/Chrome/Default/History /tmp/h sqlite3 -separator $CONF_SEP /tmp/h 'select title, url from urls order by last_visit_time desc' \ | ruby -ne ' cols = ENV["CONF_COLS"].to_i title, url = $_.split(ENV["CONF_SEP"]) puts "\x1b[33m#{title.ljust(cols)}\x1b[0m #{url}"' \ | fzf --ansi --multi --no-hscroll --tiebreak=index \ | grep --color=never -o 'https\?://.*' \ | xargs open unset CONF_COLS CONF_SEP } # FZF {{{1 url() { tmux capture-pane -pJS - \ | grep -oE '\b(https?|ftp|file)://[-A-Za-z0-9+&@#/%?=~_|!:,.;]*[-A-Za-z0-9+&@#/%=~_|]' \ | fzf-tmux --multi --tac --exit-0 \ | while read url; do open "$url"; done } f() { local file="$(fzf-tmux -1 --tac --tiebreak=index)" [[ -n $file ]] && cd "$(dirname "$file")" } p() { local dirs=( $ME/github/* $HOME/.vim/bundle ) local dir="$(find "${dirs[@]}" -type d -mindepth 1 -maxdepth 1 | fzf-tmux -1 --tac)" [[ -n $dir ]] && cd "$dir" && clear } c() { local configs=( ~/.bash_profile ~/.bashrc ~/.config/git/config ~/.profile ~/.shrc ~/.tmux.conf ~/.vim/autoload/mhi.vim ~/.vim/lua/config.lua ~/.vim/magic.vim ~/.vim/vimrc ~/.zsh/.zprofile ~/.zsh/.zshrc ~/.zshenv ) local IFS=$'\n' local files=($(echo "${configs[*]}" | fzf-tmux -m -1 --tac --tiebreak=index)) [[ -n $files ]] && v "${files[@]}" } book() { local book="$(rg --files $ME/books | fzf -1 --tac)" [[ -z $book ]] && return 1 cd "${book%/*}" clear ls -1 --group-directories-first } # Git {{{1 pr() { local origin pr if [[ $# -eq 0 ]]; then echo "usage: pr [remote] " return 1 elif [[ $# -eq 1 ]]; then origin=$(git config branch.master.remote || echo origin) pr=$1 else origin=$1 pr=$2 fi git fetch $origin refs/pull/${pr}/head || return git checkout -q FETCH_HEAD } prpush() { local pr=$1 local local_branch=$(git rev-parse --abbrev-ref HEAD) [[ $local_branch == pr[[:digit:]]* ]] && pr=${local_branch#??} local url=$(git config remote.$(git config branch.master.remote).url) local slug=${${url#*github.com?}%.git} local repo="${slug#*/}" local url=https://api.github.com/repos/${slug}/pulls/${pr} local label=$(curl -s "$url" | jq -r '.head.label') local author=${label%%:*} local remote_branch=${label#*:} local cmd="git push -f git@github.com:${author}/${repo} ${local_branch}:${remote_branch}" echo "$cmd" eval "$cmd" } changed() { local files=$(git diff -U0 --no-prefix --relative "$@" 2>/dev/null | quickfix_diff_to_hunk) [[ -z $files ]] && { echo '¯\_(ツ)_/¯'; return 1; } v -q <(echo $files) } quickfix_diff_to_hunk() { ruby -ne ' (file = $1; next) if $_ =~ /^\+\+\+ (.*)/; next if file.nil?; (linenr = $1; next) if $_ =~ /^@@ .*\+(\d+)/; next if linenr.nil?; puts "#{file}:#{linenr}: #{$1}" if $_ =~ /^[+-](.*)/; linenr = nil ' } b() { git checkout $(git branch -a | fzf -1 | cut -c3-) } gho() { local prefix prefix=$(git rev-parse --show-prefix) (( $? )) && return 1 local branch=$(git symbolic-ref -q --short HEAD) local remote=$(git config branch.master.remote || echo origin) local url=$(git config remote.${remote}.url) url=${url/git\@github\.com:/https:\/\/github.com/} url=${url%\.git} open ${url}/tree/${branch}/${prefix}${1:-} } gl() { nvim +'Gclog' } # iTerm2 {{{1 proftoggle() { if [[ -z $ITERM_PROFILE ]]; then print "Not in iTerm" 1>&2 return fi tmup if [[ $ITERM_PROFILE == Light ]]; then export ITERM_PROFILE=Dark eval $(dircolors ~/.zsh/dircolors.dark) ln -fs \ ~/.config/git/config.colors.dark \ ~/.config/git/config.colors else export ITERM_PROFILE=Light eval $(dircolors ~/.zsh/dircolors.light) ln -fs \ ~/.config/git/config.colors.light \ ~/.config/git/config.colors fi local seq="\e]1337;SetProfile=${ITERM_PROFILE}\x7" if [[ -n $TMUX ]]; then seq="\ePtmux;\e${seq}\e\\" tmux setenv -g ITERM_PROFILE $ITERM_PROFILE fi printf $seq clear } # Tmux {{{1 tm() { if (( $# )); then tmux has-session -t "$*" && tmux attach -t "$*" || tmux new-session -s "$*" else tmux attach || tmux new-session -s default fi } tmup() { [[ -n $TMUX ]] && export "$(tmux showenv -s)" } # Vim {{{1 v() { if [[ -x $ME/github/neovim/neovim/build/bin/nvim ]]; then VIMRUNTIME=$ME/github/neovim/neovim/runtime $ME/github/neovim/neovim/build/bin/nvim "$@" else $EDITOR "$@" fi } vd() { VIMRUNTIME=$ME/github/neovim/neovim/runtime lldb -- $ME/github/neovim/neovim/build/bin/nvim "$@" } all() { git rev-parse --is-inside-work-tree &>/dev/null && tool=git || tool=ag nvim +"Grepper -tool $tool -highlight -jump -open -noswitch -query $1" } va() { nvim -q <(ag --vimgrep "$@") } vg() { nvim -q <(git grep -nI "$@") } test -r ~/.shenv && . ~/.shenv # vim: ft=sh fdm=marker