├── .bash_profile ├── .bashrc ├── .config ├── atuin │ └── config.toml ├── bash │ ├── .bashrc │ ├── conf.d │ │ ├── aliases.sh │ │ └── functions.sh │ ├── plugins │ │ ├── __init__.sh │ │ ├── atuin.sh │ │ ├── ble.sh │ │ ├── brew.sh │ │ ├── colors.sh │ │ ├── completions.sh │ │ ├── confd.sh │ │ ├── directory.sh │ │ ├── editor.sh │ │ ├── environment.sh │ │ ├── fzf.sh │ │ ├── history-substring-search.sh │ │ ├── history.sh │ │ ├── macos.sh │ │ ├── magic-enter.sh │ │ ├── prompt.sh │ │ ├── python.sh │ │ ├── repos.sh │ │ ├── utils.sh │ │ ├── wezterm.sh │ │ ├── zoxide.sh │ │ └── zzz.sh │ ├── readme.md │ └── repos.txt ├── blesh │ └── init.sh ├── git │ ├── config │ └── gitignore ├── helix │ └── config.toml ├── homebrew │ └── init.brewfile ├── kak │ ├── kakrc │ └── plugins │ │ └── example.lua ├── npm │ └── npmrc ├── nvim │ ├── .gitignore │ ├── .stylua.toml │ ├── LICENSE.md │ ├── README.md │ ├── doc │ │ └── kickstart.txt │ ├── init.lua │ ├── lazy-lock.json │ └── lua │ │ ├── custom │ │ └── plugins │ │ │ └── init.lua │ │ └── kickstart │ │ ├── health.lua │ │ └── plugins │ │ ├── autopairs.lua │ │ ├── debug.lua │ │ ├── gitsigns.lua │ │ ├── indent_line.lua │ │ ├── lint.lua │ │ └── neo-tree.lua ├── pep8 ├── pycodestyle ├── readline │ └── inputrc ├── starship │ ├── bash.toml │ ├── fish.toml │ ├── hydro.toml │ ├── mmc.toml │ ├── mmc_256.toml │ ├── omf.toml │ ├── powershell.toml │ ├── prezto.toml │ ├── pure.toml │ ├── starship.toml │ ├── xonsh.toml │ ├── zebrafish.toml │ └── zsh.toml ├── tmux │ └── tmux.conf ├── vim │ ├── init.vim │ └── kickstart.vim ├── wezterm │ ├── README.md │ ├── backgrounds │ │ ├── botw_corrupted_nydra.jpg │ │ ├── botw_corrupted_nydra2.png │ │ ├── botw_corrupted_nydra_dark.png │ │ └── botw_corrupted_nydra_rev.jpg │ └── wezterm.lua └── zsh │ ├── .p10k.zsh │ ├── .zshenv │ ├── .zshrc │ └── conf.d │ ├── git-clone-with-cd.zsh │ ├── history.zsh │ ├── myaliases.zsh │ └── myfuncs.zsh ├── .editorconfig ├── .gitignore ├── .gitmodules ├── .hammerspoon ├── Spoons │ └── .gitkeep ├── init.lua └── readme.md ├── .stow-local-ignore ├── .vimrc ├── .zshenv ├── LICENSE ├── README.md ├── bin ├── antidote1 ├── backup ├── backup.rsync ├── capsmap ├── code ├── color-spaces.pl ├── colorschemes ├── colortrans ├── context_demo.zsh ├── csv2tsv ├── em ├── fishy │ ├── .bcrc │ ├── .bcrc2 │ ├── .editorconfig │ ├── argparse.lua │ ├── contains │ ├── contains.lua │ ├── count │ ├── math │ ├── math.lua │ ├── random.lua │ ├── string │ ├── string-join │ ├── string-join0 │ ├── string-length │ ├── string-lower │ ├── string-transform │ ├── string-upper │ ├── string.lua │ └── test.lua ├── fix-bom ├── git │ ├── git-branch-cleanup │ ├── git-cloner │ ├── git-pushup │ └── git-submodule-up ├── gitex ├── hello.zsh ├── linkify ├── macopts.zsh ├── new_mac_config ├── new_mac_secrets ├── new_mac_setup ├── otp ├── palette ├── pkgmgr ├── pocket2ffbookmarks ├── pocketdownload ├── prj ├── reference │ ├── emacs-plus.sh │ └── git-fix-email.sh ├── repo ├── shell-safe-rm ├── str.py ├── subl_wait.sh ├── trash ├── upallthethings └── whichos ├── docs ├── emacs.md ├── git.md ├── macos-config.md ├── macos.md ├── readme.md ├── taskpaper.md ├── vim.md ├── xdg.md └── zsh │ ├── completions.md │ ├── readme.md │ ├── zdotdir.md │ ├── zsh-cheatsheet.md │ ├── zsh-optparse.md │ ├── zsh-setopts.md │ ├── zsh-string.md │ └── zsh.md └── makefile /.bash_profile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | . $HOME/.bashrc 3 | -------------------------------------------------------------------------------- /.bashrc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | BASH_HOME="${BASH_HOME:-$HOME/.config/bash}" 3 | . $BASH_HOME/.bashrc 4 | -------------------------------------------------------------------------------- /.config/bash/.bashrc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # shellcheck shell=bash disable=SC2001,SC2002 3 | 4 | BASH_THEME="starship" 5 | BASH_HOME=~/.config/bash 6 | 7 | plugins=( 8 | __init__ 9 | brew 10 | ble 11 | repos 12 | atuin 13 | colors 14 | completions 15 | directory 16 | editor 17 | environment 18 | history 19 | history-substring-search 20 | macos 21 | magic-enter 22 | prompt 23 | python 24 | utils 25 | wezterm 26 | zoxide 27 | confd 28 | zzz 29 | ) 30 | 31 | for _plugin in "${plugins[@]}"; do 32 | if [ -r "$BASH_HOME/plugins/${_plugin}.sh" ]; then 33 | source "$BASH_HOME/plugins/${_plugin}.sh" 34 | else 35 | echo >&2 "Plugin not found: '$_plugin'." 36 | fi 37 | done 38 | 39 | unset _plugin 40 | -------------------------------------------------------------------------------- /.config/bash/conf.d/aliases.sh: -------------------------------------------------------------------------------- 1 | # shellcheck shell=bash 2 | 3 | # ls shorthand. 4 | alias ls='ls --color=auto' 5 | alias la='ls -lah' 6 | alias ll='ls -lh' 7 | alias l='ls -F' 8 | alias ldot='ls -ld .*' 9 | 10 | # Single character shortcuts - be sparing! 11 | alias _='sudo' 12 | alias h='history' 13 | alias v='vim' 14 | alias c='clear' 15 | 16 | # Mask built-ins with better defaults. 17 | alias ping='ping -c 5' 18 | alias vi=vim 19 | alias grep='grep --color=auto --exclude-dir={.git,.hg,.svn,.vscode}' 20 | 21 | # Fix typos. 22 | alias get=git 23 | alias quit='exit' 24 | alias cd..='cd ..' 25 | alias zz='exit' 26 | 27 | # Navigate directories faster. 28 | alias "dirh"="dirs -v" 29 | alias ".."="cd .." 30 | alias "..."="cd ../.." 31 | alias "...."="cd ../../.." 32 | alias "....."="cd ../../../.." 33 | 34 | # Tell gpg to store its keyring as data. 35 | if [[ -d "$XDG_DATA_HOME" ]]; then 36 | export GNUPGHOME="${GNUPGHOME:-$XDG_DATA_HOME/gnupg}" 37 | alias gpg='gpg --homedir "$GNUPGHOME"' 38 | fi 39 | 40 | # url encode/decode 41 | alias urldecode='python3 -c "import sys, urllib.parse as ul; \ 42 | print(ul.unquote_plus(sys.argv[1]))"' 43 | alias urlencode='python3 -c "import sys, urllib.parse as ul; \ 44 | print (ul.quote_plus(sys.argv[1]))"' 45 | 46 | # find 47 | alias fd='find . -type d -name ' 48 | alias ff='find . -type f -name ' 49 | 50 | # date/time 51 | alias timestamp="date '+%Y-%m-%d %H:%M:%S'" 52 | alias datestamp="date '+%Y-%m-%d'" 53 | alias isodate="date +%Y-%m-%dT%H:%M:%S%z" 54 | alias utc="date -u +%Y-%m-%dT%H:%M:%SZ" 55 | alias unixepoch="date +%s" 56 | 57 | # Safer way to rm. 58 | if type safe-rm >/dev/null 2>&1; then 59 | alias rm='safe-rm' 60 | alias del='safe-rm' 61 | fi 62 | 63 | # Homebrew 64 | alias brewup="brew update && brew upgrade && brew cleanup" 65 | alias brewinfo="brew leaves | xargs brew desc --eval-all" 66 | 67 | # dotfiles 68 | export DOTFILES="${DOTFILES:-$HOME/.dotfiles}" 69 | alias dotf='cd "$DOTFILES"' 70 | alias fdot="cd ~/.config/fish" 71 | alias zdot="cd ~/.config/zsh" 72 | alias bdot="cd ~/.config/bash" 73 | alias rcs='cd "${BASH_HOME:-$HOME}"' 74 | alias bashrc='"${EDITOR:-vim}" "${BASH_HOME:-$HOME}/.bashrc"' 75 | alias reload='source "${BASH_HOME:-$HOME}/.bashrc"' 76 | 77 | # Quick way to get back to your initial working directory. 78 | IWD="${IWD:-$PWD}" 79 | alias iwd='cd "$IWD"' 80 | 81 | # Misc aliases. 82 | alias myip="curl ifconfig.me" 83 | alias nv=nvim 84 | alias curry="xargs -I{}" # printf '%s\n' foo bar baz | curry touch {}.txt 85 | alias ppath='echo $PATH | tr ":" "\n"' 86 | alias cls="clear && printf '\e[3J'" 87 | alias bench="for i in {1..10}; do /usr/bin/time bash -ic 'echo -n'; done" 88 | -------------------------------------------------------------------------------- /.config/bash/conf.d/functions.sh: -------------------------------------------------------------------------------- 1 | # shellcheck shell=bash disable=SC2155 2 | 3 | function clone { 4 | git cloner "$@" 5 | } 6 | 7 | function func/exists() { 8 | declare -F -- "$1" >/dev/null 2>&1 9 | } 10 | 11 | # A basic calculator. 12 | function test_exitcode() { 13 | [[ "$#" -ne 0 ]] && return "$1" || return 0 14 | } 15 | 16 | # A basic calculator. 17 | function calc() { 18 | bc -l <<< "$@" 19 | } 20 | 21 | # Check strings for boolean values. 22 | function is_true() { 23 | case "${1,,}" in 24 | (t|y|true|yes|on|1) return 0 ;; 25 | (*) return 1 ;; 26 | esac 27 | } 28 | 29 | # Print 256 terminal color codes. 30 | function colormap() { 31 | local i bg fg reset 32 | reset=$'\E[00m' 33 | for i in {0..255}; do 34 | fg=$'\E[38;5;'$i'm' 35 | bg=$'\E[48;5;'$i'm' 36 | printf "%s %s" "$bg" "$reset" 37 | printf "${fg}%03d${reset} " "$i" 38 | (( i <= 15 && (i + 1) % 8 == 0 )) && echo 39 | (( i > 15 && (i - 15) % 6 == 0 )) && echo 40 | done 41 | } 42 | 43 | # cd upward X directories. 44 | function up() { 45 | local lvls cdstr 46 | lvls="${1:-1}" 47 | cdstr=".." 48 | while (( --lvls > 0 )); do 49 | cdstr+="/.." 50 | done 51 | cd "$cdstr" || return 52 | } 53 | 54 | # Extract all the things. 55 | function extract() { 56 | case "$1" in 57 | *.tar.bz2) tar xjf "$1" ;; 58 | *.tar.gz) tar xzf "$1" ;; 59 | *.bz2) bunzip2 "$1" ;; 60 | *.gz) gunzip "$1" ;; 61 | *.tar.xz) tar xJf "$1" ;; 62 | *.xz) unxz "$1" ;; 63 | *.zip) unzip "$1" ;; 64 | *.7z) 7z x "$1" ;; 65 | *) echo "'$1' cannot be extracted via extract()" ;; 66 | esac 67 | } 68 | 69 | # Join strings with a delimiter. 70 | function str/join() { 71 | local sep ret arg 72 | [[ $# -ne 0 ]] || return 1 73 | [[ $# -ne 1 ]] || return 0 74 | sep="$1"; shift 75 | ret="$1"; shift 76 | for arg; do ret+="${sep}${arg}"; done 77 | echo "$ret" 78 | } 79 | 80 | # Split strings on a delimiter. 81 | function str/split() { 82 | local sep str 83 | [[ $# -ne 0 ]] || return 1 84 | sep=$(echo "$1" | sed 's/[]\/\\$*.^|[]/\\&/g') 85 | shift 86 | for str; do 87 | echo "$str" | sed "s/${sep}/\n/g" 88 | done 89 | } 90 | 91 | # Trims whitespace from start and end of string. 92 | function str/trim() { 93 | local arg 94 | for arg; do 95 | arg="${arg#"${arg%%[![:space:]]*}"}" 96 | arg="${arg%"${arg##*[![:space:]]}"}" 97 | echo "$arg" 98 | done 99 | } 100 | 101 | # Convert to UPPERCASE string. 102 | function str/upper() { 103 | local arg 104 | for arg; do 105 | echo "$arg" | tr '[:lower:]' '[:upper:]' 106 | done 107 | } 108 | 109 | # Convert to lowercase string. 110 | function str/lower() { 111 | local arg 112 | for arg; do 113 | echo "$arg" | tr '[:upper:]' '[:lower:]' 114 | done 115 | } 116 | 117 | # Sum an array. 118 | function arr/sum() { 119 | local i tot=0 120 | for i; do (( tot+=i )); done 121 | echo "$tot" 122 | } 123 | 124 | # Check if an element is in an array. 125 | function arr/contains() { 126 | local arg find="$1"; shift 127 | for arg; do 128 | [[ "$find" == "$arg" ]] && return 0 129 | done 130 | return 1 131 | } 132 | 133 | # Get the index of an element is in an array. 134 | function arr/index_of() { 135 | local arg find="$1" i=0; shift 136 | for arg; do 137 | if [[ "$find" == "$arg" ]]; then 138 | echo "$i" 139 | return 140 | fi 141 | ((i++)) 142 | done 143 | return 1 144 | } 145 | 146 | function prj { 147 | local selection="$(~/bin/prj "$*")" 148 | [ -z "$selection" ] && return 149 | cd "${selection}" && pwd 150 | } 151 | -------------------------------------------------------------------------------- /.config/bash/plugins/__init__.sh: -------------------------------------------------------------------------------- 1 | # shellcheck shell=bash 2 | 3 | # Use XDG base dirs. 4 | export XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}" 5 | export XDG_CACHE_HOME="${XDG_CACHE_HOME:-$HOME/.cache}" 6 | export XDG_DATA_HOME="${XDG_DATA_HOME:-$HOME/.local/share}" 7 | export XDG_STATE_HOME="${XDG_STATE_HOME:-$HOME/.local/state}" 8 | mkdir -p "$XDG_CONFIG_HOME" "$XDG_CACHE_HOME" "$XDG_DATA_HOME" "$XDG_STATE_HOME" 9 | 10 | # Support alternative BASH_HOME locations. 11 | BASH_HOME="$XDG_CONFIG_HOME"/bash 12 | BASH_DATA_HOME="$XDG_DATA_HOME"/bash 13 | BASH_CACHE_HOME="$XDG_CACHE_HOME"/bash 14 | REPO_HOME="$BASH_CACHE_HOME"/repos 15 | mkdir -p "$BASH_HOME" "$BASH_DATA_HOME" "$BASH_CACHE_HOME" "$REPO_HOME" 16 | 17 | # Setup profiling if needed. 18 | if [ "${PROFRC:-0}" -eq 1 ]; then 19 | PS4='+ $(gdate "+%s.%N")\011 ' 20 | exec 3>&2 2>"$BASH_HOME"/.bashrc.$$.log 21 | set -x 22 | fi 23 | 24 | # Declare a post_init array for post init operations. 25 | # shellcheck disable=SC2034 26 | declare -a post_init=() 27 | -------------------------------------------------------------------------------- /.config/bash/plugins/atuin.sh: -------------------------------------------------------------------------------- 1 | # shellcheck shell=bash 2 | 3 | # Enable atuin bash integration. 4 | if type atuin >/dev/null 2>&1; then 5 | # Disable up arrow with --disable-up-arrow. 6 | # Disabling up arrow means that we need to use C-r for search. 7 | # eval "$(atuin init bash --disable-up-arrow)" 8 | eval "$(atuin init bash)" 9 | fi 10 | -------------------------------------------------------------------------------- /.config/bash/plugins/ble.sh: -------------------------------------------------------------------------------- 1 | # shellcheck shell=bash source=/dev/null 2 | 3 | BLE_HOME="${BLE_HOME:-${XDG_DATA_HOME:-$HOME/.local/share}/blesh}" 4 | REPO_HOME="${REPO_HOME:-${XDG_CACHE_HOME:-$HOME/.cache}/bash/repos}" 5 | 6 | if [[ ! -d "$BLE_HOME" ]]; then 7 | export PATH="/opt/homebrew/bin:$PATH" 8 | make -C "$REPO_HOME/akinomyoga/ble.sh" install PREFIX=~/.local 9 | fi 10 | 11 | # Initialize ble.sh for interactive shells. Do this near the beginning of .bashrc. 12 | BLE_HOME="$XDG_DATA_HOME/blesh" 13 | if [[ -d "$BLE_HOME" ]] && [[ "${PROFRC:-0}" -ne 1 ]]; then 14 | [[ $- == *i* ]] && source "$BLE_HOME/ble.sh" --noattach 15 | else 16 | unset BLE_HOME 17 | fi 18 | -------------------------------------------------------------------------------- /.config/bash/plugins/brew.sh: -------------------------------------------------------------------------------- 1 | # shellcheck shell=bash 2 | 3 | [ -d /opt/homebrew/bin ] || return 1 4 | 5 | # Add common directories. 6 | if [[ :$PATH: != *:/usr/bin:* ]]; then 7 | export PATH="/usr/bin:/usr/sbin:$PATH" 8 | fi 9 | if [[ :$PATH: != *:/usr/local/bin:* ]]; then 10 | export PATH="/usr/local/bin:/usr/local/sbin:$PATH" 11 | fi 12 | 13 | # Set up homebrew if the user didn't already in a .pre.bash file. 14 | if [[ -z "${HOMEBREW_PREFIX:-}" ]]; then 15 | for brewcmd in /opt/homebrew/bin/brew /usr/local/bin/brew; do 16 | [[ -x "$brewcmd" ]] || continue 17 | eval "$("$brewcmd" shellenv)" 18 | break 19 | done 20 | fi 21 | 22 | if [[ :$PATH: != *:/opt/homebrew/bin:* ]]; then 23 | export PATH="/opt/homebrew/bin:/opt/homebrew/sbin:$PATH" 24 | fi 25 | 26 | # Add user directories. 27 | export PATH="$HOME/bin:$HOME/.local/bin:$PATH" 28 | 29 | # Show the root installs with all deps. 30 | brews() { 31 | local bluify_deps=' 32 | BEGIN { blue = "\033[34m"; reset = "\033[0m" } 33 | { leaf = $1; $1 = ""; printf "%s%s%s%s\n", leaf, blue, $0, reset} 34 | ' 35 | brew leaves | xargs brew deps --installed --for-each | awk "$bluify_deps" 36 | } 37 | -------------------------------------------------------------------------------- /.config/bash/plugins/colors.sh: -------------------------------------------------------------------------------- 1 | # shellcheck shell=bash 2 | 3 | # Colorize man pages. 4 | export LESS_TERMCAP_md=$'\E[01;34m' # start bold 5 | export LESS_TERMCAP_mb=$'\E[01;34m' # start blink 6 | export LESS_TERMCAP_so=$'\E[00;47;30m' # start standout: white bg, black fg 7 | export LESS_TERMCAP_us=$'\E[04;35m' # start underline: underline magenta 8 | export LESS_TERMCAP_se=$'\E[0m' # end standout 9 | export LESS_TERMCAP_ue=$'\E[0m' # end underline 10 | export LESS_TERMCAP_me=$'\E[0m' # end bold/blink 11 | 12 | # Set LS_COLORS using dircolors 13 | if [[ -z "$LS_COLORS" ]]; then 14 | if type dircolors >/dev/null 2>&1; then 15 | eval "$(dircolors --sh)" 16 | elif type gdircolors >/dev/null 2>&1; then 17 | eval "$(gdircolors --sh)" 18 | fi 19 | fi 20 | 21 | # Fallback, even for BSD systems 22 | export LS_COLORS="${LS_COLORS:-di=34:ln=35:so=32:pi=33:ex=31:bd=1;36:cd=1;33:su=30;41:sg=30;46:tw=30;42:ow=30;43}" 23 | 24 | # For BSD systems, set LSCOLORS instead. 25 | if ! type dircolors >/dev/null 2>&1; then 26 | export CLICOLOR=1 27 | export LSCOLORS="exfxcxdxbxGxDxabagacad" 28 | fi 29 | -------------------------------------------------------------------------------- /.config/bash/plugins/completions.sh: -------------------------------------------------------------------------------- 1 | # shellcheck shell=bash source=/dev/null 2 | 3 | # Completions. 4 | if [ -r "${HOMEBREW_PREFIX:-?}/etc/profile.d/bash_completion.sh" ]; then 5 | . "${HOMEBREW_PREFIX:-?}/etc/profile.d/bash_completion.sh" 6 | elif [ -f /usr/share/bash-completion/bash_completion ]; then 7 | . /usr/share/bash-completion/bash_completion 8 | elif [ -f /etc/bash_completion ]; then 9 | . /etc/bash_completion 10 | fi 11 | 12 | [ -n "$BLE_VERSION" ] || return 1 13 | 14 | function settings-for-completion { 15 | # shellcheck disable=SC2016 16 | ble/function#advice around ble/complete/auto-complete.idle ' 17 | if ble/string#match "${_ble_edit_str:_ble_edit_ind}" "^[[:space:]]|^$"; then 18 | ble/function#advice/do 19 | else 20 | ble/util/idle.wait-user-input 21 | fi 22 | ' 23 | } 24 | blehook/eval-after-load complete settings-for-completion 25 | -------------------------------------------------------------------------------- /.config/bash/plugins/confd.sh: -------------------------------------------------------------------------------- 1 | # shellcheck shell=bash 2 | 3 | # Load every script in conf.d 4 | shopt -s nullglob 5 | for _rc in "$BASH_HOME"/conf.d/*.sh; do 6 | source "$_rc" 7 | done 8 | shopt -u nullglob 9 | unset _rc 10 | -------------------------------------------------------------------------------- /.config/bash/plugins/directory.sh: -------------------------------------------------------------------------------- 1 | # shellcheck shell=bash 2 | 3 | # Config for dirstack, globbing, special dirs, and general file system nav. 4 | # CDPATH="." 5 | set -o noclobber # Prevent file overwrite on stdout redirection; use `>|` to force 6 | set -o pipefail # Return the rightmost non-zero code for piped commands if any fail 7 | shopt -s checkwinsize 2> /dev/null # Update window size after every command 8 | shopt -s cmdhist 2> /dev/null # Save multi-line commands as one command 9 | shopt -s extglob 2> /dev/null # Turn on extended globbing 10 | shopt -s globstar 2> /dev/null # Turn on recursive globbing (enables ** to recurse all directories) 11 | shopt -s nocaseglob 2> /dev/null # Case-insensitive globbing (used in pathname expansion) 12 | shopt -s autocd 2> /dev/null # Prepend cd to directory names automatically 13 | shopt -s dirspell 2> /dev/null # Correct spelling errors during tab-completion 14 | # shopt -s cdspell 2> /dev/null # Correct spelling errors in arguments supplied to cd 15 | # shopt -s cdable_vars 2> /dev/null # CD across the filesystem as if you're in that dir 16 | -------------------------------------------------------------------------------- /.config/bash/plugins/editor.sh: -------------------------------------------------------------------------------- 1 | # shellcheck shell=bash 2 | 3 | # Allow ctrl-S for history navigation (with ctrl-R) 4 | stty -ixon 5 | 6 | # Do ble.sh things from here on. 7 | [ -n "$BLE_VERSION" ] || return 1 8 | 9 | # Strip leading dollar signs. Fixes commands pasted from markdown. 10 | # shellcheck disable=SC2016 11 | ble/function#advice around ble/widget/default/accept-line ' 12 | if [[ "${_ble_edit_str:0:2}" == "$ " ]]; then 13 | ble/widget/beginning-of-logical-line 14 | ble/widget/insert-string "${_ble_edit_str:2}" 15 | ble/widget/kill-forward-logical-line 16 | fi 17 | ble/function#advice/do 18 | ' 19 | -------------------------------------------------------------------------------- /.config/bash/plugins/environment.sh: -------------------------------------------------------------------------------- 1 | # shellcheck shell=bash 2 | 3 | # Set locale. 4 | export LANG="${LANG:-en_US.UTF-8}" 5 | export TZ="${TZ:-America/New_York}" 6 | 7 | # Set preferred editors, pagers, and launchers. 8 | export EDITOR="${EDITOR:-vim}" 9 | export VISUAL="${VISUAL:-code}" 10 | export PAGER="${PAGER:-less}" 11 | export BROWSER="${BROWSER:-open}" 12 | 13 | # Set flags for less command. 14 | export LESS="-giMRSw -z-4" 15 | 16 | # Reduce key delay. 17 | export KEYTIMEOUT="${KEYTIMEOUT:-1}" 18 | -------------------------------------------------------------------------------- /.config/bash/plugins/fzf.sh: -------------------------------------------------------------------------------- 1 | # shellcheck shell=bash 2 | 3 | # Enable fzf bash integration. 4 | if type fzf >/dev/null 2>&1; then 5 | eval "$(fzf --bash)" 6 | fi 7 | -------------------------------------------------------------------------------- /.config/bash/plugins/history-substring-search.sh: -------------------------------------------------------------------------------- 1 | # History substring search 2 | bind '"\e[A": history-substring-search-backward' 3 | bind '"\e[B": history-substring-search-forward' 4 | -------------------------------------------------------------------------------- /.config/bash/plugins/history.sh: -------------------------------------------------------------------------------- 1 | # shellcheck shell=bash 2 | 3 | shopt -s histappend # Append to history, don't overwrite it. 4 | HISTTIMEFORMAT='%F %T ' # Use standard ISO 8601 timestamp. 5 | HISTSIZE=10000 # Remember the last x commands in memory during session 6 | HISTFILESIZE=100000 # Start truncating history file after x lines 7 | HISTCONTROL=ignoreboth # ignoreboth is shorthand for ignorespace and ignoredups 8 | HISTFILE="${BASH_DATA_HOME:-$HOME}/history" 9 | -------------------------------------------------------------------------------- /.config/bash/plugins/macos.sh: -------------------------------------------------------------------------------- 1 | # shellcheck shell=bash 2 | 3 | # Check requirements. 4 | [[ "$OSTYPE" == darwin* ]] || return 1 5 | 6 | # Change to the current Finder directory. 7 | function cdf() { 8 | cd "$(pfd)" || return 9 | } 10 | 11 | # Flush the DNS cache. 12 | function flushdns() { 13 | dscacheutil -flushcache && sudo killall -HUP mDNSResponder 14 | } 15 | 16 | # Hide hidden dotfiles in Finder. 17 | function hidefiles() { 18 | defaults write com.apple.finder AppleShowAllFiles -bool false && killall Finder 19 | } 20 | 21 | # Show hidden dotfiles in Finder. 22 | function showfiles() { 23 | defaults write com.apple.finder AppleShowAllFiles -bool true && killall Finder 24 | } 25 | 26 | # Have Siri let me know when a process is complete. 27 | function lmk() { 28 | # eg: sleep 2 && lmk 29 | say "${*:-Process complete}" 30 | } 31 | 32 | # Read man page with Preview.app 33 | function manp() { 34 | # https://scriptingosx.com/2022/11/on-viewing-man-pages-ventura-update/ 35 | if [[ $# -eq 0 ]]; then 36 | echo >&2 'manp: You must specify the manual page you want' 37 | return 1 38 | fi 39 | mandoc -T pdf "$(/usr/bin/man -w "$*")" | open -fa Preview 40 | } 41 | 42 | # Open the current directory in Finder 43 | function ofd() { 44 | open "$PWD" 45 | } 46 | 47 | # Take a quick look at a file using an appropriate viewer 48 | function peek() { 49 | [[ $# -gt 0 ]] && qlmanage -p "$*" &>/dev/null & 50 | } 51 | 52 | # Print the frontmost Finder directory. 53 | function pfd() { 54 | osascript 2> /dev/null <&1 </dev/null; then 14 | magic_cmd="$MAGIC_ENTER_GIT_COMMAND" 15 | else 16 | magic_cmd="$MAGIC_ENTER_OTHER_COMMAND" 17 | fi 18 | 19 | # Run the command magically. 20 | ble/widget/execute-command "$magic_cmd" 21 | 22 | # Or, run the command more explicitly. 23 | # ble/widget/insert-string "$magic_cmd" 24 | # ble/widget/accept-line 25 | } 26 | 27 | function ble/widget/blerc/magic-enter { 28 | # If no command is given, run magic-enter-command. Otherwise, run the 29 | # ble.sh default binding for C-m/RET. 30 | if [[ ! $_ble_edit_str ]]; then 31 | ble/widget/blerc/magic-enter-command 32 | else 33 | ble/widget/accept-single-line-or-newline 34 | fi 35 | } 36 | ble-bind -f C-m blerc/magic-enter # for traditional keyboard protocol 37 | ble-bind -f RET blerc/magic-enter # for advanced keyboard protocol 38 | -------------------------------------------------------------------------------- /.config/bash/plugins/prompt.sh: -------------------------------------------------------------------------------- 1 | # shellcheck shell=bash disable=SC2155 source=/dev/null 2 | 3 | # TODO: Hydro should show cmd duration (from ble.sh?) 4 | # TODO: Hydro should show stashes 5 | # TODO: Hydro should be async?? 6 | 7 | HYDRO_COLOR_PROMPT="$(tput setaf 206)" 8 | HYDRO_USE_GITSTATUS=${HYDRO_USE_GITSTATUS:-0} 9 | 10 | # Enable promptvars so that ${GITSTATUS_PROMPT} in PS1 is expanded. 11 | shopt -s promptvars 12 | 13 | function shorten_path() { 14 | local OPTIND OPTARG opt o_len 15 | while getopts "l:" opt; do 16 | case "$opt" in 17 | l) o_len="${OPTARG}" ;; 18 | *) return 1 ;; 19 | esac 20 | done 21 | shift $(( OPTIND - 1 )) 22 | if [[ "${o_len:-1}" -gt 0 ]]; then 23 | echo "$1" | sed -E -e "s:${HOME}:~:" -e 's:([^/\.]{1,'"${o_len:-1}"'})[^/]*/:\1/:g' 24 | else 25 | basename "$1" 26 | fi 27 | } 28 | 29 | # Load gitstatus if available 30 | if [[ $HYDRO_USE_GITSTATUS -eq 1 ]]; then 31 | # Start gitstatusd in the background. 32 | source "$REPO_HOME/romkatv/gitstatus/gitstatus.plugin.sh" 33 | gitstatus_stop && gitstatus_start -s -1 -u -1 -c -1 -d -1 34 | fi 35 | 36 | function set_vcs_vars() { 37 | VCS_STATUS_RESULT="error" 38 | command -v git > /dev/null 2>&1 || return 1 39 | [ -d .git ] || git rev-parse --is-inside-work-tree > /dev/null 2>&1 || return 1 40 | 41 | # Use gitstatus if it's available 42 | if [[ $HYDRO_USE_GITSTATUS -eq 1 ]]; then 43 | gitstatus_query || return 1 44 | if (( VCS_STATUS_NUM_STAGED + VCS_STATUS_NUM_UNSTAGED + VCS_STATUS_NUM_UNTRACKED > 0 )); then 45 | VCS_STATUS_IS_DIRTY=1 46 | else 47 | VCS_STATUS_IS_DIRTY=0 48 | fi 49 | return 0 50 | fi 51 | 52 | # Otherwise, do the git status calls ourself 53 | VCS_STATUS_RESULT="ok-manual" 54 | VCS_STATUS_LOCAL_BRANCH="$(git symbolic-ref --short HEAD 2>/dev/null)" 55 | VCS_STATUS_COMMITS_AHEAD="$(git rev-list --count '@{upstream}..HEAD' 2>/dev/null)" 56 | VCS_STATUS_COMMITS_BEHIND="$(git rev-list --count 'HEAD..@{upstream}' 2>/dev/null)" 57 | VCS_STATUS_TAG="$(git describe --tags --exact-match HEAD 2>/dev/null)" 58 | VCS_STATUS_COMMIT="$(git rev-parse HEAD 2>/dev/null)" 59 | local gitstatus_porcelain="$(git status --porcelain 2>/dev/null)" 60 | [[ -n "$gitstatus_porcelain" ]] && VCS_STATUS_IS_DIRTY=1 || VCS_STATUS_IS_DIRTY=0 61 | VCS_STATUS_STASHES="$(git rev-list --walk-reflogs --count refs/stash 2>/dev/null || echo 0)" 62 | } 63 | 64 | # Fish-like path shortener: $HOME/.config/bash/.docs/cheatsheet => ~/.c/b/.d/cheatsheet 65 | function prompt_hydro_short_path() { 66 | local dirname ancestor_path shortened_path 67 | local color_reset color_darkgrey color_bold_blue 68 | color_reset="\[\e[00m\]" 69 | color_darkgrey="\[\e[38;5;243m\]" 70 | color_bold_blue="\[\e[34;1m\]" 71 | shortened_path="$(shorten_path "$PWD")" 72 | dirname="${shortened_path##*/}" 73 | [[ "$shortened_path" == */* ]] && ancestor_path="${shortened_path%/*}/" 74 | printf '%s' "${HYDRO_COLOR_SHORTENED_PWD:-$color_darkgrey}" "$ancestor_path" \ 75 | "${HYDRO_COLOR_PWD:-$color_bold_blue}" "$dirname" "${color_reset}" 76 | } 77 | 78 | # Set the " main• ↑1 ↓2" part of the Hydro prompt. 79 | function prompt_hydro_git_string() { 80 | local git_branch git_dirty git_behind git_ahead color_green 81 | 82 | # Fail fast. 83 | set_vcs_vars 84 | [[ "$VCS_STATUS_RESULT" == ok-* ]] || return 1 85 | 86 | # Set the git branch name. 87 | git_branch=" ${VCS_STATUS_LOCAL_BRANCH:-${VCS_STATUS_TAG:-${VCS_STATUS_COMMIT:0:8}}}" 88 | 89 | # Set ahead/behind string: ↑1 ↓2 (notice git gives the reverse order from what we want). 90 | # Helpful symbols: ⇕⇡⇣↑↓ 91 | # shellcheck disable=SC2207 92 | if [[ "$VCS_STATUS_COMMITS_AHEAD" -gt 0 ]]; then 93 | git_ahead=" ${HYDRO_SYMBOL_GIT_AHEAD:-⇡}${VCS_STATUS_COMMITS_AHEAD}" 94 | fi 95 | if [[ "$VCS_STATUS_COMMITS_BEHIND" -gt 0 ]]; then 96 | git_behind=" ${HYDRO_SYMBOL_GIT_BEHIND:-⇣}${VCS_STATUS_COMMITS_BEHIND}" 97 | fi 98 | 99 | # Set the dirty symbol. 100 | if [[ "$VCS_STATUS_IS_DIRTY" -eq 1 ]]; then 101 | git_dirty="${HYDRO_SYMBOL_GIT_DIRTY:-•}" 102 | fi 103 | 104 | # Print the git part of the prompt. 105 | color_green="\[\e[32m\]" 106 | printf '%s' "${HYDRO_COLOR_GIT:-$color_green}" "${git_branch}" \ 107 | "${git_dirty}" "${git_ahead}" "${git_behind}" 108 | } 109 | 110 | # Bash version of Hydro - https://github.com/jorgebucaran/hydro 111 | # ~/p/hydro main• ↑1 ↓2 | 0 1 1 ❱ 112 | function prompt_hydro_setup() { 113 | local -a last_pipestatus=("${BLE_PIPESTATUS[@]:-${PIPESTATUS[@]}}") 114 | local prompt_error prompt_char 115 | 116 | color_red="\[\e[31m\]" 117 | color_magenta="\[\e[35m\]" 118 | color_reset="\[\e[00m\]" 119 | 120 | if [[ "${last_pipestatus[*]}" =~ [1-9] ]]; then 121 | prompt_error=" ${HYDRO_COLOR_ERROR:-$color_red}[${last_pipestatus[*]}]" 122 | fi 123 | prompt_char=" ${HYDRO_COLOR_PROMPT:-$color_magenta}${HYDRO_SYMBOL_PROMPT:-❱}" 124 | if [[ "${HYDRO_MULTILINE:-false}" != false ]]; then 125 | prompt_char="\n${prompt_char}" 126 | fi 127 | 128 | PS1="" 129 | if [[ -n "$VIRTUAL_ENV" ]]; then 130 | PS1+="(${VIRTUAL_ENV##*/}) " 131 | fi 132 | 133 | # bottom padding 134 | # PS1=$'\n\n\n\n\n\e[5A'"$PS1" 135 | 136 | PS1+="$(prompt_hydro_short_path)$(prompt_hydro_git_string)${prompt_error}${prompt_char} ${color_reset}" 137 | } 138 | 139 | # A minimal bash prompt. 140 | function prompt_minimal_setup() { 141 | PS1='[\u@\h \W]\$ ' 142 | } 143 | 144 | # Set the prompt theme. 145 | if [[ "$BASH_THEME" == "starship" ]]; then 146 | export STARSHIP_CONFIG="$XDG_CONFIG_HOME/starship/bash.toml" 147 | eval "$(starship init bash)" 148 | elif [[ "$(type -t "prompt_${BASH_THEME}_setup")" == function ]]; then 149 | export PROMPT_COMMAND="prompt_${BASH_THEME}_setup;${PROMPT_COMMAND}" 150 | else 151 | PS1='[\u@\h \W]\$ ' 152 | fi 153 | -------------------------------------------------------------------------------- /.config/bash/plugins/python.sh: -------------------------------------------------------------------------------- 1 | # shellcheck shell=bash source=/dev/null 2 | 3 | # Manage Python venvs. 4 | function venv { 5 | local workon_home="${WORKON_HOME:-${XDG_DATA_HOME:-$HOME/.local/share}/venvs}" 6 | local -a usage=( 7 | "usage: venv [--home=] [-r|--remove] [-p|--path] " 8 | " venv [-h|--help] [-l|--list]" 9 | ) 10 | local -a o_badopt o_home o_list o_remove o_path 11 | 12 | # Show help if no arguments provided. 13 | if [[ "$#" -eq 0 ]]; then 14 | printf "%s\n" "${usage[@]}"; return 0 15 | fi 16 | 17 | # Parse arguments 18 | while [[ "$#" -gt 0 ]]; do 19 | case "$1" in 20 | --) shift; break ;; 21 | -h|--help) printf "%s\n" "${usage[@]}"; return 0 ;; 22 | -l|--list) o_list+=("$1") ;; 23 | -r|--remove) o_remove+=("$1") ;; 24 | -p|--path) o_path+=("$1") ;; 25 | --home) shift; o_home+=("$1") ;; 26 | --home=*) o_home=("${1#*=}") ;; 27 | -*) o_badopt+=("$1") ;; 28 | *) break ;; 29 | esac 30 | shift 31 | done 32 | 33 | if [[ "${#o_badopt}" -gt 0 ]]; then 34 | echo >&2 "venv: Unexpected option '${o_badopt[0]}'." 35 | printf "%s\n" "${usage[@]}"; return 1 36 | fi 37 | 38 | if [[ "${#o_home}" -gt 0 ]]; then 39 | workon_home="${o_home[-1]}" 40 | fi 41 | 42 | # --list 43 | if [[ "${#o_list}" -gt 0 ]]; then 44 | shopt -s nullglob 45 | local pyvenv 46 | for pyvenv in "$workon_home"/*; do 47 | echo "${pyvenv##*/}" 48 | done 49 | shopt -u nullglob 50 | return 0 51 | fi 52 | 53 | # Expecting 54 | if [[ "$#" -eq 0 ]]; then 55 | echo >&2 "venv: Expecting argument . Try 'venv -h' for usage." 56 | return 1 57 | fi 58 | 59 | # --path/--remove 60 | if [[ "${#o_path}" -gt 0 ]] || [[ "${#o_remove}" -gt 0 ]]; then 61 | if [[ ! -d "$workon_home/$1" ]]; then 62 | echo >&2 "venv: pyvenv not found '$1'." 63 | return 1 64 | fi 65 | if [[ "${#o_remove}" -gt 0 ]]; then 66 | rm -rf -- "${workon_home:-?}/$1" 67 | else 68 | echo "$workon_home/$1" 69 | fi 70 | return 0 71 | fi 72 | 73 | # Make venv if missing and activate 74 | if [[ ! -d "$workon_home/$1" ]]; then 75 | echo "Creating pyvenv: '$1'." 76 | python3 -m venv "$workon_home/$1" || return 1 77 | fi 78 | source "$workon_home/$1/bin/activate" 79 | } 80 | 81 | # Work on Python venvs. 82 | function workon() { 83 | if [[ "$#" -eq 0 ]]; then 84 | echo >&2 "workon: Expecting name of Python venv." 85 | return 1 86 | fi 87 | local workon_home="${WORKON_HOME:-${XDG_DATA_HOME:-$HOME/.local/share}/venvs}" 88 | [[ -d "$workon_home" ]] || mkdir -p "$workon_home" 89 | if [[ ! -d "$workon_home/$1" ]]; then 90 | echo >&2 "workon: Python venv not found '$1'." 91 | return 1 92 | fi 93 | source "$workon_home/$1/bin/activate" 94 | } 95 | -------------------------------------------------------------------------------- /.config/bash/plugins/repos.sh: -------------------------------------------------------------------------------- 1 | # shellcheck shell=bash 2 | 3 | : "${REPO_HOME:=${XDG_CACHE_HOME:-$HOME/.cache}/bash/repos}" 4 | declare -a repos=() 5 | 6 | # Read the file line-by-line, skipping comments and empty lines. 7 | repos_txt="$BASH_HOME/repos.txt" 8 | while IFS= read -r line; do 9 | line="${line%#*}" 10 | 11 | # Trim leading/trailing whitespace and check if the line is not empty and not a comment. 12 | if [[ -n "$line" && ! "$line" =~ ^# ]]; then 13 | repos+=("$line") # Add the line to the array. 14 | fi 15 | done < "$repos_txt" 16 | 17 | # Clone missing repos. 18 | for repo in "${repos[@]}"; do 19 | [[ -d "$REPO_HOME/$repo" ]] && continue 20 | echo "Cloning ${repo}..." 21 | git clone --quiet --depth 1 --recurse-submodules --shallow-submodules \ 22 | "https://github.com/$repo" "$REPO_HOME/$repo" & 23 | done 24 | wait 25 | 26 | # Clean up. 27 | unset line repo repos_txt 28 | -------------------------------------------------------------------------------- /.config/bash/plugins/utils.sh: -------------------------------------------------------------------------------- 1 | # shellcheck shell=bash 2 | 3 | # Cross-platform support for an 'open' command. 4 | if ! type open >/dev/null 2>&1; then 5 | if [[ "$OSTYPE" == cygwin* ]]; then 6 | alias open='cygstart' 7 | elif [[ "$OSTYPE" == linux-android ]]; then 8 | alias open='termux-open' 9 | elif type explorer.exe >/dev/null 2>&1; then 10 | alias open='explorer.exe' 11 | elif type xdg-open >/dev/null 2>&1; then 12 | alias open='xdg-open' 13 | fi 14 | fi 15 | 16 | # Cross-platform support for clipboard commands (clipcopy/clippaste). 17 | if [[ "$OSTYPE" == darwin* ]]; then 18 | alias clipcopy='pbcopy' 19 | alias clippaste='pbpaste' 20 | elif [[ "$OSTYPE" == cygwin* ]]; then 21 | alias clipcopy='tee > /dev/clipboard' 22 | alias clippaste='cat /dev/clipboard' 23 | elif type clip.exe >/dev/null 2>&1 && type powershell.exe >/dev/null 2>&1; then 24 | alias clipcopy='clip.exe' 25 | alias clippaste='powershell.exe -noprofile -command Get-Clipboard' 26 | elif [[ -n "$WAYLAND_DISPLAY" ]] && type wl-copy >/dev/null 2>&1 && type wl-paste >/dev/null 2>&1; then 27 | alias clipcopy='wl-copy' 28 | alias clippaste='wl-paste' 29 | elif [[ -n "$DISPLAY" ]] && type xclip >/dev/null 2>&1; then 30 | alias clipcopy='xclip -selection clipboard -in' 31 | alias clippaste='xclip -selection clipboard -out' 32 | elif [[ -n "$DISPLAY" ]] && type xsel >/dev/null 2>&1; then 33 | alias clipcopy='xsel --clipboard --input' 34 | alias clippaste='xsel --clipboard --output' 35 | fi 36 | -------------------------------------------------------------------------------- /.config/bash/plugins/wezterm.sh: -------------------------------------------------------------------------------- 1 | # shellcheck shell=bash source=/dev/null 2 | 3 | [[ -n "${REPO_HOME}" ]] || return 1 4 | 5 | [[ "$TERM_PROGRAM" == "WezTerm" ]] || return 1 6 | if [[ -r "${REPO_HOME:-?}/wez/wezterm/assets/shell-integration/wezterm.sh" ]]; then 7 | source "${REPO_HOME:-?}/wez/wezterm/assets/shell-integration/wezterm.sh" 8 | else 9 | return 1 10 | fi 11 | 12 | function __wezterm_my_precmd() { 13 | __wezterm_set_user_var "TERM_CURRENT_SHELL" "bash $BASH_VERSION" 14 | } 15 | 16 | # Emit an OSC 1337 sequence to define vars that terminals like WezTerm/iTerm2 can use. 17 | if [[ -n "$BLE_VERSION" ]]; then 18 | blehook PRECMD+=__wezterm_my_precmd 19 | else 20 | precmd_functions+=(__wezterm_my_precmd) 21 | fi 22 | -------------------------------------------------------------------------------- /.config/bash/plugins/zoxide.sh: -------------------------------------------------------------------------------- 1 | # shellcheck shell=bash 2 | 3 | # Enable z command. 4 | if type zoxide >/dev/null 2>&1; then 5 | eval "$(zoxide init bash)" 6 | fi 7 | -------------------------------------------------------------------------------- /.config/bash/plugins/zzz.sh: -------------------------------------------------------------------------------- 1 | # shellcheck shell=bash 2 | 3 | # Clean up '$PATH'. 4 | # PATH="$( 5 | # printf %s "$PATH" | 6 | # awk -vRS=: -vORS= '!a[$0]++ {if (NR>1) printf(":"); printf("%s", $0) }' 7 | # )" 8 | 9 | # Attach ble.sh last. 10 | [[ ${BLE_VERSION-} ]] && ble-attach 11 | 12 | # End profiling. 13 | if [ "${PROFRC:-0}" -eq 1 ]; then 14 | set +x 15 | exec 2>&3 3>&- 16 | fi 17 | -------------------------------------------------------------------------------- /.config/bash/readme.md: -------------------------------------------------------------------------------- 1 | # bashrc 2 | 3 | ## XDG base directories 4 | 5 | Bash does not have a built-in way to use proper XDG base directory locations for 6 | its files, so you're forced to clutter up your $HOME. But, you can minimize the 7 | content of those $HOME files and put your real config in a different location by 8 | creating stubs for the Bash runcoms. For example, create the following stub in 9 | '~/.bashrc' to allow this file to live in '~/.config/bash/.bashrc'. It also allows 10 | you to try out other configs by changing a $BASH_HOME variable, like Zsh's $ZDOTDIR. 11 | 12 | ```bash 13 | # contents of ~/.bashrc 14 | export BASH_HOME="${BASH_HOME:-${XDG_CONFIG_HOME:-$HOME/.config}/bash}" 15 | [ -r "${BASH_HOME:-?}"/.bashrc ] && . "$BASH_HOME"/.bashrc 16 | 17 | # contents of ~/.bash_profile 18 | [ -r "${BASH_HOME:-?}"/.bash_profile ] && . "$BASH_HOME"/.bash_profile 19 | ``` 20 | 21 | ## ble.sh 22 | 23 | This config can leverage ble.sh if you have it installed. Ble.sh makes Bash a much 24 | nicer shell to use interactively. It's optional, but recommended. See here for more 25 | info: https://github.com/akinomyoga/ble.sh. 26 | 27 | You can install ble.sh by running the following commands: 28 | 29 | ```bash 30 | BLE_REPO_HOME="${XDG_CACHE_HOME:-$HOME/.cache}/repos/akinomyoga/ble.sh" 31 | git clone --depth 1 --recurse-submodules --shallow-submodules https://github.com/akinomyoga/ble.sh "$BLE_REPO_HOME" 32 | make -C "$BLE_REPO_HOME" install PREFIX=~/.local 33 | ``` 34 | -------------------------------------------------------------------------------- /.config/bash/repos.txt: -------------------------------------------------------------------------------- 1 | # Zsh-like preexec 2 | rcaloras/bash-preexec 3 | 4 | # Make bash modern. 5 | akinomyoga/ble.sh 6 | 7 | # Awesome terminal, with some helpful includes. 8 | wez/wezterm 9 | 10 | # Fast git status for prompts. 11 | romkatv/gitstatus 12 | 13 | # Bash frameworks, though I likely will snag snippets rather than use them. 14 | #bash-it/bash-it 15 | #ohmybash/oh-my-bash 16 | 17 | # vim: ft=jproperties sw=2 ts=2 et 18 | -------------------------------------------------------------------------------- /.config/git/gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.gitignore.io/api/go,osx,node,code,python,jupyternotebook,emacs,vim 2 | 3 | ### Code ### 4 | # Visual Studio Code - https://code.visualstudio.com/ 5 | .settings/ 6 | .vscode/ 7 | tsconfig.json 8 | jsconfig.json 9 | 10 | ### Emacs ### 11 | # -*- mode: gitignore; -*- 12 | *~ 13 | \#*\# 14 | /.emacs.desktop 15 | /.emacs.desktop.lock 16 | *.elc 17 | auto-save-list 18 | tramp 19 | .\#* 20 | 21 | # Org-mode 22 | .org-id-locations 23 | *_archive 24 | 25 | # flymake-mode 26 | *_flymake.* 27 | 28 | # eshell files 29 | /eshell/history 30 | /eshell/lastdir 31 | 32 | # elpa packages 33 | /elpa/ 34 | 35 | # reftex files 36 | *.rel 37 | 38 | # AUCTeX auto folder 39 | /auto/ 40 | 41 | # cask packages 42 | .cask/ 43 | dist/ 44 | 45 | # Flycheck 46 | flycheck_*.el 47 | 48 | # server auth directory 49 | /server/ 50 | 51 | # projectiles files 52 | .projectile 53 | 54 | # directory configuration 55 | .dir-locals.el 56 | 57 | ### Go ### 58 | # Binaries for programs and plugins 59 | *.exe 60 | *.exe~ 61 | *.dll 62 | *.so 63 | *.dylib 64 | 65 | # Test binary, build with `go test -c` 66 | *.test 67 | 68 | # Output of the go coverage tool, specifically when used with LiteIDE 69 | *.out 70 | 71 | ### Go Patch ### 72 | /vendor/ 73 | /Godeps/ 74 | 75 | ### JupyterNotebook ### 76 | .ipynb_checkpoints 77 | */.ipynb_checkpoints/* 78 | 79 | # Remove previous ipynb_checkpoints 80 | # git rm -r .ipynb_checkpoints/ 81 | # 82 | 83 | ### Node ### 84 | # Logs 85 | *.log 86 | npm-debug.log* 87 | yarn-debug.log* 88 | yarn-error.log* 89 | 90 | # Runtime data 91 | pids 92 | *.pid 93 | *.seed 94 | *.pid.lock 95 | 96 | # Directory for instrumented libs generated by jscoverage/JSCover 97 | lib-cov 98 | 99 | # Coverage directory used by tools like istanbul 100 | # coverage 101 | 102 | # nyc test coverage 103 | .nyc_output 104 | 105 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 106 | .grunt 107 | 108 | # Bower dependency directory (https://bower.io/) 109 | bower_components 110 | 111 | # node-waf configuration 112 | .lock-wscript 113 | 114 | # Compiled binary addons (https://nodejs.org/api/addons.html) 115 | build/Release 116 | 117 | # Dependency directories 118 | node_modules/ 119 | jspm_packages/ 120 | 121 | # TypeScript v1 declaration files 122 | typings/ 123 | 124 | # Optional npm cache directory 125 | .npm 126 | 127 | # Optional eslint cache 128 | .eslintcache 129 | 130 | # Optional REPL history 131 | .node_repl_history 132 | 133 | # Output of 'npm pack' 134 | *.tgz 135 | 136 | # Yarn Integrity file 137 | .yarn-integrity 138 | 139 | # dotenv environment variables file 140 | .env 141 | 142 | # parcel-bundler cache (https://parceljs.org/) 143 | .cache 144 | 145 | # next.js build output 146 | .next 147 | 148 | # nuxt.js build output 149 | .nuxt 150 | 151 | # vuepress build output 152 | .vuepress/dist 153 | 154 | # Serverless directories 155 | .serverless 156 | 157 | ### OSX ### 158 | # General 159 | .DS_Store 160 | .AppleDouble 161 | .LSOverride 162 | 163 | # Icon must end with two \r 164 | Icon 165 | 166 | # Thumbnails 167 | ._* 168 | 169 | # Files that might appear in the root of a volume 170 | .DocumentRevisions-V100 171 | .fseventsd 172 | .Spotlight-V100 173 | .TemporaryItems 174 | .Trashes 175 | .VolumeIcon.icns 176 | .com.apple.timemachine.donotpresent 177 | 178 | # Directories potentially created on remote AFP share 179 | .AppleDB 180 | .AppleDesktop 181 | Network Trash Folder 182 | Temporary Items 183 | .apdisk 184 | 185 | ### Python ### 186 | # Byte-compiled / optimized / DLL files 187 | __pycache__/ 188 | *.py[cod] 189 | *$py.class 190 | 191 | # C extensions 192 | 193 | # Distribution / packaging 194 | .Python 195 | build/ 196 | develop-eggs/ 197 | downloads/ 198 | eggs/ 199 | .eggs/ 200 | # lib/ # NO! 201 | lib64/ 202 | parts/ 203 | sdist/ 204 | var/ 205 | wheels/ 206 | *.egg-info/ 207 | .installed.cfg 208 | *.egg 209 | MANIFEST 210 | 211 | # PyInstaller 212 | # Usually these files are written by a python script from a template 213 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 214 | *.manifest 215 | *.spec 216 | 217 | # Installer logs 218 | pip-log.txt 219 | pip-delete-this-directory.txt 220 | 221 | # Unit test / coverage reports 222 | htmlcov/ 223 | .tox/ 224 | .coverage 225 | .coverage.* 226 | nosetests.xml 227 | coverage.xml 228 | *.cover 229 | .hypothesis/ 230 | .pytest_cache/ 231 | 232 | # Translations 233 | *.mo 234 | *.pot 235 | 236 | # Django stuff: 237 | local_settings.py 238 | db.sqlite3 239 | 240 | # Flask stuff: 241 | instance/ 242 | .webassets-cache 243 | 244 | # Scrapy stuff: 245 | .scrapy 246 | 247 | # Sphinx documentation 248 | docs/_build/ 249 | 250 | # PyBuilder 251 | target/ 252 | 253 | # Jupyter Notebook 254 | 255 | # pyenv 256 | .python-version 257 | 258 | # celery beat schedule file 259 | celerybeat-schedule 260 | 261 | # SageMath parsed files 262 | *.sage.py 263 | 264 | # Environments 265 | .venv 266 | env/ 267 | venv/ 268 | ENV/ 269 | env.bak/ 270 | venv.bak/ 271 | 272 | # Spyder project settings 273 | .spyderproject 274 | .spyproject 275 | 276 | # Rope project settings 277 | .ropeproject 278 | 279 | # mkdocs documentation 280 | /site 281 | 282 | # mypy 283 | .mypy_cache/ 284 | 285 | ### Python Patch ### 286 | .venv/ 287 | 288 | ### Vim ### 289 | # Swap 290 | [._]*.s[a-v][a-z] 291 | [._]*.sw[a-p] 292 | [._]s[a-rt-v][a-z] 293 | [._]ss[a-gi-z] 294 | [._]sw[a-p] 295 | 296 | # Session 297 | Session.vim 298 | 299 | # Temporary 300 | .netrwhist 301 | # Auto-generated tag files 302 | tags 303 | # Persistent undo 304 | [._]*.un~ 305 | 306 | # End of https://www.gitignore.io/api/go,osx,node,code,python,jupyternotebook,emacs,vim 307 | 308 | .idea/ 309 | .vscode/ 310 | 311 | *.zwc 312 | *.zwc.old 313 | 314 | # test things 315 | foo 316 | foo.* 317 | .foo 318 | .foo/* 319 | -------------------------------------------------------------------------------- /.config/helix/config.toml: -------------------------------------------------------------------------------- 1 | theme = "tokyonight" 2 | 3 | [editor] 4 | line-number = "relative" 5 | 6 | [editor.cursor-shape] 7 | insert = "bar" 8 | normal = "block" 9 | select = "underline" 10 | 11 | [editor.file-picker] 12 | hidden = false 13 | 14 | [keys.normal] 15 | # ------------------------- 16 | # QWERTY to Colemak - UNEI arrows 17 | # [YJ] [UL] [IU] [..] 18 | # [HH] [JN] [KE] [LI] 19 | # [NK] [..] [..] [..] 20 | # 21 | # N <=> K (K is in the QWERTY N position) 22 | n = "move_char_left" 23 | N = "keep_selections" 24 | k = "search_next" 25 | K = "search_prev" 26 | # E <=> J (J now 'jumps words') 27 | e = "move_line_down" 28 | E = "join_selections" 29 | j = "move_next_word_end" 30 | J = "move_next_long_word_end" 31 | # H <=> I (H is just a sideways I) 32 | i = "move_char_right" 33 | I = "no_op" 34 | h = "insert_mode" 35 | H = "insert_at_line_start" 36 | # U <=> L (L is in the QWERTY U position) 37 | u = "move_line_up" 38 | U = "no_op" 39 | l = "undo" 40 | L = "redo" 41 | -------------------------------------------------------------------------------- /.config/homebrew/init.brewfile: -------------------------------------------------------------------------------- 1 | tap "homebrew/bundle" 2 | tap "homebrew/cask-fonts" 3 | brew "coreutils" 4 | brew "curl" 5 | brew "editorconfig" 6 | brew "fish" 7 | brew "fzf" 8 | brew "git" 9 | brew "gnupg" 10 | brew "go" 11 | brew "helix" 12 | brew "mas" 13 | brew "neovim" 14 | brew "oath-toolkit" 15 | brew "sqlite" 16 | brew "ripgrep" 17 | brew "rsync" 18 | brew "starship" 19 | brew "stow" 20 | brew "tmux" 21 | brew "tree" 22 | brew "vim" 23 | brew "wget" 24 | brew "yq" 25 | brew "zoxide" 26 | brew "zsh" 27 | cask "alfred" 28 | cask "bartender" 29 | cask "betterdisplay" 30 | cask "brave-browser" 31 | cask "font-fira-code" 32 | cask "font-fira-code-nerd-font" 33 | cask "font-hack-nerd-font" 34 | cask "font-inconsolata-nerd-font" 35 | cask "font-iosevka-nerd-font" 36 | cask "font-meslo-lg-nerd-font" 37 | cask "font-sauce-code-pro-nerd-font" 38 | cask "hammerspoon" 39 | cask "iterm2" 40 | cask "keepingyouawake" 41 | cask "slack" 42 | cask "sublime-text" 43 | cask "visual-studio-code" 44 | mas "Bitwarden", id: 1352778147 45 | mas "DaisyDisk", id: 411643860 46 | mas "GarageBand", id: 682658836 47 | mas "GoodNotes", id: 1444383602 48 | mas "iMovie", id: 408981434 49 | mas "Keynote", id: 409183694 50 | mas "Microsoft Excel", id: 462058435 51 | mas "Microsoft OneNote", id: 784801555 52 | mas "Microsoft Outlook", id: 985367838 53 | mas "Microsoft PowerPoint", id: 462062816 54 | mas "Microsoft Word", id: 462054704 55 | mas "MindNode", id: 1289197285 56 | mas "Numbers", id: 409203825 57 | mas "OneDrive", id: 823766827 58 | mas "Pages", id: 409201541 59 | mas "Pixelmator Pro", id: 1289583905 60 | mas "Tampermonkey", id: 1482490089 61 | mas "TaskPaper", id: 1090940630 62 | mas "Wipr", id: 1320666476 63 | -------------------------------------------------------------------------------- /.config/kak/kakrc: -------------------------------------------------------------------------------- 1 | colorscheme tomorrow-night 2 | define-command -docstring "Example Lua plugin" run-example %sh{ 3 | lua $HOME/.config/kak/plugins/example.lua 4 | } 5 | -------------------------------------------------------------------------------- /.config/kak/plugins/example.lua: -------------------------------------------------------------------------------- 1 | -- myplugin.lua 2 | local message = "Hello from Lua!" 3 | print(message) 4 | -------------------------------------------------------------------------------- /.config/npm/npmrc: -------------------------------------------------------------------------------- 1 | prefix=${XDG_DATA_HOME}/npm 2 | cache=${XDG_CACHE_HOME}/npm 3 | tmp=${XDG_RUNTIME_DIR}/npm 4 | init-module=${XDG_CONFIG_HOME}/npm/config/npm-init.js 5 | -------------------------------------------------------------------------------- /.config/nvim/.gitignore: -------------------------------------------------------------------------------- 1 | tags 2 | test.sh 3 | .luarc.json 4 | nvim 5 | 6 | spell/ 7 | -------------------------------------------------------------------------------- /.config/nvim/.stylua.toml: -------------------------------------------------------------------------------- 1 | column_width = 160 2 | line_endings = "Unix" 3 | indent_type = "Spaces" 4 | indent_width = 2 5 | quote_style = "AutoPreferSingle" 6 | call_parentheses = "None" 7 | -------------------------------------------------------------------------------- /.config/nvim/LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /.config/nvim/doc/kickstart.txt: -------------------------------------------------------------------------------- 1 | ================================================================================ 2 | INTRODUCTION *kickstart.nvim* 3 | 4 | Kickstart.nvim is a project to help you get started on your neovim journey. 5 | 6 | *kickstart-is-not* 7 | It is not: 8 | - Complete framework for every plugin under the sun 9 | - Place to add every plugin that could ever be useful 10 | 11 | *kickstart-is* 12 | It is: 13 | - Somewhere that has a good start for the most common "IDE" type features: 14 | - autocompletion 15 | - goto-definition 16 | - find references 17 | - fuzzy finding 18 | - and hinting at what more can be done :) 19 | - A place to _kickstart_ your journey. 20 | - You should fork this project and use/modify it so that it matches your 21 | style and preferences. If you don't want to do that, there are probably 22 | other projects that would fit much better for you (and that's great!)! 23 | 24 | vim:tw=78:ts=8:ft=help:norl: 25 | -------------------------------------------------------------------------------- /.config/nvim/lazy-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "LuaSnip": { "branch": "master", "commit": "e808bee352d1a6fcf902ca1a71cee76e60e24071" }, 3 | "cmp-nvim-lsp": { "branch": "main", "commit": "39e2eda76828d88b773cc27a3f61d2ad782c922d" }, 4 | "cmp-path": { "branch": "main", "commit": "91ff86cd9c29299a64f968ebb45846c485725f23" }, 5 | "cmp_luasnip": { "branch": "master", "commit": "05a9ab28b53f71d1aece421ef32fee2cb857a843" }, 6 | "conform.nvim": { "branch": "master", "commit": "1a99fdc1d3aa9ccdf3021e67982a679a8c5c740c" }, 7 | "fidget.nvim": { "branch": "main", "commit": "d855eed8a06531a7e8fd0684889b2943f373c469" }, 8 | "gitsigns.nvim": { "branch": "main", "commit": "1ef74b546732f185d0f806860fa5404df7614f28" }, 9 | "lazy.nvim": { "branch": "main", "commit": "077102c5bfc578693f12377846d427f49bc50076" }, 10 | "lazydev.nvim": { "branch": "main", "commit": "491452cf1ca6f029e90ad0d0368848fac717c6d2" }, 11 | "luvit-meta": { "branch": "main", "commit": "ce76f6f6cdc9201523a5875a4471dcfe0186eb60" }, 12 | "mason-lspconfig.nvim": { "branch": "main", "commit": "25c11854aa25558ee6c03432edfa0df0217324be" }, 13 | "mason-tool-installer.nvim": { "branch": "main", "commit": "c5e07b8ff54187716334d585db34282e46fa2932" }, 14 | "mason.nvim": { "branch": "main", "commit": "e2f7f9044ec30067bc11800a9e266664b88cda22" }, 15 | "mini.icons": { "branch": "main", "commit": "2d89252993fec829b24720097a687412d10f6c85" }, 16 | "mini.nvim": { "branch": "main", "commit": "e50cf9de614500a20e47cfc50e30a100042f91c3" }, 17 | "nvim-cmp": { "branch": "main", "commit": "ae644feb7b67bf1ce4260c231d1d4300b19c6f30" }, 18 | "nvim-lspconfig": { "branch": "master", "commit": "a9bc587e9ae0cbcb3e90a2e9342f86b3b78c4408" }, 19 | "nvim-treesitter": { "branch": "master", "commit": "0c8a582e474e248f2a4406188e0c653f92a064cf" }, 20 | "nvim-web-devicons": { "branch": "master", "commit": "26220156aafb198b2de6a4cf80c1b120a3768da0" }, 21 | "oil.nvim": { "branch": "master", "commit": "1360be5fda9c67338331abfcd80de2afbb395bcd" }, 22 | "plenary.nvim": { "branch": "master", "commit": "2d9b06177a975543726ce5c73fca176cedbffe9d" }, 23 | "telescope-fzf-native.nvim": { "branch": "main", "commit": "cf48d4dfce44e0b9a2e19a008d6ec6ea6f01a83b" }, 24 | "telescope-ui-select.nvim": { "branch": "master", "commit": "6e51d7da30bd139a6950adf2a47fda6df9fa06d2" }, 25 | "telescope.nvim": { "branch": "0.1.x", "commit": "a0bbec21143c7bc5f8bb02e0005fa0b982edc026" }, 26 | "todo-comments.nvim": { "branch": "main", "commit": "ae0a2afb47cf7395dc400e5dc4e05274bf4fb9e0" }, 27 | "tokyonight.nvim": { "branch": "main", "commit": "817bb6ffff1b9ce72cdd45d9fcfa8c9cd1ad3839" }, 28 | "vim-sleuth": { "branch": "master", "commit": "be69bff86754b1aa5adcbb527d7fcd1635a84080" }, 29 | "which-key.nvim": { "branch": "main", "commit": "fb070344402cfc662299d9914f5546d840a22126" } 30 | } 31 | -------------------------------------------------------------------------------- /.config/nvim/lua/custom/plugins/init.lua: -------------------------------------------------------------------------------- 1 | -- You can add your own plugins here or in other files in this directory! 2 | -- I promise not to create any merge conflicts in this directory :) 3 | -- 4 | -- See the kickstart.nvim README for more information 5 | return {} 6 | -------------------------------------------------------------------------------- /.config/nvim/lua/kickstart/health.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | -- 3 | -- This file is not required for your own configuration, 4 | -- but helps people determine if their system is setup correctly. 5 | -- 6 | --]] 7 | 8 | local check_version = function() 9 | local verstr = tostring(vim.version()) 10 | if not vim.version.ge then 11 | vim.health.error(string.format("Neovim out of date: '%s'. Upgrade to latest stable or nightly", verstr)) 12 | return 13 | end 14 | 15 | if vim.version.ge(vim.version(), '0.10-dev') then 16 | vim.health.ok(string.format("Neovim version is: '%s'", verstr)) 17 | else 18 | vim.health.error(string.format("Neovim out of date: '%s'. Upgrade to latest stable or nightly", verstr)) 19 | end 20 | end 21 | 22 | local check_external_reqs = function() 23 | -- Basic utils: `git`, `make`, `unzip` 24 | for _, exe in ipairs { 'git', 'make', 'unzip', 'rg' } do 25 | local is_executable = vim.fn.executable(exe) == 1 26 | if is_executable then 27 | vim.health.ok(string.format("Found executable: '%s'", exe)) 28 | else 29 | vim.health.warn(string.format("Could not find executable: '%s'", exe)) 30 | end 31 | end 32 | 33 | return true 34 | end 35 | 36 | return { 37 | check = function() 38 | vim.health.start 'kickstart.nvim' 39 | 40 | vim.health.info [[NOTE: Not every warning is a 'must-fix' in `:checkhealth` 41 | 42 | Fix only warnings for plugins and languages you intend to use. 43 | Mason will give warnings for languages that are not installed. 44 | You do not need to install, unless you want to use those languages!]] 45 | 46 | local uv = vim.uv or vim.loop 47 | vim.health.info('System Information: ' .. vim.inspect(uv.os_uname())) 48 | 49 | check_version() 50 | check_external_reqs() 51 | end, 52 | } 53 | -------------------------------------------------------------------------------- /.config/nvim/lua/kickstart/plugins/autopairs.lua: -------------------------------------------------------------------------------- 1 | -- autopairs 2 | -- https://github.com/windwp/nvim-autopairs 3 | 4 | return { 5 | 'windwp/nvim-autopairs', 6 | event = 'InsertEnter', 7 | -- Optional dependency 8 | dependencies = { 'hrsh7th/nvim-cmp' }, 9 | config = function() 10 | require('nvim-autopairs').setup {} 11 | -- If you want to automatically add `(` after selecting a function or method 12 | local cmp_autopairs = require 'nvim-autopairs.completion.cmp' 13 | local cmp = require 'cmp' 14 | cmp.event:on('confirm_done', cmp_autopairs.on_confirm_done()) 15 | end, 16 | } 17 | -------------------------------------------------------------------------------- /.config/nvim/lua/kickstart/plugins/debug.lua: -------------------------------------------------------------------------------- 1 | -- debug.lua 2 | -- 3 | -- Shows how to use the DAP plugin to debug your code. 4 | -- 5 | -- Primarily focused on configuring the debugger for Go, but can 6 | -- be extended to other languages as well. That's why it's called 7 | -- kickstart.nvim and not kitchen-sink.nvim ;) 8 | 9 | return { 10 | -- NOTE: Yes, you can install new plugins here! 11 | 'mfussenegger/nvim-dap', 12 | -- NOTE: And you can specify dependencies as well 13 | dependencies = { 14 | -- Creates a beautiful debugger UI 15 | 'rcarriga/nvim-dap-ui', 16 | 17 | -- Required dependency for nvim-dap-ui 18 | 'nvim-neotest/nvim-nio', 19 | 20 | -- Installs the debug adapters for you 21 | 'williamboman/mason.nvim', 22 | 'jay-babu/mason-nvim-dap.nvim', 23 | 24 | -- Add your own debuggers here 25 | 'leoluz/nvim-dap-go', 26 | }, 27 | keys = function(_, keys) 28 | local dap = require 'dap' 29 | local dapui = require 'dapui' 30 | return { 31 | -- Basic debugging keymaps, feel free to change to your liking! 32 | { '', dap.continue, desc = 'Debug: Start/Continue' }, 33 | { '', dap.step_into, desc = 'Debug: Step Into' }, 34 | { '', dap.step_over, desc = 'Debug: Step Over' }, 35 | { '', dap.step_out, desc = 'Debug: Step Out' }, 36 | { 'b', dap.toggle_breakpoint, desc = 'Debug: Toggle Breakpoint' }, 37 | { 38 | 'B', 39 | function() 40 | dap.set_breakpoint(vim.fn.input 'Breakpoint condition: ') 41 | end, 42 | desc = 'Debug: Set Breakpoint', 43 | }, 44 | -- Toggle to see last session result. Without this, you can't see session output in case of unhandled exception. 45 | { '', dapui.toggle, desc = 'Debug: See last session result.' }, 46 | unpack(keys), 47 | } 48 | end, 49 | config = function() 50 | local dap = require 'dap' 51 | local dapui = require 'dapui' 52 | 53 | require('mason-nvim-dap').setup { 54 | -- Makes a best effort to setup the various debuggers with 55 | -- reasonable debug configurations 56 | automatic_installation = true, 57 | 58 | -- You can provide additional configuration to the handlers, 59 | -- see mason-nvim-dap README for more information 60 | handlers = {}, 61 | 62 | -- You'll need to check that you have the required things installed 63 | -- online, please don't ask me how to install them :) 64 | ensure_installed = { 65 | -- Update this to ensure that you have the debuggers for the langs you want 66 | 'delve', 67 | }, 68 | } 69 | 70 | -- Dap UI setup 71 | -- For more information, see |:help nvim-dap-ui| 72 | dapui.setup { 73 | -- Set icons to characters that are more likely to work in every terminal. 74 | -- Feel free to remove or use ones that you like more! :) 75 | -- Don't feel like these are good choices. 76 | icons = { expanded = '▾', collapsed = '▸', current_frame = '*' }, 77 | controls = { 78 | icons = { 79 | pause = '⏸', 80 | play = '▶', 81 | step_into = '⏎', 82 | step_over = '⏭', 83 | step_out = '⏮', 84 | step_back = 'b', 85 | run_last = '▶▶', 86 | terminate = '⏹', 87 | disconnect = '⏏', 88 | }, 89 | }, 90 | } 91 | 92 | dap.listeners.after.event_initialized['dapui_config'] = dapui.open 93 | dap.listeners.before.event_terminated['dapui_config'] = dapui.close 94 | dap.listeners.before.event_exited['dapui_config'] = dapui.close 95 | 96 | -- Install golang specific config 97 | require('dap-go').setup { 98 | delve = { 99 | -- On Windows delve must be run attached or it crashes. 100 | -- See https://github.com/leoluz/nvim-dap-go/blob/main/README.md#configuring 101 | detached = vim.fn.has 'win32' == 0, 102 | }, 103 | } 104 | end, 105 | } 106 | -------------------------------------------------------------------------------- /.config/nvim/lua/kickstart/plugins/gitsigns.lua: -------------------------------------------------------------------------------- 1 | -- Adds git related signs to the gutter, as well as utilities for managing changes 2 | -- NOTE: gitsigns is already included in init.lua but contains only the base 3 | -- config. This will add also the recommended keymaps. 4 | 5 | return { 6 | { 7 | 'lewis6991/gitsigns.nvim', 8 | opts = { 9 | on_attach = function(bufnr) 10 | local gitsigns = require 'gitsigns' 11 | 12 | local function map(mode, l, r, opts) 13 | opts = opts or {} 14 | opts.buffer = bufnr 15 | vim.keymap.set(mode, l, r, opts) 16 | end 17 | 18 | -- Navigation 19 | map('n', ']c', function() 20 | if vim.wo.diff then 21 | vim.cmd.normal { ']c', bang = true } 22 | else 23 | gitsigns.nav_hunk 'next' 24 | end 25 | end, { desc = 'Jump to next git [c]hange' }) 26 | 27 | map('n', '[c', function() 28 | if vim.wo.diff then 29 | vim.cmd.normal { '[c', bang = true } 30 | else 31 | gitsigns.nav_hunk 'prev' 32 | end 33 | end, { desc = 'Jump to previous git [c]hange' }) 34 | 35 | -- Actions 36 | -- visual mode 37 | map('v', 'hs', function() 38 | gitsigns.stage_hunk { vim.fn.line '.', vim.fn.line 'v' } 39 | end, { desc = 'stage git hunk' }) 40 | map('v', 'hr', function() 41 | gitsigns.reset_hunk { vim.fn.line '.', vim.fn.line 'v' } 42 | end, { desc = 'reset git hunk' }) 43 | -- normal mode 44 | map('n', 'hs', gitsigns.stage_hunk, { desc = 'git [s]tage hunk' }) 45 | map('n', 'hr', gitsigns.reset_hunk, { desc = 'git [r]eset hunk' }) 46 | map('n', 'hS', gitsigns.stage_buffer, { desc = 'git [S]tage buffer' }) 47 | map('n', 'hu', gitsigns.undo_stage_hunk, { desc = 'git [u]ndo stage hunk' }) 48 | map('n', 'hR', gitsigns.reset_buffer, { desc = 'git [R]eset buffer' }) 49 | map('n', 'hp', gitsigns.preview_hunk, { desc = 'git [p]review hunk' }) 50 | map('n', 'hb', gitsigns.blame_line, { desc = 'git [b]lame line' }) 51 | map('n', 'hd', gitsigns.diffthis, { desc = 'git [d]iff against index' }) 52 | map('n', 'hD', function() 53 | gitsigns.diffthis '@' 54 | end, { desc = 'git [D]iff against last commit' }) 55 | -- Toggles 56 | map('n', 'tb', gitsigns.toggle_current_line_blame, { desc = '[T]oggle git show [b]lame line' }) 57 | map('n', 'tD', gitsigns.toggle_deleted, { desc = '[T]oggle git show [D]eleted' }) 58 | end, 59 | }, 60 | }, 61 | } 62 | -------------------------------------------------------------------------------- /.config/nvim/lua/kickstart/plugins/indent_line.lua: -------------------------------------------------------------------------------- 1 | return { 2 | { -- Add indentation guides even on blank lines 3 | 'lukas-reineke/indent-blankline.nvim', 4 | -- Enable `lukas-reineke/indent-blankline.nvim` 5 | -- See `:help ibl` 6 | main = 'ibl', 7 | opts = {}, 8 | }, 9 | } 10 | -------------------------------------------------------------------------------- /.config/nvim/lua/kickstart/plugins/lint.lua: -------------------------------------------------------------------------------- 1 | return { 2 | 3 | { -- Linting 4 | 'mfussenegger/nvim-lint', 5 | event = { 'BufReadPre', 'BufNewFile' }, 6 | config = function() 7 | local lint = require 'lint' 8 | lint.linters_by_ft = { 9 | markdown = { 'markdownlint' }, 10 | } 11 | 12 | -- To allow other plugins to add linters to require('lint').linters_by_ft, 13 | -- instead set linters_by_ft like this: 14 | -- lint.linters_by_ft = lint.linters_by_ft or {} 15 | -- lint.linters_by_ft['markdown'] = { 'markdownlint' } 16 | -- 17 | -- However, note that this will enable a set of default linters, 18 | -- which will cause errors unless these tools are available: 19 | -- { 20 | -- clojure = { "clj-kondo" }, 21 | -- dockerfile = { "hadolint" }, 22 | -- inko = { "inko" }, 23 | -- janet = { "janet" }, 24 | -- json = { "jsonlint" }, 25 | -- markdown = { "vale" }, 26 | -- rst = { "vale" }, 27 | -- ruby = { "ruby" }, 28 | -- terraform = { "tflint" }, 29 | -- text = { "vale" } 30 | -- } 31 | -- 32 | -- You can disable the default linters by setting their filetypes to nil: 33 | -- lint.linters_by_ft['clojure'] = nil 34 | -- lint.linters_by_ft['dockerfile'] = nil 35 | -- lint.linters_by_ft['inko'] = nil 36 | -- lint.linters_by_ft['janet'] = nil 37 | -- lint.linters_by_ft['json'] = nil 38 | -- lint.linters_by_ft['markdown'] = nil 39 | -- lint.linters_by_ft['rst'] = nil 40 | -- lint.linters_by_ft['ruby'] = nil 41 | -- lint.linters_by_ft['terraform'] = nil 42 | -- lint.linters_by_ft['text'] = nil 43 | 44 | -- Create autocommand which carries out the actual linting 45 | -- on the specified events. 46 | local lint_augroup = vim.api.nvim_create_augroup('lint', { clear = true }) 47 | vim.api.nvim_create_autocmd({ 'BufEnter', 'BufWritePost', 'InsertLeave' }, { 48 | group = lint_augroup, 49 | callback = function() 50 | lint.try_lint() 51 | end, 52 | }) 53 | end, 54 | }, 55 | } 56 | -------------------------------------------------------------------------------- /.config/nvim/lua/kickstart/plugins/neo-tree.lua: -------------------------------------------------------------------------------- 1 | -- Neo-tree is a Neovim plugin to browse the file system 2 | -- https://github.com/nvim-neo-tree/neo-tree.nvim 3 | 4 | return { 5 | 'nvim-neo-tree/neo-tree.nvim', 6 | version = '*', 7 | dependencies = { 8 | 'nvim-lua/plenary.nvim', 9 | 'nvim-tree/nvim-web-devicons', -- not strictly required, but recommended 10 | 'MunifTanjim/nui.nvim', 11 | }, 12 | cmd = 'Neotree', 13 | keys = { 14 | { '\\', ':Neotree reveal', desc = 'NeoTree reveal', silent = true }, 15 | }, 16 | opts = { 17 | filesystem = { 18 | window = { 19 | mappings = { 20 | ['\\'] = 'close_window', 21 | }, 22 | }, 23 | }, 24 | }, 25 | } 26 | -------------------------------------------------------------------------------- /.config/pep8: -------------------------------------------------------------------------------- 1 | [pep8] 2 | ignore = E226,E731,E401,E402 3 | max-line-length = 100 4 | -------------------------------------------------------------------------------- /.config/pycodestyle: -------------------------------------------------------------------------------- 1 | [pycodestyle] 2 | ignore = E226,E731,E401,E402 3 | max-line-length = 100 4 | -------------------------------------------------------------------------------- /.config/readline/inputrc: -------------------------------------------------------------------------------- 1 | # inputrc is the config for GNU Readline. Anything that uses Readline 2 | # benefits from these configs (in case you're wondering why they aren't 3 | # in .bashrc). 4 | # From http://www.ukuug.org/events/linux2003/papers/bash_tips/ 5 | # https://github.com/JEG2/dotfiles/blob/master/inputrc 6 | 7 | # allow the use of the Home/End keys 8 | "\e[1~": beginning-of-line 9 | "\e[4~": end-of-line 10 | 11 | # allow the use of the Delete/Insert keys 12 | "\e[3~": delete-char 13 | "\e[2~": quoted-insert 14 | 15 | # mappings for "page up" and "page down" 16 | # to step to the beginning/end of the history 17 | "\e[5~": beginning-of-history 18 | "\e[6~": end-of-history 19 | 20 | "\e[5C": forward-word 21 | "\e[5D": backward-word 22 | "\e\e[C": forward-word 23 | "\e\e[D": backward-word 24 | 25 | set completion-ignore-case on 26 | set expand-tilde on 27 | set convert-meta off 28 | set input-meta on 29 | set output-meta on 30 | set show-all-if-ambiguous on 31 | set visible-stats on 32 | set bell-style none 33 | -------------------------------------------------------------------------------- /.config/starship/bash.toml: -------------------------------------------------------------------------------- 1 | # 2 | # My default bash prompt theme 3 | # 4 | 5 | add_newline = false 6 | 7 | # A minimal left prompt 8 | format = """ 9 | $line_break\ 10 | ${custom.dirname}\ 11 | ${custom.basename}\ 12 | $git_branch\ 13 | ${custom.git_status_dirty}\ 14 | $git_status 15 | $python\ 16 | $character\ 17 | """ 18 | 19 | # Move the rest of the prompt to the right 20 | right_format = """ 21 | $all$status$cmd_duration 22 | """ 23 | 24 | # Timeout for commands executed by starship (in milliseconds) 25 | command_timeout = 2000 26 | 27 | # Set the palette. 28 | palette = "p10k" 29 | 30 | # Define custom colors 31 | [palettes.tokyo_night_256] 32 | black = '16' 33 | blue = '111' 34 | cyan = '117' 35 | green = '149' 36 | purple = '141' 37 | red = '210' 38 | white = '146' 39 | yellow = '179' 40 | 41 | [palettes.wombat_256] 42 | black = '0' 43 | blue = '75' 44 | cyan = '123' 45 | green = '149' 46 | purple = '171' 47 | red = '203' 48 | white = '188' 49 | yellow = '223' 50 | true_white = '255' 51 | 52 | [palettes.p10k] 53 | black = '0' 54 | blue = '31' 55 | cyan = '39' 56 | green = '76' 57 | purple = '205' 58 | magenta = '205' 59 | red = '204' 60 | white = '223' 61 | yellow = '226' 62 | 63 | [character] 64 | success_symbol = '[\$](green)' 65 | error_symbol = '[\$](red)' 66 | vicmd_symbol = '[vi\$](bold white)' 67 | 68 | [python] 69 | format = '[(\($virtualenv\) )]($style)' 70 | style = 'white' 71 | 72 | [directory] 73 | style = "bold cyan" 74 | truncate_to_repo = false 75 | disabled = true 76 | 77 | [git_branch] 78 | format = '[$branch]($style)' 79 | style = 'purple' 80 | 81 | [git_status] 82 | format = '( [\[$ahead_behind$stashed\]]($style))' 83 | style = "cyan" 84 | stashed = "≡" 85 | ahead = "⇡${count}" 86 | behind = "⇣${count}" 87 | diverged = "⇕⇡${ahead_count}⇣${behind_count}" 88 | 89 | [custom.git_status_dirty] 90 | when = 'test -n "$(git status --porcelain 2>/dev/null)"' 91 | symbol = "•" 92 | style = "yellow" 93 | format = "[$symbol]($style)" 94 | shell = ["sh"] 95 | 96 | [custom.dirname] 97 | when = true 98 | command = 'test "$PWD" != "$HOME" && printf "%s/\n" "$(dirname "$PWD")" | sed -E "s|$HOME/|\~/|"' 99 | format = '[$symbol($output)]($style)' 100 | style = "blue" 101 | disabled = false 102 | shell = ["sh"] 103 | 104 | [custom.basename] 105 | when = true 106 | command = 'test "$PWD" = "$HOME" && echo "~" || basename "$PWD" | sed -E "s|$HOME/|\~/|"' 107 | style = "bold cyan" 108 | disabled = false 109 | shell = ["sh"] 110 | 111 | [custom.todo] 112 | when = 'test $(todo.sh ls | wc -l) -gt 2' 113 | command = 'todo.sh ls | tail -n 1 | cut -d" " -f2' 114 | symbol = "☑" 115 | format = '[$symbol( $output)]($style)' 116 | style = "blue" 117 | disabled = false 118 | shell = ["sh"] 119 | 120 | [cmd_duration] 121 | format = ' [$duration]($style)' 122 | 123 | [line_break] 124 | disabled = false 125 | 126 | [status] 127 | disabled = false 128 | format = '[$symbol$int]($style)' 129 | symbol = '✘' 130 | pipestatus = true 131 | pipestatus_format = '\[$pipestatus\]($style)' 132 | -------------------------------------------------------------------------------- /.config/starship/fish.toml: -------------------------------------------------------------------------------- 1 | add_newline = false 2 | 3 | # A minimal left prompt 4 | format = """$python$directory$character""" 5 | 6 | # move the rest of the prompt to the right 7 | right_format = """$status$all$git_branch$git_status""" 8 | 9 | [character] 10 | success_symbol = "[»](cyan)" 11 | error_symbol = "[»](red)" 12 | vicmd_symbol = "[⪻](yellow)" 13 | 14 | [python] 15 | format = '\($virtualenv\) ' 16 | 17 | [directory] 18 | style = "blue" 19 | truncation_length = 1 20 | truncation_symbol = "" 21 | fish_style_pwd_dir_length = 1 22 | 23 | # right prompt uses left space padding 24 | [git_branch] 25 | format = ' [$branch]($style)' 26 | style = 'bold green' 27 | 28 | # [git_status] 29 | # format = '$all_status$ahead_behind' 30 | # ahead = ' [⬆](bold purple)' 31 | # behind = ' [⬇](bold purple)' 32 | # staged = ' [✚](green)' 33 | # deleted = ' [✖](red)' 34 | # renamed = ' [➜](purple)' 35 | # stashed = ' [✭](cyan)' 36 | # untracked = ' [◼](white)' 37 | # modified = ' [✱](blue)' 38 | # conflicted = ' [═](yellow)' 39 | # diverged = ' ⇕' 40 | # up_to_date = '' 41 | 42 | [cmd_duration] 43 | format = ' [$duration]($style)' 44 | 45 | [line_break] 46 | disabled = true 47 | 48 | [status] 49 | disabled = false 50 | symbol = ' ✘' 51 | -------------------------------------------------------------------------------- /.config/starship/hydro.toml: -------------------------------------------------------------------------------- 1 | # 2 | # hydro - mimic Fish's hydro prompt 3 | # 4 | 5 | add_newline = false 6 | 7 | # A minimal left prompt 8 | format = """$all$directory$git_branch${custom.git_status_dirty}$git_status$cmd_duration$status$character""" 9 | 10 | # no right prompt 11 | right_format = "" 12 | 13 | # Timeout for commands executed by starship (in milliseconds) 14 | command_timeout=2000 15 | 16 | [character] 17 | success_symbol = "[❱](purple)" 18 | error_symbol = "[❱](red)" 19 | vicmd_symbol = "[❰](cyan)" 20 | 21 | [python] 22 | format = '[(\($virtualenv\) )]($style)' 23 | style = 'white' 24 | 25 | [directory] 26 | style = "blue" 27 | truncation_length = 1 28 | truncation_symbol = "" 29 | fish_style_pwd_dir_length = 1 30 | 31 | # right prompt uses left space padding 32 | [git_branch] 33 | format = '[$branch]($style)' 34 | style = 'bold green' 35 | 36 | [git_status] 37 | format = "[($ahead_behind$stashed)]($style) " 38 | style = "cyan" 39 | stashed = "≡" 40 | ahead = "⇡${count}" 41 | behind = "⇣${count}" 42 | diverged = "⇕⇡${ahead_count}⇣${behind_count}" 43 | 44 | [custom.git_status_dirty] 45 | when = 'test -n "$(git status --porcelain 2>/dev/null)"' 46 | symbol = "•" 47 | style = "white" 48 | format="[$symbol]($style)" 49 | shell = ["zsh", "--no-rcs", "--no-globalrcs"] 50 | 51 | [cmd_duration] 52 | format = '[$duration]($style) ' 53 | 54 | [line_break] 55 | disabled = true 56 | 57 | [status] 58 | disabled = false 59 | pipestatus = true 60 | format = '[$symbol$int]($style)' 61 | symbol = '✘' 62 | pipestatus_format = '\[$pipestatus\]($style)' 63 | -------------------------------------------------------------------------------- /.config/starship/mmc.toml: -------------------------------------------------------------------------------- 1 | # 2 | # mmc - My default prompt theme 3 | # 4 | 5 | add_newline = false 6 | 7 | # A minimal left prompt 8 | format = """$python$directory$character""" 9 | 10 | # Move the rest of the prompt to the right 11 | right_format = """$status$cmd_duration$git_branch${custom.git_status_dirty}$git_status$shell""" 12 | 13 | # Timeout for commands executed by starship (in milliseconds) 14 | command_timeout=2000 15 | 16 | # Set the palette. 17 | palette = "wombat_256" 18 | 19 | # Define custom colors 20 | [palettes.tokyo_night] 21 | black = '#15161e' 22 | blue = '#7aa2f7' 23 | cyan = '#7dcfff' 24 | green = '#9ece6a' 25 | purple = '#bb9af7' 26 | red = '#f7768e' 27 | white = '#a9b1d6' 28 | yellow = '#e0af68' 29 | 30 | [palettes.tokyo_night_256] 31 | black = '16' 32 | blue = '111' 33 | cyan = '117' 34 | green = '149' 35 | purple = '141' 36 | red = '210' 37 | white = '146' 38 | yellow = '179' 39 | 40 | [palettes.wombat] 41 | black = '#000000' 42 | blue = '#5da9f6' 43 | cyan = '#82fff7' 44 | green = '#b1e969' 45 | purple = '#e86aff' 46 | red = '#ff615a' 47 | white = '#dedacf' 48 | yellow = '#ebd99c' 49 | 50 | [palettes.wombat_256] 51 | black = '0' 52 | blue = '75' 53 | cyan = '123' 54 | green = '149' 55 | purple = '171' 56 | red = '203' 57 | white = '188' 58 | yellow = '223' 59 | 60 | [character] 61 | success_symbol = "[❯](purple)[❯](cyan)" 62 | error_symbol = "[❯](yellow)[❯](red)" 63 | vicmd_symbol = "[❮](purple)[❮](cyan)" 64 | 65 | [python] 66 | format = '[(\($virtualenv\) )]($style)' 67 | style = 'white' 68 | 69 | [directory] 70 | style = "blue" 71 | truncation_length = 1 72 | truncation_symbol = "" 73 | fish_style_pwd_dir_length = 1 74 | 75 | # Right prompt uses left space padding. 76 | [git_branch] 77 | format = ' [$branch]($style)' 78 | style = 'green' 79 | 80 | [git_status] 81 | format = '( [\[$ahead_behind$stashed\]]($style))' 82 | style = "cyan" 83 | stashed = "≡" 84 | ahead = "⇡${count}" 85 | behind = "⇣${count}" 86 | diverged = "⇕⇡${ahead_count}⇣${behind_count}" 87 | 88 | [custom.git_status_dirty] 89 | when = 'test -n "$(git status --porcelain 2>/dev/null)"' 90 | symbol = "•" 91 | style = "purple" 92 | format="[$symbol]($style)" 93 | shell = ["sh"] 94 | 95 | [shell] 96 | format = ' [$indicator]($style)' 97 | fish_indicator = '🐟' # 󰈺 🐟 🐠 98 | powershell_indicator = '_' 99 | pwsh_indicator = '>_' 100 | zsh_indicator = '󠀥%' 101 | bash_indicator = '󠀥\$' 102 | style = 'cyan bold' 103 | disabled = false 104 | 105 | [cmd_duration] 106 | format = ' [$duration]($style)' 107 | 108 | [line_break] 109 | disabled = true 110 | 111 | [status] 112 | disabled = false 113 | format = '[$symbol$int]($style)' 114 | symbol = '✘' 115 | # pipestatus = true 116 | # pipestatus_format = '\[$pipestatus\]($style)' 117 | -------------------------------------------------------------------------------- /.config/starship/mmc_256.toml: -------------------------------------------------------------------------------- 1 | # 2 | # mmc - My default prompt theme 3 | # 4 | 5 | add_newline = false 6 | 7 | # A minimal left prompt 8 | format = """$python$directory$character""" 9 | 10 | # Move the rest of the prompt to the right 11 | right_format = """$status$cmd_duration$git_branch${custom.git_status_dirty}$git_status$shell""" 12 | 13 | # Timeout for commands executed by starship (in milliseconds) 14 | command_timeout=2000 15 | 16 | # Set the palette. 17 | palette = "wombat_256" 18 | 19 | # Define custom colors 20 | [palettes.tokyo_night_256] 21 | black = '16' 22 | blue = '111' 23 | cyan = '117' 24 | green = '149' 25 | purple = '141' 26 | red = '210' 27 | white = '146' 28 | yellow = '179' 29 | 30 | [palettes.wombat_256] 31 | black = '0' 32 | blue = '75' 33 | cyan = '123' 34 | green = '149' 35 | purple = '171' 36 | red = '203' 37 | white = '188' 38 | yellow = '223' 39 | 40 | [character] 41 | success_symbol = "[❯](purple)[❯](cyan)" 42 | error_symbol = "[❯](yellow)[❯](red)" 43 | vicmd_symbol = "[❮](purple)[❮](cyan)" 44 | 45 | [python] 46 | format = '[(\($virtualenv\) )]($style)' 47 | style = 'white' 48 | 49 | [directory] 50 | style = "blue" 51 | truncation_length = 1 52 | truncation_symbol = "" 53 | fish_style_pwd_dir_length = 1 54 | 55 | # Right prompt uses left space padding. 56 | [git_branch] 57 | format = ' [$branch]($style)' 58 | style = 'green' 59 | 60 | [git_status] 61 | format = '( [\[$ahead_behind$stashed\]]($style))' 62 | style = "cyan" 63 | stashed = "≡" 64 | ahead = "⇡${count}" 65 | behind = "⇣${count}" 66 | diverged = "⇕⇡${ahead_count}⇣${behind_count}" 67 | 68 | [custom.git_status_dirty] 69 | when = 'test -n "$(git status --porcelain 2>/dev/null)"' 70 | symbol = "•" 71 | style = "purple" 72 | format="[$symbol]($style)" 73 | shell = ["sh"] 74 | 75 | [shell] 76 | format = ' [$indicator]($style)' 77 | fish_indicator = '🐟' # 󰈺 🐟 🐠 78 | powershell_indicator = '_' 79 | pwsh_indicator = '>_' 80 | zsh_indicator = '󠀥%' 81 | bash_indicator = '󠀥$' 82 | style = 'cyan bold' 83 | disabled = false 84 | 85 | [cmd_duration] 86 | format = ' [$duration]($style)' 87 | 88 | [line_break] 89 | disabled = true 90 | 91 | [status] 92 | disabled = false 93 | format = '[$symbol$int]($style)' 94 | symbol = '✘' 95 | # pipestatus = true 96 | # pipestatus_format = '\[$pipestatus\]($style)' 97 | -------------------------------------------------------------------------------- /.config/starship/omf.toml: -------------------------------------------------------------------------------- 1 | add_newline = false 2 | 3 | # A minimal left prompt 4 | format = """$directory$character""" 5 | 6 | # move the rest of the prompt to the right 7 | right_format = """$status$time$git_branch${custom.git_status_dirty}$git_status""" 8 | 9 | [character] 10 | success_symbol = '[⋊>](cyan)' 11 | error_symbol = '[⋊>](bold red)' 12 | vicmd_symbol = '[vi ⋊>](blue)' 13 | 14 | [directory] 15 | style = "white" 16 | truncation_length = 1 17 | truncation_symbol = "" 18 | fish_style_pwd_dir_length = 1 19 | 20 | # right prompt uses left space padding 21 | [git_branch] 22 | format = ' [$branch]($style)' 23 | style = 'bold green' 24 | 25 | [git_status] 26 | format = '[$all_status$ahead_behind]($style)' 27 | ahead = '↑' 28 | behind = '↓' 29 | stashed = '≡' 30 | modified = '⨯' 31 | diverged = '⥄' 32 | style = "purple" 33 | 34 | [time] 35 | format = '[$time]($style)' 36 | disabled = false 37 | 38 | [line_break] 39 | disabled = true 40 | 41 | [status] 42 | disabled = false 43 | symbol = ' ✘' 44 | 45 | [custom.git_status_dirty] 46 | when = 'test -n "$(git status --porcelain 2>/dev/null)"' 47 | symbol = "⨯" 48 | style = "purple" 49 | format="[$symbol]($style)" 50 | shell = ["sh"] 51 | -------------------------------------------------------------------------------- /.config/starship/powershell.toml: -------------------------------------------------------------------------------- 1 | # 2 | # mmc - mattmc3's starship config 3 | # 4 | 5 | add_newline = true 6 | 7 | # A minimal left prompt 8 | format = """$python$directory$status$cmd_duration$git_branch${custom.git_status_dirty}$git_status 9 | $character""" 10 | 11 | # Timeout for commands executed by starship (in milliseconds) 12 | command_timeout=2000 13 | 14 | # Set the color palette 15 | palette = "tokyonight" 16 | 17 | # Define custom colors 18 | [palettes.tokyonight] 19 | black = '#15161e' 20 | blue = '#7aa2f7' 21 | cyan = '#7dcfff' 22 | green = '#9ece6a' 23 | magenta = '#bb9af7' 24 | red = '#f7768e' 25 | white = '#a9b1d6' 26 | yellow = '#e0af68' 27 | pink = '#ff6ac1' 28 | 29 | [character] 30 | success_symbol = "[_](pink)" 31 | error_symbol = "[_](red)" 32 | vicmd_symbol = "[❰_](cyan)" 33 | 34 | [python] 35 | format = '[(\($virtualenv\) )]($style)' 36 | style = 'cyan' 37 | 38 | [directory] 39 | style = "blue" 40 | truncation_length = 1 41 | truncation_symbol = "" 42 | fish_style_pwd_dir_length = 1 43 | 44 | # Right-side prompt items use left space padding 45 | [git_branch] 46 | format = ' [$branch]($style)' 47 | style = 'white' 48 | 49 | [git_status] 50 | format = "[( $ahead_behind$stashed)]($style)" 51 | style = "cyan" 52 | stashed = "≡" 53 | ahead = "⇡${count}" 54 | behind = "⇣${count}" 55 | diverged = "⇕⇡${ahead_count}⇣${behind_count}" 56 | 57 | [custom.git_status_dirty] 58 | when = 'test -n "$(git status --porcelain 2>/dev/null)"' 59 | symbol = "*" # • * ﹡ * ✱ 60 | style = "purple" 61 | format="[$symbol]($style)" 62 | shell = ["sh"] 63 | 64 | [shell] 65 | fish_indicator = '🐟' # 󰈺 🐟 🐠 66 | powershell_indicator = '_' 67 | pwsh_indicator = '_' 68 | zsh_indicator = '󠀥%' 69 | style = 'cyan bold' 70 | disabled = false 71 | 72 | [cmd_duration] 73 | format = '[$duration]($style)' 74 | 75 | [line_break] 76 | disabled = true 77 | 78 | [status] 79 | disabled = false 80 | pipestatus = true 81 | format = '[$symbol$int]($style)' 82 | symbol = '✘' 83 | pipestatus_format = '\[$pipestatus\]($style)' 84 | -------------------------------------------------------------------------------- /.config/starship/prezto.toml: -------------------------------------------------------------------------------- 1 | # 2 | # prezto - mimic the default prezto prompt (sorin) 3 | # 4 | 5 | add_newline = false 6 | 7 | # A minimal left prompt 8 | format = """$python$directory$character""" 9 | 10 | # move the rest of the prompt to the right 11 | right_format = """$status$git_branch$git_status""" 12 | 13 | [character] 14 | success_symbol = "[❯](red)[❯](yellow)[❯](green)" 15 | error_symbol = "[❯](red)[❯](yellow)[❯](green)" 16 | vicmd_symbol = "[❮](green)[❮](yellow)[❮](red)" 17 | 18 | [git_branch] 19 | format = '[$branch]($style) ' 20 | style = 'bold green' 21 | 22 | [python] 23 | format = '\($virtualenv\) ' 24 | 25 | [git_status] 26 | format = '$all_status$ahead_behind ' 27 | ahead = '[⬆](bold purple) ' 28 | behind = '[⬇](bold purple) ' 29 | staged = '[✚](green) ' 30 | deleted = '[✖](red) ' 31 | renamed = '[➜](purple) ' 32 | stashed = '[✭](cyan) ' 33 | untracked = '[◼](white) ' 34 | modified = '[✱](blue) ' 35 | conflicted = '[═](yellow) ' 36 | diverged = '⇕ ' 37 | up_to_date = '' 38 | 39 | [directory] 40 | style = "blue" 41 | truncation_length = 1 42 | truncation_symbol = "" 43 | fish_style_pwd_dir_length = 1 44 | 45 | [cmd_duration] 46 | format = '[$duration]($style) ' 47 | 48 | [line_break] 49 | disabled = true 50 | 51 | [status] 52 | disabled = false 53 | symbol = '✘ ' 54 | -------------------------------------------------------------------------------- /.config/starship/pure.toml: -------------------------------------------------------------------------------- 1 | # 2 | # Refined - a Pure-like theme for Starship 3 | # 4 | 5 | format = """ 6 | $username\ 7 | $hostname\ 8 | $directory\ 9 | $git_branch\ 10 | $git_state\ 11 | ${custom.git_status_dirty}\ 12 | $git_status\ 13 | $cmd_duration\ 14 | $line_break\ 15 | $python\ 16 | $character""" 17 | 18 | [directory] 19 | style = "blue" 20 | 21 | [character] 22 | success_symbol = "[❯](purple)" 23 | error_symbol = "[❯](red)" 24 | vicmd_symbol = "[❮](cyan)" 25 | 26 | [git_branch] 27 | format = "[$branch]($style)" 28 | style = "bright-black" 29 | 30 | [git_status] 31 | format = "[($ahead_behind$stashed)]($style)" 32 | style = "cyan" 33 | stashed = "≡" 34 | 35 | [custom.git_status_dirty] 36 | when = 'test -n "$(git status --porcelain 2>/dev/null)"' 37 | symbol = "*" 38 | style = "purple" 39 | format="[$symbol]($style) " 40 | shell = ["zsh", "--no-rcs", "--no-globalrcs"] 41 | 42 | [git_state] 43 | format = '\([$state( $progress_current/$progress_total)]($style)\) ' 44 | style = "bright-black" 45 | 46 | [cmd_duration] 47 | format = "[$duration]($style) " 48 | style = "yellow" 49 | 50 | [python] 51 | format = "[$virtualenv]($style) " 52 | style = "bright-black" 53 | -------------------------------------------------------------------------------- /.config/starship/starship.toml: -------------------------------------------------------------------------------- 1 | # https://github.com/starship/starship/discussions/1908 2 | 3 | [character] 4 | success_symbol = "[❯](bold green)" 5 | error_symbol = "[✗](bold red)" 6 | vicmd_symbol = "[❮](bold green)" 7 | 8 | [status] 9 | disabled = false 10 | 11 | [shell] 12 | bash_indicator = "$" 13 | zsh_indicator = "%" 14 | xonsh_indicator = "🐚" 15 | fish_indicator = "🐟" 16 | powershell_indicator = "❯_" 17 | format = "$indicator(bold green) " 18 | disabled = false 19 | 20 | [custom.zsh] 21 | symbol = "%" 22 | when = '[ "$STARSHIP_SHELL" == "zsh" ]' 23 | shell = ["bash", "--noprofile", "--norc"] 24 | 25 | [custom.xonsh] 26 | symbol = '\(🐍 xsh\)' 27 | when = '[ "$STARSHIP_SHELL" == "xonsh" ]' 28 | shell = ["bash", "--noprofile", "--norc"] 29 | -------------------------------------------------------------------------------- /.config/starship/xonsh.toml: -------------------------------------------------------------------------------- 1 | # https://starship.rs/presets/pure-preset.html 2 | add_newline = true 3 | 4 | format = """ 5 | $username\ 6 | $hostname\ 7 | $directory\ 8 | $git_branch\ 9 | $git_state\ 10 | $git_status\ 11 | $cmd_duration\ 12 | $line_break\ 13 | $python\ 14 | $character""" 15 | 16 | [directory] 17 | style = "bold blue" 18 | repo_root_style = "blue" 19 | truncate_to_repo = false 20 | truncation_length = 0 21 | disabled = false 22 | 23 | [character] 24 | success_symbol = "[§](green)" 25 | error_symbol = "[§](red)" 26 | vicmd_symbol = "[§](purple)" 27 | 28 | [git_branch] 29 | format = "[$branch]($style)" 30 | style = "bright-black" 31 | 32 | [git_status] 33 | format = "[[(*$conflicted$untracked$modified$staged$renamed$deleted)](218) ($ahead_behind$stashed)]($style) " 34 | style = "cyan" 35 | conflicted = "​" 36 | untracked = "​" 37 | modified = "​" 38 | staged = "​" 39 | renamed = "​" 40 | deleted = "​" 41 | stashed = "≡" 42 | ahead = "⇡${count}" 43 | diverged = "⇕⇡${ahead_count}⇣${behind_count}" 44 | behind = "⇣${count}" 45 | 46 | [git_state] 47 | format = '\([$state( $progress_current/$progress_total)]($style)\) ' 48 | style = "bright-black" 49 | 50 | [cmd_duration] 51 | format = "[$duration]($style) " 52 | style = "yellow" 53 | 54 | [python] 55 | format = "[$virtualenv]($style) " 56 | style = "bright-black" 57 | 58 | [status] 59 | style = "red" 60 | format = '[\[$int\]]($style) ' 61 | disabled = false 62 | -------------------------------------------------------------------------------- /.config/starship/zebrafish.toml: -------------------------------------------------------------------------------- 1 | # Zebrafish prompt (made possible with Starship) 2 | # Copyright (c) 2021-2022 mattmc3 3 | # https://github.com/mattmc3/zebrafish 4 | # License: MIT 5 | # version v0.7.0 6 | 7 | add_newline = false 8 | 9 | [character] 10 | success_symbol = "[%%](purple)" 11 | error_symbol = "[%%](red)" 12 | vicmd_symbol = "[❮](bold green)" 13 | 14 | [directory] 15 | style = "blue" 16 | repo_root_style = "blue" 17 | truncate_to_repo = false 18 | truncation_length = 0 19 | disabled = false 20 | 21 | [cmd_duration] 22 | format = "[$duration](yellow)" 23 | 24 | [git_branch] 25 | style = "bright-black" 26 | format = "[$branch]($style)" 27 | 28 | [git_status] 29 | format = "[[(*$conflicted$untracked$modified$staged$renamed$deleted)](218) ($ahead_behind$stashed)]($style) " 30 | style = "cyan" 31 | conflicted = "​" 32 | untracked = "​" 33 | modified = "​" 34 | staged = "​" 35 | renamed = "​" 36 | deleted = "​" 37 | stashed = "≡" 38 | ahead = "⇡${count}" 39 | diverged = "⇕⇡${ahead_count}⇣${behind_count}" 40 | behind = "⇣${count}" 41 | 42 | [git_state] 43 | format = '\([$state( $progress_current/$progress_total)]($style)\) ' 44 | style = "bright-black" 45 | 46 | [status] 47 | style = "red" 48 | format = '[\[$int\]]($style) ' 49 | disabled = false 50 | -------------------------------------------------------------------------------- /.config/starship/zsh.toml: -------------------------------------------------------------------------------- 1 | add_newline = false 2 | 3 | # A minimal left prompt 4 | format = """$python$directory$character""" 5 | 6 | # move the rest of the prompt to the right 7 | #right_format = """$status$git_branch${custom.git_status_dirty}$git_status""" 8 | right_format = """$status$cmd_duration$git_branch$git_status${custom.git_status_dirty}""" 9 | 10 | # Set the palette. 11 | palette = "wombat" 12 | 13 | # Define custom colors 14 | [palettes.tokyo_night] 15 | black = '16' 16 | blue = '111' 17 | cyan = '117' 18 | green = '149' 19 | purple = '141' 20 | red = '210' 21 | white = '146' 22 | yellow = '179' 23 | 24 | [palettes.wombat] 25 | black = '0' 26 | blue = '75' 27 | cyan = '123' 28 | green = '149' 29 | purple = '171' 30 | red = '203' 31 | white = '188' 32 | yellow = '223' 33 | 34 | [character] 35 | success_symbol = "[❯](purple)[❯](cyan)" 36 | error_symbol = "[❯](yellow)[❯](red)" 37 | vicmd_symbol = "[❮](purple)[❮](cyan)" 38 | 39 | [python] 40 | format = '\($virtualenv\) ' 41 | 42 | [directory] 43 | style = "blue" 44 | truncation_length = 1 45 | truncation_symbol = "" 46 | fish_style_pwd_dir_length = 1 47 | 48 | # right prompt uses left space padding 49 | [git_branch] 50 | format = ' [$branch]($style)' 51 | style = 'green' 52 | 53 | [git_status] 54 | format = '([\[$ahead_behind$stashed\]]($style))' 55 | style = "cyan" 56 | stashed = "≡" 57 | ahead = "⇡${count}" 58 | behind = "⇣${count}" 59 | 60 | [custom.git_status_dirty] 61 | when = 'test -n "$(git status --porcelain 2>/dev/null)"' 62 | symbol = "•" 63 | style = "white" 64 | format="[$symbol]($style)" 65 | shell = ["sh"] 66 | 67 | [cmd_duration] 68 | format = ' [$duration]($style)' 69 | 70 | [line_break] 71 | disabled = true 72 | 73 | [status] 74 | disabled = false 75 | symbol = ' ✘' 76 | -------------------------------------------------------------------------------- /.config/tmux/tmux.conf: -------------------------------------------------------------------------------- 1 | # https://www.seanh.cc/2020/12/30/how-to-make-tmux's-windows-behave-like-browser-tabs 2 | 3 | set -g base-index 1 # Start numbering windows at 1, not 0. 4 | set -g pane-base-index 1 # Start numbering panes at 1, not 0. 5 | bind -n C-t new-window 6 | bind -n C-PgDn next-window 7 | bind -n C-PgUp previous-window 8 | bind -n C-S-Left swap-window -t -1\; select-window -t -1 9 | bind -n C-S-Right swap-window -t +1\; select-window -t +1 10 | bind -n M-1 select-window -t 1 11 | bind -n M-2 select-window -t 2 12 | bind -n M-3 select-window -t 3 13 | bind -n M-4 select-window -t 4 14 | bind -n M-5 select-window -t 5 15 | bind -n M-6 select-window -t 6 16 | bind -n M-7 select-window -t 7 17 | bind -n M-8 select-window -t 8 18 | bind -n M-9 select-window -t:$ 19 | bind -n C-M-w kill-window 20 | bind -n C-M-q confirm -p "Kill this tmux session?" kill-session 21 | bind -n F11 resize-pane -Z 22 | set -g mouse on 23 | 24 | set -g status-style "bg=default" 25 | set -g window-status-current-style "bg=default,reverse" 26 | set -g window-status-separator '' # No spaces between windows in the status bar. 27 | set -g window-status-format "#{?window_start_flag,, }#I:#W#{?window_flags,#F, } " 28 | set -g window-status-current-format "#{?window_start_flag,, }#I:#W#{?window_flags,#F, } " 29 | -------------------------------------------------------------------------------- /.config/vim/init.vim: -------------------------------------------------------------------------------- 1 | " 2 | " Notes: 3 | " 4 | " References 5 | " http://stevelosh.com/blog/2010/09/coming-home-to-vim/#making-vim-more-useful 6 | " https://github.com/fabi1cazenave/cua-mode.vim/blob/master/plugin/cua-mode.vim 7 | " https://github.com/tpope/vim-sensible/blob/master/plugin/sensible.vim 8 | 9 | " better defaults were introduced in vim 7, but they only load for a missing vimrc. 10 | unlet! skip_defaults_vim 11 | source $VIMRUNTIME/defaults.vim 12 | 13 | " Kickstart: 14 | source ~/.config/vim/kickstart.vim 15 | 16 | " General Settings 17 | set colorcolumn=88 " add ruler 18 | set nobackup " We have vcs, we don't need backups this way 19 | set nowritebackup " We have vcs, we don't need backups this way 20 | set noswapfile " No need for this on a modern system 21 | set autowrite " autosaving files is a nice feature 22 | set lazyredraw " don't redraw the screen on macros, or other non-typed operations 23 | set shortmess+=I " no vim welcome screen 24 | set virtualedit+=block " allow the cursor to go anywhere in visual block mode 25 | set wildmode=list:full 26 | set foldmethod=marker 27 | 28 | " https://vim.fandom.com/wiki/Disable_beeping 29 | set noerrorbells visualbell t_vb= 30 | autocmd GUIEnter * set visualbell t_vb= 31 | 32 | 33 | " Cursor 34 | " Use a line cursor within insert mode and a block cursor everywhere else. 35 | " Reference chart of values: 36 | " Ps = 0 -> blinking block. 37 | " Ps = 1 -> blinking block (default). 38 | " Ps = 2 -> steady block. 39 | " Ps = 3 -> blinking underline. 40 | " Ps = 4 -> steady underline. 41 | " Ps = 5 -> blinking bar (xterm). 42 | " Ps = 6 -> steady bar (xterm). 43 | let &t_SI = "\e[6 q" 44 | let &t_EI = "\e[2 q" 45 | 46 | " Editor 47 | 48 | set list " needed for listchars 49 | set listchars=tab:»\ ,trail:· " Display tabs and trailing spaces visually 50 | set title " Sets the terminal to show the buffer title 51 | set scrolloff=4 " when scrolling around, keep a buffer of a few lines above/below 52 | 53 | 54 | " Whitespace 55 | 56 | set expandtab " use spaces instead of tabs. 57 | set tabstop=4 " number of spaces that a tab in a file counts for 58 | set shiftwidth=4 " affects how autoindentation works 59 | set softtabstop=4 " when tab is pressed, only move to the next tab stop 60 | set shiftround " tab / shifting moves to closest tabstop. 61 | set smartindent " intelligently dedent / indent new lines based on rules. 62 | 63 | 64 | " 65 | " Key bindings 66 | " 67 | 68 | " Assign keys 69 | nnoremap ve :e $MYVIMRC 70 | nnoremap vr :source $MYVIMRC 71 | 72 | " Make U be redo. 73 | nnoremap U 74 | 75 | " Colemak 76 | " set langmap=je,JE,li,LI,nj,NJ,ek,EK,il,IL,kn,KN 77 | " Arrow with neiu, and then make H-U, J->E, K->N, and L->I. 78 | " set langmap=nh,NH,ej,EJ,il,IL,uk,UK,je,JE,li,LI,hu,HU,nh,kn,KN 79 | " Make tn get us out of insert mode because that's handy. 80 | " inoremap tn 81 | 82 | " Emacs shortcuts 83 | inoremap I 84 | nnoremap ^ 85 | inoremap A 86 | nnoremap $ 87 | inoremap Bi 88 | inoremap lWi 89 | 90 | """ CUA shortcuts 91 | " meta(alt)-left/right moves across words 92 | map B 93 | map W 94 | map { 95 | map } 96 | 97 | " inoremap E 98 | " noremap E 99 | " inoremap B 100 | " noremap B 101 | nnoremap :w 102 | nnoremap :u 103 | inoremap :u 104 | 105 | " Make search more sane 106 | set showmatch " live match highlighting 107 | set gdefault " use the `g` flag by default. 108 | " make search use normal PERL regex 109 | " nnoremap / /\v 110 | " vnoremap / /\v 111 | " This unsets the "last search pattern" register by hitting return 112 | nnoremap :noh: 113 | 114 | 115 | " Save on focus lost (breaks when unnamed) 116 | " au FocusLost * :wa 117 | 118 | " Theme 119 | " to get the font name, set it in MacVim and then run `:set guifont?` to see 120 | " the value. 121 | if has('gui_running') 122 | set guifont=HackNF-Regular:h15 123 | endif 124 | 125 | " FZF 126 | set rtp+=/usr/local/opt/fzf 127 | 128 | -------------------------------------------------------------------------------- /.config/wezterm/README.md: -------------------------------------------------------------------------------- 1 | # WezTerm 2 | 3 | WezTerm is awesome. This is a quick place to find links and reference snippets: 4 | 5 | References: 6 | - https://alexplescan.com/posts/2024/08/10/wezterm/ 7 | - https://gist.github.com/alexpls/83d7af23426c8928402d6d79e72f9401 8 | - https://news.ycombinator.com/item?id=41223934 9 | -------------------------------------------------------------------------------- /.config/wezterm/backgrounds/botw_corrupted_nydra.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattmc3/dotfiles/e7d2d7515bce6fa1cc05de3b32be44f84fc3da2a/.config/wezterm/backgrounds/botw_corrupted_nydra.jpg -------------------------------------------------------------------------------- /.config/wezterm/backgrounds/botw_corrupted_nydra2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattmc3/dotfiles/e7d2d7515bce6fa1cc05de3b32be44f84fc3da2a/.config/wezterm/backgrounds/botw_corrupted_nydra2.png -------------------------------------------------------------------------------- /.config/wezterm/backgrounds/botw_corrupted_nydra_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattmc3/dotfiles/e7d2d7515bce6fa1cc05de3b32be44f84fc3da2a/.config/wezterm/backgrounds/botw_corrupted_nydra_dark.png -------------------------------------------------------------------------------- /.config/wezterm/backgrounds/botw_corrupted_nydra_rev.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattmc3/dotfiles/e7d2d7515bce6fa1cc05de3b32be44f84fc3da2a/.config/wezterm/backgrounds/botw_corrupted_nydra_rev.jpg -------------------------------------------------------------------------------- /.config/zsh/.zshenv: -------------------------------------------------------------------------------- 1 | # Reduce key delay 2 | export KEYTIMEOUT=${KEYTIMEOUT:-1} 3 | 4 | # Make Apple Terminal behave. 5 | if [[ "$OSTYPE" == darwin* ]]; then 6 | export SHELL_SESSIONS_DISABLE=${SHELL_SESSIONS_DISABLE:-1} 7 | fi 8 | -------------------------------------------------------------------------------- /.config/zsh/conf.d/git-clone-with-cd.zsh: -------------------------------------------------------------------------------- 1 | # Enhance git clone so that it will cd into the newly cloned directory 2 | autoload -Uz add-zsh-hook 3 | typeset -g last_cloned_dir 4 | 5 | # Preexec: Detect 'git clone' command and set last_cloned_dir so we can cd into it 6 | _git_clone_preexec() { 7 | if [[ "$1" == git\ clone* ]]; then 8 | local last_arg="${1##* }" 9 | if [[ "$last_arg" =~ ^(https?|git@|ssh://|git://) ]]; then 10 | last_cloned_dir=$(basename "$last_arg" .git) 11 | else 12 | last_cloned_dir="$last_arg" 13 | fi 14 | fi 15 | } 16 | 17 | # Precmd: Runs before prompt is shown, and we can cd into our last_cloned_dir 18 | _git_clone_precmd() { 19 | if [[ -n "$last_cloned_dir" ]]; then 20 | if [[ -d "$last_cloned_dir" ]]; then 21 | echo "→ cd from $PWD to $last_cloned_dir" 22 | cd "$last_cloned_dir" 23 | fi 24 | # Reset 25 | last_cloned_dir= 26 | fi 27 | } 28 | 29 | add-zsh-hook preexec _git_clone_preexec 30 | add-zsh-hook precmd _git_clone_precmd 31 | -------------------------------------------------------------------------------- /.config/zsh/conf.d/history.zsh: -------------------------------------------------------------------------------- 1 | # History 2 | HISTFILE="${XDG_DATA_HOME:-$HOME/.local/share}/zsh/history" 3 | [ -d "${HISTFILE:h}" ] || mkdir -p "${HISTFILE:h}" 4 | 5 | ## History command configuration 6 | # OMZ settings: 7 | # setopt extended_history # record timestamp of command in HISTFILE 8 | # setopt hist_expire_dups_first # delete duplicates first when HISTFILE size exceeds HISTSIZE 9 | # setopt hist_ignore_dups # ignore duplicated commands history list 10 | # setopt hist_ignore_space # ignore commands that start with space 11 | # setopt hist_verify # show command with history expansion to user before running it 12 | # setopt share_history # share command history data 13 | 14 | # My additional settings: 15 | setopt bang_hist # Treat the '!' character specially during expansion. 16 | setopt hist_find_no_dups # Do not display a previously found event. 17 | setopt hist_ignore_all_dups # Delete an old recorded event if a new event is a duplicate. 18 | setopt hist_reduce_blanks # Remove extra blanks from commands added to the history list. 19 | setopt hist_save_no_dups # Do not write a duplicate event to the history file. 20 | setopt inc_append_history # Write to the history file immediately, not when the shell exits. 21 | setopt NO_hist_beep # Don't beep when accessing non-existent history. 22 | setopt NO_share_history # Don't share history between all sessions. 23 | 24 | # History aliases. 25 | alias hist='fc -li' 26 | alias history-stat="history 0 | awk '{print \$2}' | sort | uniq -c | sort -n -r | head" 27 | -------------------------------------------------------------------------------- /.config/zsh/conf.d/myaliases.zsh: -------------------------------------------------------------------------------- 1 | # 2 | # aliases - Zsh and bash aliases 3 | # 4 | 5 | # References 6 | # - https://medium.com/@webprolific/getting-started-with-dotfiles-43c3602fd789#.vh7hhm6th 7 | # - https://github.com/webpro/dotfiles/blob/master/system/.alias 8 | # - https://github.com/mathiasbynens/dotfiles/blob/master/.aliases 9 | # - https://github.com/ohmyzsh/ohmyzsh/blob/master/plugins/common-aliases/common-aliases.plugin.zsh 10 | # 11 | 12 | # single character shortcuts - be sparing! 13 | alias _=sudo 14 | alias l=ls 15 | alias g=git 16 | 17 | # mask built-ins with better defaults 18 | alias ping='ping -c 5' 19 | alias vi=vim 20 | alias nv=nvim 21 | alias grep="${aliases[grep]:-grep} --exclude-dir={.git,.vscode}" 22 | 23 | # directories 24 | alias secrets="cd ${XDG_DATA_HOME:-~/.local/share}/secrets" 25 | 26 | # more ways to ls 27 | alias ll='ls -lh' 28 | alias la='ls -lAh' 29 | alias lsa="ls -aG" 30 | alias ldot='ls -ld .*' 31 | 32 | # fix typos 33 | alias get=git 34 | alias quit='exit' 35 | alias cd..='cd ..' 36 | alias zz='exit' 37 | 38 | # tar 39 | alias tarls="tar -tvf" 40 | alias untar="tar -xf" 41 | 42 | # date/time 43 | alias timestamp="date '+%Y-%m-%d %H:%M:%S'" 44 | alias datestamp="date '+%Y-%m-%d'" 45 | alias isodate="date +%Y-%m-%dT%H:%M:%S%z" 46 | alias utc="date -u +%Y-%m-%dT%H:%M:%SZ" 47 | alias unixepoch="date +%s" 48 | 49 | # find 50 | # alias fd='find . -type d -name' 51 | # alias ff='find . -type f -name' 52 | 53 | # homebrew 54 | #alias brewup="brew update && brew upgrade && brew cleanup" 55 | #alias brewinfo="brew leaves | xargs brew desc --eval-all" 56 | 57 | # disk usage 58 | alias biggest='du -s ./* | sort -nr | awk '\''{print $2}'\'' | xargs du -sh' 59 | alias dux='du -x --max-depth=1 | sort -n' 60 | alias dud='du -d 1 -h' 61 | alias duf='du -sh *' 62 | 63 | # url encode/decode 64 | alias urldecode='python3 -c "import sys, urllib.parse as ul; \ 65 | print(ul.unquote_plus(sys.argv[1]))"' 66 | alias urlencode='python3 -c "import sys, urllib.parse as ul; \ 67 | print (ul.quote_plus(sys.argv[1]))"' 68 | 69 | # misc 70 | alias please=sudo 71 | alias zshrc='${EDITOR:-vim} "${ZDOTDIR:-$HOME}"/.zshrc' 72 | alias zbench='for i in {1..10}; do /usr/bin/time zsh -lic exit; done' 73 | alias cls="clear && printf '\e[3J'" 74 | 75 | # print things 76 | alias print-fpath='for fp in $fpath; do echo $fp; done; unset fp' 77 | alias print-path='echo $PATH | tr ":" "\n"' 78 | alias print-functions='print -l ${(k)functions[(I)[^_]*]} | sort' 79 | 80 | # auto-orient images based on exif tags 81 | alias autorotate="jhead -autorot" 82 | 83 | # color 84 | alias colormap='for i in {0..255}; do print -Pn "%K{$i} %k%F{$i}${(l:3::0:)i}%f " ${${(M)$((i%6)):#3}:+"\n"}; done' 85 | 86 | # dotfiles 87 | : ${DOTFILES:=$HOME/.dotfiles} 88 | alias dotf='cd "$DOTFILES"' 89 | alias dotfed='cd "$DOTFILES" && ${VISUAL:-${EDITOR:-vim}} .' 90 | alias dotfl="cd \$DOTFILES/local" 91 | alias fdot='cd ${XDG_CONFIG_HOME:-~/.config}/fish' 92 | alias fconf=fdot 93 | alias zdot='cd $ZDOTDIR' 94 | alias zcust='cd $ZSH_CUSTOM' 95 | 96 | # fonts 97 | alias fontlist="system_profiler SPFontsDataType | grep 'Full Name' | awk -F: '{print \$2}' | sed 's/^ *//g' | sort" 98 | 99 | # gpg 100 | export GNUPGHOME=${GNUPGHOME:=${XDG_DATA_HOME:-$HOME/.local/share}/gnupg} 101 | [[ -e $GNUPGHOME:h ]] || mkdir -p $GNUPGHOME:h 102 | alias gpg="${aliases[gpg]:-gpg} --homedir \"$GNUPGHOME\"" 103 | 104 | # iwd - initial working directory 105 | : ${IWD:=$PWD} 106 | alias iwd='cd $IWD' 107 | 108 | # java 109 | alias setjavahome="export JAVA_HOME=\`/usr/libexec/java_home\`" 110 | 111 | # dotnet 112 | alias dotnet8="/opt/homebrew/opt/dotnet@8/bin/dotnet" 113 | 114 | # todo-txt 115 | alias t="todo.sh" 116 | alias todos="$VISUAL $HOME/Desktop/todo.txt" 117 | 118 | # Ensure python commands exist. 119 | if (( $+commands[python3] )) && ! (( $+commands[python] )); then 120 | alias python=python3 121 | fi 122 | if (( $+commands[pip3] )) && ! (( $+commands[pip] )); then 123 | alias pip=pip3 124 | fi 125 | 126 | # Ensure envsubst command exists. 127 | if ! (( $+commands[envsubst] )); then 128 | alias envsubst="python -c 'import os,sys;[sys.stdout.write(os.path.expandvars(l)) for l in sys.stdin]'" 129 | fi 130 | 131 | # vim: ft=zsh sw=2 ts=2 et 132 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | indent_style = tab 7 | indent_size = 4 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [bin/*] 12 | indent_style = space 13 | indent_size = 2 14 | 15 | [*.json] 16 | indent_style = space 17 | indent_size = 2 18 | 19 | [.{zshrc,zprofile,zshenv,zlogin,zlogout,zstyle}] 20 | indent_style = space 21 | indent_size = 2 22 | 23 | [**/zsh/functions/*] 24 | indent_style = space 25 | indent_size = 2 26 | 27 | [**/bin/*] 28 | indent_style = space 29 | indent_size = 2 30 | 31 | [**/bin/*/*] 32 | indent_style = space 33 | indent_size = 2 34 | 35 | [.{bashrc,bash_profile}] 36 | indent_style = space 37 | indent_size = 2 38 | 39 | [*.{bash,zsh,sh}] 40 | indent_style = space 41 | indent_size = 2 42 | 43 | [*.{md,markdown}] 44 | trim_trailing_whitespace = false 45 | 46 | [*.lua] 47 | indent_style = tab 48 | indent_size = 4 49 | 50 | [*.sql] 51 | indent_style = space 52 | indent_size = 4 53 | 54 | [*.fish] 55 | indent_style = space 56 | 57 | [*.{py,xsh}] 58 | indent_style = space 59 | 60 | [*.vim] 61 | indent_style = space 62 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # use custom ignores with this command: 2 | # GIT_WORK_TREE=$HOME GIT_DIR=$HOME/.dotfiles.git git config --local core.excludesfile .gitignore.dotfiles 3 | 4 | # Ignore everything by default. 5 | 6 | * 7 | 8 | # Add back items as needed. 9 | 10 | # config 11 | !.config/ 12 | !.config/* 13 | 14 | # atuin 15 | !.config/atuin/ 16 | !.config/atuin/** 17 | 18 | # bin 19 | !bin/ 20 | !bin/** 21 | 22 | # bash 23 | !.bash_profile 24 | !.bashrc 25 | !.config/bash/ 26 | !.config/bash/** 27 | .config/bash/*.log 28 | 29 | # blesh 30 | !.config/blesh/ 31 | !.config/blesh/** 32 | 33 | # docs 34 | !docs/ 35 | !docs/** 36 | 37 | # editorconfig 38 | !~/.editorconfig 39 | 40 | # fish 41 | !.config/fish/ 42 | !.config/fish/* 43 | !.config/fish/** 44 | .config/fish/fish_variables 45 | 46 | # git 47 | !.gitignore 48 | !.config/git/ 49 | !.config/git/** 50 | 51 | # hammmerspoon 52 | !.hammerspoon/ 53 | !.hammerspoon/Spoons/** 54 | !.hammerspoon/init.lua 55 | !.hammerspoon/readme.md 56 | 57 | # helix 58 | !.config/helix/ 59 | !.config/helix/** 60 | 61 | # homebrew 62 | !.config/homebrew/ 63 | !.config/homebrew/** 64 | 65 | # iterm2 66 | !.config/iterm2/ 67 | !.config/iterm2/*.json 68 | 69 | # kak 70 | !.config/kak/ 71 | !.config/kak/** 72 | 73 | # npm 74 | !.config/npm/ 75 | !.config/npm/** 76 | 77 | # neovim 78 | !.config/nvim/ 79 | !.config/nvim/** 80 | 81 | # readline 82 | !.config/readline/ 83 | !.config/readline/** 84 | 85 | # shell 86 | !.config/shell/ 87 | !.config/shell/** 88 | 89 | # starship 90 | !.config/starship/ 91 | !.config/starship/** 92 | 93 | # stow 94 | !.stow-* 95 | 96 | # tmux 97 | !.config/tmux/ 98 | !.config/tmux/** 99 | 100 | # vim 101 | !~/.vimrc 102 | !.config/vim/ 103 | !.config/vim/*.vim 104 | 105 | # wezterm 106 | !.config/wezterm/ 107 | !.config/wezterm/** 108 | 109 | # zsh 110 | !.config/zsh/ 111 | !.config/zsh/** 112 | .config/zsh/.* 113 | .config/zsh/.*/ 114 | !.p10k.zsh 115 | !.zaliases 116 | !.zlogin 117 | !.zlogout 118 | !.zprofile 119 | !.zshenv 120 | !.zshrc 121 | !.zshrc.* 122 | !.zstyles 123 | !.zplugins 124 | !.config/zsh/.zshrc.d/ 125 | !.config/zsh/.zshrc.d/** 126 | .config/zsh/.zcompdump* 127 | .config/zsh/custom/ 128 | .config/zsh/ohmyzsh/ 129 | .config/zsh/.oh-my-zsh/ 130 | 131 | # re-ignore local files 132 | *.local 133 | local.* 134 | *.local/ 135 | *.local.* 136 | !.local/ 137 | !.local/** 138 | 139 | # helpers 140 | !makefile 141 | !LICENSE 142 | !README.md 143 | 144 | # final 145 | *_history* 146 | .DS_Store 147 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule ".local"] 2 | path = .local 3 | url = git@github.com:mattmc3/dotfiles.local 4 | branch = main 5 | -------------------------------------------------------------------------------- /.hammerspoon/Spoons/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattmc3/dotfiles/e7d2d7515bce6fa1cc05de3b32be44f84fc3da2a/.hammerspoon/Spoons/.gitkeep -------------------------------------------------------------------------------- /.hammerspoon/readme.md: -------------------------------------------------------------------------------- 1 | # Hammerspoon 2 | 3 | - https://github.com/evantravers/hammerspoon-config/blob/abc945264a4ec1830083c53079b2bfd5c4a4d23d/hyper.lua 4 | -------------------------------------------------------------------------------- /.stow-local-ignore: -------------------------------------------------------------------------------- 1 | \.DS_Store 2 | \.git 3 | \.github 4 | \.gitignore 5 | \.vscode 6 | \.stow-local-ignore 7 | docs 8 | makefile 9 | LICENSE 10 | README.md 11 | readme.md 12 | -------------------------------------------------------------------------------- /.vimrc: -------------------------------------------------------------------------------- 1 | .config/vim/init.vim -------------------------------------------------------------------------------- /.zshenv: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | export ZDOTDIR="${ZDOTDIR:-$HOME/.config/zsh}" 3 | [[ -r $ZDOTDIR/.zshenv ]] && . $ZDOTDIR/.zshenv 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020-2025 mattmc3 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # dotfiles 2 | 3 | My dotfiles 4 | 5 | ## Intro 6 | 7 | This repo is for storing my public config files, canonically called "dotfiles". Having dotfiles in a repo makes setup on a new machine just a simple `git clone` away. Some of the techniques and code are based on concepts from [this article][dotfiles-getting-started], [this article on bare repos](https://www.atlassian.com/git/tutorials/dotfiles), and the zillions of other [dotfile repos on GitHub][github-dotfiles]. 8 | 9 | ![Terminal][terminal_gif] 10 | 11 | ### Prereqs 12 | 13 | - git 14 | 15 | ## Bare repo 16 | 17 | ```zsh 18 | alias dotty='GIT_WORK_TREE=~ GIT_DIR=~/.dotfiles' 19 | alias dotfiles='git --git-dir=$HOME/.dotfiles --work-tree=$HOME' 20 | git clone --bare git@github.com:mattmc3/dotfiles $HOME/.dotfiles 21 | dotfiles checkout 22 | if [[ $? == 0 ]]; then 23 | echo "Checked out dotfiles."; 24 | else 25 | echo "Backing up pre-existing dot files."; 26 | dotfiles checkout 2>&1 | egrep "\s+\." | awk {'print $1'} | xargs -I{} mv {} .dotfiles.bak/{} 27 | fi 28 | ``` 29 | 30 | ## Edit 31 | 32 | ```zsh 33 | IDE=${VISUAL:-${EDITOR:-vim}} 34 | dotty $IDE ~ 35 | ``` 36 | 37 | ## Git submodules 38 | 39 | Run this to make .local always track the main branch. 40 | 41 | ```sh 42 | cd .local 43 | git checkout main 44 | git pull origin main # Ensure it's up to date 45 | cd .. 46 | git config -f .gitmodules submodule..local.branch main 47 | ``` 48 | 49 | Adding these configs helps with push/pull on the .local submodule. 50 | 51 | ```sh 52 | git config push.recurseSubmodules on-demand 53 | git config submodule.recurse true 54 | ``` 55 | 56 | ## Notes 57 | 58 | Certain legacy apps don't properly use .config, so anything that doesn't has a simple wrapper in `$HOME` that then sources the real files from `~/.config`. 59 | 60 | ## Resources 61 | 62 | - [Managing dotfiles with a bare git repo](https://www.atlassian.com/git/tutorials/dotfiles) 63 | - [Managing dotfiles with GNU Stow](https://venthur.de/2021-12-19-managing-dotfiles-with-stow.html) 64 | - [Using GNU Stow to Manage Symbolic Links for Your Dotfiles](https://systemcrafters.net/managing-your-dotfiles/using-gnu-stow/) 65 | 66 | [dotfiles-getting-started]: https://medium.com/@webprolific/getting-started-with-dotfiles-43c3602fd789#.vh7hhm6th 67 | [github-dotfiles]: https://dotfiles.github.io/ 68 | [homebrew]: https://brew.sh 69 | [rsync]: http://man7.org/linux/man-pages/man1/rsync.1.html 70 | [stow]: https://www.gnu.org/software/stow/ 71 | [terminal]: https://raw.githubusercontent.com/mattmc3/dotfiles/resources/images/zsh_terminal.png 72 | [terminal_gif]: https://raw.githubusercontent.com/mattmc3/dotfiles/resources/img/zdotdir.gif 73 | -------------------------------------------------------------------------------- /bin/backup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env zsh 2 | 3 | 0=${(%):-%x} 4 | rsync_file=${0:A:h}/backup.rsync 5 | 6 | BACKUP_DIR=${BACKUP_DIR:-$HOME/.bak} 7 | mkdir -p $BACKUP_DIR 8 | echo "backing up to ${BACKUP_DIR}..." 9 | rsync -aLv --include-from="$rsync_file" "$HOME/" ${BACKUP_DIR}/$(date +"%Y%m%d_%H%M%S") 10 | -------------------------------------------------------------------------------- /bin/backup.rsync: -------------------------------------------------------------------------------- 1 | # header ####################################################################### 2 | - .DS_Store 3 | - .git/ 4 | 5 | # dirs 6 | .config/ 7 | 8 | # common includes 9 | .aliases 10 | .bash_aliases 11 | 12 | # shell includes 13 | .includes/ 14 | .includes/*** 15 | 16 | # atom 17 | .atom/ 18 | .atom/*.cson 19 | .atom/*.coffee 20 | .atom/*.less 21 | .atom/*.json 22 | .config/ 23 | .config/atom/ 24 | .config/atom/*.cson 25 | .config/atom/*.coffee 26 | .config/atom/*.less 27 | .config/atom/*.json 28 | 29 | # azure-data-studio 30 | Library/ 31 | Library/Application Support/ 32 | Library/Application Support/azuredatastudio/ 33 | Library/Application Support/azuredatastudio/User/ 34 | - Library/Application Support/azuredatastudio/User/workspaceStorage/ 35 | Library/Application Support/azuredatastudio/User/*** 36 | 37 | # bin 38 | bin/ 39 | bin/*** 40 | 41 | # bash 42 | .bash_login 43 | .bash_logout 44 | .bashrc 45 | .profile 46 | .bash_profile 47 | 48 | # doom-emacs 49 | .doom.d/ 50 | .doom.d/*** 51 | .config/doom/*** 52 | 53 | # editor config 54 | .editorconfig 55 | 56 | # emacs 57 | .emacs.d/ 58 | - .emacs.d/elpa 59 | .emacs.d/*** 60 | - .config/emacs/elpa 61 | .config/emacs/*** 62 | 63 | # fish 64 | - .config/fish/fisher/ 65 | .config/fish/*** 66 | 67 | # git 68 | .gitconfig 69 | .config/git 70 | .config/git/*** 71 | 72 | # macos 73 | Library/ 74 | Library/KeyBindings/ 75 | Library/KeyBindings/DefaultKeyBinding.dict 76 | 77 | # neovim 78 | .config/nvim/ 79 | .config/nvim/*** 80 | 81 | # npm 82 | .config/npm/ 83 | .config/npm/*** 84 | 85 | # oni2 86 | .config/oni2/ 87 | .config/oni2/*** 88 | 89 | # python 90 | .config/pep8 91 | .config/pycodestyle 92 | 93 | # readline 94 | .inputrc 95 | .config/readline/ 96 | .config/readline/*** 97 | 98 | # screen 99 | .screenrc 100 | .config/screen/ 101 | .config/screen/*** 102 | 103 | # spacemacs 104 | .spacemacs 105 | .spacemacs.d/ 106 | .spacemacs.d/*** 107 | 108 | # sublime-text 109 | Library/ 110 | Library/Application Support/ 111 | Library/Application Support/Sublime Text 3/ 112 | Library/Application Support/Sublime Text 3/Packages/ 113 | Library/Application Support/Sublime Text 3/Packages/User/ 114 | Library/Application Support/Sublime Text 3/Packages/User/*** 115 | Library/Application Support/Sublime Text/ 116 | Library/Application Support/Sublime Text/Packages/ 117 | Library/Application Support/Sublime Text/Packages/User/ 118 | Library/Application Support/Sublime Text/Packages/User/*** 119 | 120 | # taskpaper 121 | Library/ 122 | Library/Application Support/ 123 | Library/Application Support/TaskPaper/ 124 | Library/Application Support/TaskPaper/Configurations/ 125 | Library/Application Support/TaskPaper/Configurations/*** 126 | Library/Application Support/TaskPaper/StyleSheets/ 127 | Library/Application Support/TaskPaper/StyleSheets/*** 128 | Library/Containers/ 129 | Library/Containers/com.hogbaysoftware.TaskPaper3/ 130 | Library/Containers/com.hogbaysoftware.TaskPaper3/Data/ 131 | Library/Containers/com.hogbaysoftware.TaskPaper3/Data/Library/ 132 | Library/Containers/com.hogbaysoftware.TaskPaper3/Data/Library/Application Support/ 133 | Library/Containers/com.hogbaysoftware.TaskPaper3/Data/Library/Application Support/TaskPaper/ 134 | Library/Containers/com.hogbaysoftware.TaskPaper3/Data/Library/Application Support/TaskPaperConfigurations/ 135 | Library/Containers/com.hogbaysoftware.TaskPaper3/Data/Library/Application Support/TaskPaperConfigurations/*** 136 | Library/Containers/com.hogbaysoftware.TaskPaper3/Data/Library/Application Support/TaskPaper/StyleSheets/ 137 | Library/Containers/com.hogbaysoftware.TaskPaper3/Data/Library/Application Support/TaskPaper/StyleSheets/*** 138 | 139 | # tmux 140 | .tmux.conf 141 | .config/tmux/ 142 | .config/tmux/*** 143 | 144 | # todo-txt 145 | .config/todo-txt/ 146 | .config/todo-txt/*** 147 | 148 | # vim 149 | .vimrc 150 | .vim/ 151 | .vim/*** 152 | 153 | # vscode 154 | Library/ 155 | Library/Application Support/ 156 | Library/Application Support/Code/ 157 | Library/Application Support/Code/User/ 158 | - Library/Application Support/Code/User/workspaceStorage/ 159 | - Library/Application Support/Code/User/globalStorage/ 160 | - Library/Application Support/Code/User/History/ 161 | - Library/Application Support/Code/User/sync/ 162 | Library/Application Support/Code/User/*** 163 | 164 | # zsh 165 | .zshenv 166 | .zprofile 167 | .zshrc 168 | .zlogin 169 | .zlogout 170 | .zsh/ 171 | .zsh/*** 172 | .config/zsh/ 173 | - .config/zsh/.antidote 174 | .config/zsh/*** 175 | 176 | # footer ####################################################################### 177 | # exclude any directories we haven't already included 178 | - */ 179 | 180 | # exclude any files we haven't explicitly included 181 | - * 182 | -------------------------------------------------------------------------------- /bin/capsmap: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | 3 | # http://homeowmorphism.com/2017/05/27/Remap-CapsLock-Backspace-Sierra 4 | # https://developer.apple.com/library/archive/technotes/tn2450/_index.html 5 | 6 | # map caps (0x39) to delete (0x2A) 7 | # hidutil property --set '{"UserKeyMapping":[{"HIDKeyboardModifierMappingSrc":0x700000039,"HIDKeyboardModifierMappingDst":0x70000002A}]}' 8 | 9 | # map caps (0x39) to F18 (0x6D) 10 | hidutil property --set '{"UserKeyMapping":[{"HIDKeyboardModifierMappingSrc":0x700000039,"HIDKeyboardModifierMappingDst":0x70000006D}]}' 11 | 12 | # hyper - right alt (0xE6) to F19 (0x6E) 13 | # hidutil property --set '{"UserKeyMapping":[{"HIDKeyboardModifierMappingSrc":0x7000000E6,"HIDKeyboardModifierMappingDst":0x70000006E}]}' 14 | -------------------------------------------------------------------------------- /bin/code: -------------------------------------------------------------------------------- 1 | /Applications/Visual Studio Code.app/Contents/Resources/app/bin/code -------------------------------------------------------------------------------- /bin/color-spaces.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # Author: Todd Larason 3 | # $XFree86: xc/programs/xterm/vttests/256colors2.pl,v 1.1 1999/07/11 08:49:54 dawes Exp $ 4 | 5 | print "256 color mode\n\n"; 6 | 7 | # display back ground colors 8 | 9 | for ($fgbg = 38; $fgbg <= 48; $fgbg +=10) { 10 | 11 | # first the system ones: 12 | print "System colors:\n"; 13 | for ($color = 0; $color < 8; $color++) { 14 | print "\x1b[${fgbg};5;${color}m::"; 15 | } 16 | print "\x1b[0m\n"; 17 | for ($color = 8; $color < 16; $color++) { 18 | print "\x1b[${fgbg};5;${color}m::"; 19 | } 20 | print "\x1b[0m\n\n"; 21 | 22 | # now the color cube 23 | print "Color cube, 6x6x6:\n"; 24 | for ($green = 0; $green < 6; $green++) { 25 | for ($red = 0; $red < 6; $red++) { 26 | for ($blue = 0; $blue < 6; $blue++) { 27 | $color = 16 + ($red * 36) + ($green * 6) + $blue; 28 | print "\x1b[${fgbg};5;${color}m::"; 29 | } 30 | print "\x1b[0m "; 31 | } 32 | print "\n"; 33 | } 34 | 35 | # now the grayscale ramp 36 | print "Grayscale ramp:\n"; 37 | for ($color = 232; $color < 256; $color++) { 38 | print "\x1b[${fgbg};5;${color}m::"; 39 | } 40 | print "\x1b[0m\n\n"; 41 | 42 | } 43 | 44 | print "Examples for the 3-byte color mode\n\n"; 45 | 46 | for ($fgbg = 38; $fgbg <= 48; $fgbg +=10) { 47 | 48 | # now the color cube 49 | print "Color cube\n"; 50 | for ($green = 0; $green < 256; $green+=51) { 51 | for ($red = 0; $red < 256; $red+=51) { 52 | for ($blue = 0; $blue < 256; $blue+=51) { 53 | print "\x1b[${fgbg};2;${red};${green};${blue}m::"; 54 | } 55 | print "\x1b[0m "; 56 | } 57 | print "\n"; 58 | } 59 | 60 | # now the grayscale ramp 61 | print "Grayscale ramp:\n"; 62 | for ($gray = 8; $gray < 256; $gray+=10) { 63 | print "\x1b[${fgbg};2;${gray};${gray};${gray}m::"; 64 | } 65 | print "\x1b[0m\n\n"; 66 | 67 | } 68 | -------------------------------------------------------------------------------- /bin/colorschemes: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # shellcheck disable=SC3043 3 | 4 | COLOR_SCHEMES_HOME="${XDG_CACHE_HOME:-$HOME/.cache}/repos/mbadolato/iterm2-color-schemes" 5 | THIS="$0" 6 | 7 | _clone_color_schemes() { 8 | local lastupdated="$COLOR_SCHEMES_HOME/.lastupdated" 9 | 10 | if [ ! -d "$COLOR_SCHEMES_HOME" ]; then 11 | echo "Cloning mbadolato/iterm2-color-schemes..." 12 | git clone --depth 1 --quiet https://github.com/mbadolato/iterm2-color-schemes "$COLOR_SCHEMES_HOME" 13 | touch "$lastupdated" 14 | elif [ "$(find "$COLOR_SCHEMES_HOME" -name ".lastupdated" -mtime +7 | wc -l)" -gt 0 ]; then 15 | echo "Updating mbadolato/iterm2-color-schemes..." 16 | git -C "$COLOR_SCHEMES_HOME" pull --quiet 17 | touch "$lastupdated" 18 | fi 19 | } 20 | 21 | _usage() { 22 | echo "colorschemes - Show color schemes from https://iterm2colorschemes.com/" 23 | echo "usage:" 24 | echo " colorschemes [-l|-d] Fuzzy find a color scheme" 25 | echo " colorschemes -p Preview color scheme" 26 | echo "flags:" 27 | echo " -l Find only light color schemes" 28 | echo " -d Find only dark color schemes" 29 | } 30 | 31 | _isdark() { 32 | local darkness 33 | # shellcheck disable=SC2046 34 | set -- $(_hex2rgb "$1") # Reset args to RGB values from hex color 35 | darkness="$(echo "0.2126 * $1 + 0.7152 * $2 + 0.0722 * $3" | bc)" 36 | test "${darkness%.*}" -le 40 37 | } 38 | 39 | _hex2rgb() { 40 | printf "ibase=16; %s\n%s\n%s\n" \ 41 | "$(printf "%s" "$1" | cut -c1-2)" \ 42 | "$(printf "%s" "$1" | cut -c3-4)" \ 43 | "$(printf "%s" "$1" | cut -c5-6)" | 44 | bc 45 | } 46 | 47 | _preview_color() { 48 | local name hex bg fg reset 49 | name="$1" 50 | hex="$2" 51 | # shellcheck disable=SC2046 52 | set -- $(_hex2rgb "$hex") # Reset args to RGB values from hex color 53 | fg="\033[38;2;${1};${2};${3}m" 54 | bg="\033[48;2;${1};${2};${3}m" 55 | reset="\033[0m" 56 | 57 | # Output colored text 58 | printf "${bg} ${reset} %12s %s rgb(%3s,%3s,%3s)" "$name" "#${hex}" "$1" "$2" "$3" 59 | printf " ${fg}%s${reset} ${bg}%s${reset}\n" foreground background 60 | } 61 | 62 | _preview() { 63 | local jsonfile filter colorfilter key 64 | jsonfile="$COLOR_SCHEMES_HOME/vhs/${1}.json" 65 | if [ ! -f "$jsonfile" ]; then 66 | echo "No preview available for '$*'." 67 | return 1 68 | fi 69 | 70 | colorfilter='ascii_upcase | sub("#"; "")' 71 | filter='to_entries.[] | select(.key != "name") | .key' 72 | for key in $(jq -r "$filter" "$jsonfile"); do 73 | _preview_color "$key" "$(jq -r ".$key | $colorfilter" "$jsonfile")" 74 | done 75 | } 76 | 77 | _list() { 78 | local jsonfile bg 79 | for jsonfile in "$COLOR_SCHEMES_HOME"/vhs/*.json; do 80 | if [ -n "$1" ]; then 81 | bg="$(jq -r '.background | ascii_upcase | sub("#"; "")' "$jsonfile")" 82 | if [ "$1" = dark ]; then 83 | _isdark "$bg" || continue 84 | elif [ "$1" = light ]; then 85 | ! _isdark "$bg" || continue 86 | fi 87 | fi 88 | 89 | jsonfile="${jsonfile##*/}" 90 | echo "${jsonfile%.*}" 91 | done 92 | } 93 | 94 | main() { 95 | local optspec opt OPTARG OPTIND jsonfile selection theme_type fzf_opts 96 | 97 | optspec=":hldp:" 98 | while getopts "$optspec" opt; do 99 | case "$opt" in 100 | h) _usage; return 0 ;; 101 | l) theme_type="light" ;; 102 | d) theme_type="dark" ;; 103 | p) _preview "${OPTARG}"; return 0 ;; 104 | ?) echo >&2 "colorschemes: Invalid option: -${OPTARG}."; exit 1 ;; 105 | esac 106 | done 107 | shift $((OPTIND-1)) 108 | 109 | # Wish I knew how to set the preview dynamically based on the theme... 110 | if [ -n "$theme_type" ]; then 111 | if [ "$theme_type" = light ]; then 112 | fzf_opts="--color=${theme_type},preview-fg:0,preview-bg:255" 113 | elif [ "$theme_type" = dark ]; then 114 | fzf_opts="--color=${theme_type},preview-fg:255,preview-bg:0" 115 | fi 116 | fi 117 | 118 | selection="$(_list "$theme_type" | fzf $fzf_opts --layout=reverse-list --preview="$THIS -p {}" --query="$*")" 119 | # shellcheck disable=SC2181 120 | if [ "$?" -eq 0 ]; then 121 | echo "Selected Theme: $selection" 122 | _preview "$selection" 123 | fi 124 | } 125 | 126 | # Pre-reqs 127 | if ! command -v jq >/dev/null 2>&1; then 128 | echo >&2 "colorschemes: Expecting 'jq'." 129 | echo >&2 "Please use your system's package manager to install (eg: brew install jq)." 130 | return 1 131 | fi 132 | _clone_color_schemes 133 | 134 | # Run colorschemes 135 | main "$@" 136 | -------------------------------------------------------------------------------- /bin/context_demo.zsh: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | 3 | function show_context() { 4 | echo "Inside function: ZSH_EVAL_CONTEXT = $ZSH_EVAL_CONTEXT" 5 | } 6 | 7 | echo "At toplevel: ZSH_EVAL_CONTEXT = $ZSH_EVAL_CONTEXT" 8 | 9 | show_context 10 | 11 | eval 'echo "Inside eval: ZSH_EVAL_CONTEXT = $ZSH_EVAL_CONTEXT"' 12 | 13 | trap 'echo "Inside trap: ZSH_EVAL_CONTEXT = $ZSH_EVAL_CONTEXT"' EXIT 14 | -------------------------------------------------------------------------------- /bin/csv2tsv: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | python3 -c "`printf '%s\n' 'import sys,csv' 'for row in csv.reader(sys.stdin):' ' print("\t".join(row))'`" 3 | -------------------------------------------------------------------------------- /bin/em: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env zsh 2 | # https://medium.com/@bobbypriambodo/blazingly-fast-spacemacs-with-persistent-server-92260f2118b7 3 | 4 | # Checks if there's a frame open 5 | emacsclient -n -e "(if (> (length (frame-list)) 1) ‘t)" 2> /dev/null | grep t &> /dev/null 6 | if [ "$?" -eq "1" ]; then 7 | emacsclient -a '' -nqc "$@" &> /dev/null 8 | else 9 | emacsclient -nq "$@" &> /dev/null 10 | fi 11 | -------------------------------------------------------------------------------- /bin/fishy/.bcrc: -------------------------------------------------------------------------------- 1 | # https://man.freebsd.org/cgi/man.cgi?query=bc&sektion=1 2 | 3 | define npr(n, r) { 4 | return perm(n, r) 5 | } 6 | 7 | define ncr(n, r) { 8 | return comb(n, r) 9 | } 10 | 11 | define fac(n) { 12 | return f(n); 13 | } 14 | 15 | define floor(x) { 16 | scale=0 17 | return x/1 18 | } 19 | 20 | define min(n, m) { 21 | if (n < m) return n; 22 | return m; 23 | } 24 | 25 | define max(n, m) { 26 | if (n < m) return (m); 27 | return n; 28 | } 29 | 30 | # vim: ft=bc 31 | -------------------------------------------------------------------------------- /bin/fishy/.bcrc2: -------------------------------------------------------------------------------- 1 | # https://man.freebsd.org/cgi/man.cgi?query=bc&sektion=1 2 | 3 | define npr(n, r) { 4 | return perm(n, r) 5 | } 6 | 7 | define ncr(n, r) { 8 | return comb(n, r) 9 | } 10 | 11 | define fac(n) { 12 | return f(n); 13 | } 14 | 15 | define floor(x) { 16 | scale=0 17 | return x/1 18 | } 19 | 20 | define min(n, m) { 21 | if (n < m) return n; 22 | return m; 23 | } 24 | 25 | define max(n, m) { 26 | if (n < m) return (m); 27 | return n; 28 | } 29 | 30 | ######################################################################################## 31 | 32 | define pi(x) { 33 | scale=x 34 | return 4*a(1) 35 | } 36 | 37 | define ceil(x,y) { 38 | scale=0 39 | if (x == x/1) return(x) 40 | return((x+1)/1) 41 | } 42 | 43 | define abs(n) { 44 | if (n<0) return -n 45 | return n 46 | } 47 | 48 | define f(n) { 49 | if (n <= 1) return (1); 50 | return (f(n-1) * n); 51 | } 52 | 53 | define min(x,y) { 54 | if (x 1 then 79 | local name = arg:sub(2,2) 80 | local spec = short_map[name] 81 | if spec then 82 | local key = not isempty(spec.long) and spec.long or spec.short 83 | if spec.takes_value then 84 | i = i + 1 85 | results[key] = args[i] 86 | else 87 | results[key] = true 88 | end 89 | else 90 | table.insert(positionals, arg) 91 | end 92 | else 93 | table.insert(positionals, arg) 94 | end 95 | i = i + 1 96 | end 97 | 98 | -- Build result table 99 | local flags = {} 100 | for _, spec in ipairs(specs) do 101 | local key = not isempty(spec.long) and spec.long or spec.short 102 | local value = results[key] 103 | if value ~= nil then 104 | if spec.long then flags[spec.long] = value end 105 | if spec.short then flags[spec.short] = value end 106 | end 107 | end 108 | 109 | return { 110 | flags = flags, 111 | positionals = positionals, 112 | specs = specs, 113 | } 114 | end 115 | 116 | -- If run as a script 117 | if debug.getinfo(1, "S").short_src == arg[0] then 118 | local ok, parsed = pcall(argparse, {...}) 119 | 120 | if not ok then 121 | local err = parsed:match(":%s(.+)$") or parsed 122 | io.stderr:write(err, "\n") 123 | os.exit(1) 124 | end 125 | 126 | -- Unset flag vars 127 | -- for var in $(compgen -v _flag_); do unset "$var"; done 128 | -- for var in ${(k)parameters}; do 129 | -- [[ $var == _flag_* ]] && unset $var 130 | -- done 131 | 132 | -- Print flag variables as shell assignments 133 | for _, spec in ipairs(parsed.specs) do 134 | local key = not isempty(spec.long) and spec.long or spec.short 135 | local value = parsed.flags[key] 136 | if value ~= nil then 137 | if spec.long then 138 | io.write("_flag_", spec.long, "=") 139 | if type(value) == "boolean" then 140 | io.write(value and "1" or "0", "\n") 141 | else 142 | io.write(string.format("%q", tostring(value)), "\n") 143 | end 144 | end 145 | if spec.short then 146 | io.write("_flag_", spec.short, "=") 147 | if type(value) == "boolean" then 148 | io.write(value and "1" or "0", "\n") 149 | else 150 | io.write(string.format("%q", tostring(value)), "\n") 151 | end 152 | end 153 | end 154 | end 155 | 156 | -- Print positionals as a set -- statement 157 | io.write("set --") 158 | for _, v in ipairs(parsed.positionals) do 159 | io.write(" ", string.format("%q", tostring(v))) 160 | end 161 | io.write("\n") 162 | end 163 | 164 | return argparse 165 | -------------------------------------------------------------------------------- /bin/fishy/contains: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Optionally, #!/usr/bin/env dash 3 | 4 | ##? contains - test if a word is present in a list 5 | 6 | # This is a pure POSIX implementation of Fish's contains utility 7 | # Fish-like contains (https://fishshell.com/docs/current/cmds/contains.html) 8 | contains() {( 9 | while getopts "i" opt; do 10 | case "$opt" in 11 | i) o_index=1 ;; 12 | *) return 1 ;; 13 | esac 14 | done 15 | shift $(( OPTIND - 1 )) 16 | 17 | if [ "$#" -eq 0 ]; then 18 | echo >&2 "contains: key not specified" 19 | return 1 20 | fi 21 | 22 | key="$1"; shift 23 | index=0 24 | for val in "$@"; do 25 | index=$(( index + 1 )) 26 | if [ "$val" = "$key" ]; then 27 | [ -n "$o_index" ] && echo $index 28 | return 0 29 | fi 30 | done 31 | return 1 32 | )} 33 | contains "$@" 34 | -------------------------------------------------------------------------------- /bin/fishy/contains.lua: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env lua 2 | 3 | local posix = require "posix" 4 | 5 | local function contains(args) 6 | local index_flag = false 7 | local needle 8 | local start = 1 9 | 10 | -- Check for -i or --index flag 11 | if args[1] == "-i" or args[1] == "--index" then 12 | index_flag = true 13 | needle = args[2] 14 | start = 3 15 | else 16 | needle = args[1] 17 | start = 2 18 | end 19 | 20 | if not needle then 21 | error({errmsg = "contains: Key not specified", errcode = 2}) 22 | end 23 | 24 | for i = start, #args do 25 | if args[i] == needle then 26 | if index_flag then 27 | return i - (index_flag and (start - 1) or 1) 28 | else 29 | return true 30 | end 31 | end 32 | end 33 | return false 34 | end 35 | 36 | -- Run command if run as a script 37 | if debug.getinfo(1, "S").short_src == arg[0] then 38 | local ok, result = pcall(contains, {...}) 39 | if not ok then 40 | io.stderr:write(result.errmsg .. "\n") 41 | os.exit(result.errcode) 42 | elseif type(result) == "number" then 43 | print(result) 44 | elseif not result then 45 | os.exit(1) 46 | end 47 | end 48 | 49 | return contains 50 | -------------------------------------------------------------------------------- /bin/fishy/count: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Optionally, #!/usr/bin/env dash 3 | 4 | ##? count - counts args 5 | 6 | REPLY="$#" 7 | 8 | # count piped/redirected input 9 | if ! [ -t 0 ]; then 10 | while IFS= read -r DATA || [ -n "$DATA" ]; do 11 | REPLY=$((REPLY + 1)) 12 | done 13 | fi 14 | printf '%s\n' $REPLY 15 | -------------------------------------------------------------------------------- /bin/fishy/math: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # shellcheck disable=SC3043 3 | 4 | SCRIPT_DIR=$(cd -- "$(dirname -- "$0")" 2>/dev/null && pwd) 5 | 6 | main() { 7 | local formula scale bcrc 8 | formula="$*" 9 | if [ "$1" = "-s" ] || [ "$1" = "--scale" ]; then 10 | shift; scale="$1"; shift 11 | formula="scale=$scale; $*" 12 | fi 13 | bcrc="$SCRIPT_DIR"/.bcrc 14 | bc -V > /dev/null 2>&1 || bcrc="$SCRIPT_DIR"/.bcrc2 15 | printf '%s\n' "$formula" | bc -l "$bcrc" 16 | } 17 | main "$@" 18 | -------------------------------------------------------------------------------- /bin/fishy/math.lua: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env lua 2 | 3 | local posix = require "posix" 4 | 5 | -- Memoization table for factorials 6 | local factorials = {} 7 | 8 | local custom_math = {} 9 | 10 | -- Custom math functions 11 | function custom_math.cosh(x) 12 | x = tonumber(x) 13 | if not x then error("math: cosh argument must be a number") end 14 | return (math.exp(x) + math.exp(-x)) / 2 15 | end 16 | 17 | function custom_math.log2(x) 18 | x = tonumber(x) 19 | if not x or x <= 0 then error("math: log2 argument must be a positive number") end 20 | return math.log(x, 2) 21 | end 22 | 23 | function custom_math.fac(n) 24 | n = tonumber(n) 25 | if not n or n < 0 or n ~= math.floor(n) then 26 | error("math: fac argument must be a non-negative integer") 27 | end 28 | if n == 0 then return 1 end 29 | if factorials[n] then return factorials[n] end 30 | local result = 1 31 | for i = 2, n do 32 | result = result * i 33 | end 34 | factorials[n] = result 35 | return result 36 | end 37 | 38 | -- Compute gcd for reducing fractions 39 | function custom_math.gcd(a, b) 40 | while b ~= 0 do 41 | a, b = b, a % b 42 | end 43 | return a 44 | end 45 | 46 | -- Compute nCr using multiplicative formula with fraction reduction 47 | function custom_math.ncr(n, r) 48 | n, r = tonumber(n), tonumber(r) 49 | if not n or not r or n < 0 or r < 0 or n ~= math.floor(n) or r ~= math.floor(r) or r > n then 50 | error("math: ncr arguments must be non-negative integers with r <= n") 51 | end 52 | if r > n - r then r = n - r end -- take advantage of symmetry 53 | local num, den = 1, 1 54 | for i = 1, r do 55 | num = num * (n - i + 1) 56 | den = den * i 57 | local g = custom_math.gcd(num, den) 58 | num = num // g 59 | den = den // g 60 | end 61 | return num 62 | end 63 | 64 | -- Compute nPr directly 65 | function custom_math.npr(n, r) 66 | n, r = tonumber(n), tonumber(r) 67 | if not n or not r or n < 0 or r < 0 or n ~= math.floor(n) or r ~= math.floor(r) or r > n then 68 | error("math: npr arguments must be non-negative integers with r <= n") 69 | end 70 | local result = 1 71 | for i = 0, r - 1 do 72 | result = result * (n - i) 73 | end 74 | return result 75 | end 76 | 77 | function custom_math.round(x) 78 | x = tonumber(x) 79 | if not x then error("math: round argument must be a number") end 80 | if x >= 0 then 81 | return math.floor(x + 0.5) 82 | else 83 | return math.ceil(x - 0.5) 84 | end 85 | end 86 | 87 | function custom_math.eval_infix(args) 88 | for i, v in ipairs(args) do 89 | local vl = tostring(v):lower() 90 | if vl == "x" then 91 | args[i] = "*" 92 | elseif vl == "pi" then 93 | args[i] = "3.141593" 94 | elseif vl == "tau" then 95 | args[i] = "6.283185" 96 | elseif vl == "e" then 97 | args[i] = "2.718282" 98 | end 99 | end 100 | 101 | -- Join args into a string 102 | local expr = table.concat(args, " ") 103 | -- Only allow numbers, operators, parentheses, and spaces for safety 104 | if expr:match("[^%de%^%+%-%*/%%%.%(%)%sE]") then 105 | error("math: invalid characters in expression") 106 | end 107 | -- Evaluate using load 108 | local f, err = load("return " .. expr) 109 | if not f then error("math: invalid expression: " .. err) end 110 | return f() 111 | end 112 | 113 | local function math_command(args) 114 | local funcname = args[1] 115 | local fn = math[funcname] or custom_math[funcname] 116 | if type(fn) == "function" then 117 | -- Convert remaining args to numbers 118 | local params = {} 119 | for i = 2, #args do 120 | local n = tonumber(args[i]) 121 | if not n then 122 | error("math: argument '" .. tostring(args[i]) .. "' is not a number") 123 | end 124 | params[#params+1] = n 125 | end 126 | return fn(table.unpack(params)) 127 | else 128 | -- Try to evaluate as infix expression 129 | return custom_math.eval_infix(args) 130 | end 131 | end 132 | 133 | if debug.getinfo(1, "S").short_src == arg[0] then 134 | local ok, result = pcall(math_command, {...}) 135 | if not ok then 136 | local err = result:match(":%s(.+)$") or result 137 | io.stderr:write(err, "\n") 138 | os.exit(1) 139 | end 140 | print(result) 141 | end 142 | 143 | return math_command 144 | -------------------------------------------------------------------------------- /bin/fishy/random.lua: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env lua 2 | 3 | local posix = require "posix" 4 | 5 | local function random(args) 6 | local min, max 7 | 8 | if #args == 0 then 9 | min, max = 0, 32767 10 | elseif #args == 1 then 11 | min, max = 0, tonumber(args[1]) 12 | elseif #args == 2 then 13 | min, max = tonumber(args[1]), tonumber(args[2]) 14 | else 15 | error({errmsg = "random: Too many arguments", errcode = 1}) 16 | end 17 | 18 | if not min or not max then 19 | error({errmsg = "random: Arguments must be numbers", errcode = 1}) 20 | end 21 | 22 | if min > max then 23 | min, max = max, min 24 | end 25 | 26 | local val = math.random(min, max) 27 | return val 28 | end 29 | 30 | -- Run command if run as a script 31 | if debug.getinfo(1, "S").short_src == arg[0] then 32 | local pid = posix.getpid("pid") 33 | local ppid = posix.getpid("ppid") 34 | local seed = os.time() + tonumber(tostring(os.clock()):reverse()) 35 | print(string.format("ppid: %s", ppid)) 36 | print(string.format("pid: %s", pid)) 37 | print(string.format("seed: %s", seed)) 38 | math.randomseed(seed + pid) 39 | 40 | local ok, result = pcall(random, {...}) 41 | if not ok then 42 | io.stderr:write(result.errmsg .. "\n") 43 | os.exit(2) 44 | else 45 | print(result) 46 | end 47 | end 48 | 49 | return random 50 | -------------------------------------------------------------------------------- /bin/fishy/string: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # shellcheck disable=SC3043 3 | 4 | SCRIPT_DIR=$(cd -- "$(dirname -- "$0")" 2>/dev/null && pwd) 5 | 6 | usage() { 7 | printf '%s\n' "NAME" 8 | printf '%s\n' " string - manipulate strings" 9 | printf '%s\n' "" 10 | printf '%s\n' "SYNOPSIS" 11 | printf '%s\n' " string collect [-a | --allow-empty] [-N | --no-trim-newlines] [STRING ...]" 12 | printf '%s\n' " string escape [-n | --no-quoted] [--style=] [STRING ...]" 13 | printf '%s\n' " string join [-q | --quiet] [-n | --no-empty] SEP [STRING ...]" 14 | printf '%s\n' " string join0 [-q | --quiet] [STRING ...]" 15 | printf '%s\n' " string length [-q | --quiet] [STRING ...]" 16 | printf '%s\n' " string lower [-q | --quiet] [STRING ...]" 17 | printf '%s\n' " string match [-a | --all] [-e | --entire] [-i | --ignore-case]" 18 | printf '%s\n' " [-g | --groups-only] [-r | --regex] [-n | --index]" 19 | printf '%s\n' " [-q | --quiet] [-v | --invert]" 20 | printf '%s\n' " PATTERN [STRING ...]" 21 | printf '%s\n' " string pad [-r | --right] [(-c | --char) CHAR] [(-w | --width) INTEGER]" 22 | printf '%s\n' " [STRING ...]" 23 | printf '%s\n' " string repeat [(-n | --count) COUNT] [(-m | --max) MAX] [-N | --no-newline]" 24 | printf '%s\n' " [-q | --quiet] [STRING ...]" 25 | printf '%s\n' " string repeat [-N | --no-newline] [-q | --quiet] COUNT [STRING ...]" 26 | printf '%s\n' " string replace [-a | --all] [-f | --filter] [-i | --ignore-case]" 27 | printf '%s\n' " [-r | --regex] [-q | --quiet] PATTERN REPLACE [STRING ...]" 28 | printf '%s\n' " string shorten [(-c | --char) CHARS] [(-m | --max) INTEGER]" 29 | printf '%s\n' " [-N | --no-newline] [-l | --left] [-q | --quiet] [STRING ...]" 30 | printf '%s\n' " string split [(-f | --fields) FIELDS] [(-m | --max) MAX] [-n | --no-empty]" 31 | printf '%s\n' " [-q | --quiet] [-r | --right] SEP [STRING ...]" 32 | printf '%s\n' " string split0 [(-f | --fields) FIELDS] [(-m | --max) MAX] [-n | --no-empty]" 33 | printf '%s\n' " [-q | --quiet] [-r | --right] [STRING ...]" 34 | printf '%s\n' " string sub [(-s | --start) START] [(-e | --end) END] [(-l | --length) LENGTH]" 35 | printf '%s\n' " [-q | --quiet] [STRING ...]" 36 | printf '%s\n' " string trim [-l | --left] [-r | --right] [(-c | --chars) CHARS]" 37 | printf '%s\n' " [-q | --quiet] [STRING ...]" 38 | printf '%s\n' " string unescape [--style=] [STRING ...]" 39 | printf '%s\n' " string upper [-q | --quiet] [STRING ...]" 40 | } 41 | 42 | string() { 43 | local strcmd 44 | 45 | # Check usage. 46 | if [ "$1" = -h ] || [ "$1" = --help ]; then 47 | usage 48 | return 0 49 | elif [ -z "$1" ]; then 50 | printf >&2 'string: missing subcommand\n' 51 | return 2 52 | fi 53 | 54 | # Run string subcommand 55 | strcmd="string-${1}" 56 | shift 57 | if [ ! -e "${SCRIPT_DIR}/${strcmd}" ]; then 58 | printf >&2 '%s\n' "string: invalid subcommand" 59 | exit 2 60 | fi 61 | "${SCRIPT_DIR}/${strcmd}" "$@" 62 | } 63 | string "$@" || exit $? 64 | -------------------------------------------------------------------------------- /bin/fishy/string-join: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # shellcheck disable=SC3043 3 | 4 | # string join [-q | --quiet] [-n | --no-empty] SEP [STRING ...] 5 | 6 | string_join() { 7 | local sep str first o_help o_quiet o_noempty o_bad o_nullsep 8 | 9 | # Parse options. 10 | while [ "$#" -gt 0 ]; do 11 | case "$1" in 12 | -h|--help) o_help=true; shift ;; 13 | -q|--quiet) o_quiet=true; shift ;; 14 | -n|--no-empty) o_noempty=true; shift ;; 15 | -0) o_nullsep=true; shift ;; 16 | --) shift; break ;; 17 | -*) o_bad="$1"; shift ;; 18 | *) break ;; 19 | esac 20 | done 21 | 22 | # Check usage. 23 | if [ -n "$o_help" ]; then 24 | printf '%s\n' "string join [-q | --quiet] [-n | --no-empty] SEP [STRING ...]" 25 | return 0 26 | elif [ -n "$o_bad" ]; then 27 | printf >&2 'string join: %s: unknown option\n' "$o_bad" 28 | return 2 29 | fi 30 | 31 | # Handle null separator differently. 32 | if [ -n "$o_nullsep" ]; then 33 | [ "$#" -eq 0 ] && return 1 34 | [ -z "$o_quiet" ] && printf '%s\0' "$@" 35 | return 0 36 | fi 37 | 38 | # Get the separator. 39 | if [ "$#" -gt 0 ]; then 40 | sep="$1" 41 | shift 42 | else 43 | printf >&2 'string join: %s\n' "missing argument" 44 | return 2 45 | fi 46 | 47 | # Return 1 if nothing was joined, or 0 if we don't want output. 48 | if [ "$#" -eq 0 ]; then 49 | return 1 50 | elif [ -n "$o_quiet" ]; then 51 | return 0 52 | fi 53 | 54 | # We have things to join and want to see output. 55 | first=1 56 | for str in "$@"; do 57 | [ "$o_noempty" = true ] && [ -z "$str" ] && continue 58 | if [ $first -eq 1 ]; then 59 | printf '%s' "$str" 60 | first=0 61 | else 62 | printf '%s%s' "$sep" "$str" 63 | fi 64 | done 65 | printf '\n' 66 | } 67 | string_join "$@" || exit $? 68 | -------------------------------------------------------------------------------- /bin/fishy/string-join0: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | SCRIPT_DIR=$(cd -- "$(dirname -- "$0")" 2>/dev/null && pwd) 4 | "$SCRIPT_DIR"/string-join -0 "$@" 5 | -------------------------------------------------------------------------------- /bin/fishy/string-length: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # shellcheck disable=SC3043 3 | 4 | # string length [-q | --quiet] [STRING ...] 5 | 6 | string_length() { 7 | local str len line exitcode o_help o_quiet 8 | 9 | # Parse options. 10 | while [ "$#" -gt 0 ]; do 11 | case "$1" in 12 | -h|--help) o_help=true; shift ;; 13 | -q|--quiet) o_quiet=true; shift ;; 14 | --) shift; break ;; 15 | -*) o_bad="$1"; shift ;; 16 | *) break ;; 17 | esac 18 | done 19 | 20 | # Check usage. 21 | if [ -n "$o_help" ]; then 22 | printf 'string length [-h | --help] [-q | --quiet] [STRING ...]\n' 23 | return 0 24 | elif [ -n "$o_bad" ]; then 25 | printf >&2 'string length: %s: unknown option\n' "$o_bad" 26 | return 2 27 | fi 28 | 29 | # Collect piped input 30 | if ! [ -t 0 ]; then 31 | while IFS= read -r line || [ -n "$line" ]; do 32 | set -- "$@" "$line" 33 | done 34 | fi 35 | 36 | # Print lengths 37 | exitcode=1 38 | for str in "$@"; do 39 | len="${#str}" 40 | [ "$len" -gt 0 ] && exitcode=0 41 | [ -z "$o_quiet" ] && printf '%s\n' "$len" 42 | done 43 | return "$exitcode" 44 | } 45 | string_length "$@" || exit $? 46 | -------------------------------------------------------------------------------- /bin/fishy/string-lower: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | SCRIPT_DIR=$(cd -- "$(dirname -- "$0")" 2>/dev/null && pwd) 4 | "$SCRIPT_DIR"/string-transform lower "$@" 5 | -------------------------------------------------------------------------------- /bin/fishy/string-transform: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # shellcheck disable=SC3043 3 | 4 | # string upper [-q | --quiet] [STRING ...] 5 | # string lower [-q | --quiet] [STRING ...] 6 | 7 | TRANSFORM="$1" 8 | case "$TRANSFORM" in 9 | lower|upper) 10 | shift 11 | break 12 | ;; 13 | *) 14 | printf >&2 'string transform: unknown transform: %s\n' "$1" 15 | exit 2 16 | ;; 17 | esac 18 | 19 | string_transform() { 20 | local str newstr line exitcode o_help o_quiet 21 | 22 | # Parse options. 23 | while [ "$#" -gt 0 ]; do 24 | case "$1" in 25 | -h|--help) o_help=true; shift ;; 26 | -q|--quiet) o_quiet=true; shift ;; 27 | --) shift; break ;; 28 | -*) o_bad="$1"; shift ;; 29 | *) break ;; 30 | esac 31 | done 32 | 33 | # Check usage. 34 | if [ -n "$o_help" ]; then 35 | printf 'string %s [-h | --help] [-q | --quiet] [STRING ...]\n' "$TRANSFORM" 36 | return 0 37 | elif [ -n "$o_bad" ]; then 38 | printf >&2 'string %s: %s: unknown option\n' "$TRANSFORM" "$o_bad" 39 | return 2 40 | fi 41 | 42 | # Collect piped input 43 | if ! [ -t 0 ]; then 44 | while IFS= read -r line || [ -n "$line" ]; do 45 | set -- "$@" "$line" 46 | done 47 | fi 48 | 49 | # Transform strings and return success only if any were transformed. 50 | exitcode=1 51 | for str in "$@"; do 52 | if [ "$TRANSFORM" = "upper" ]; then 53 | newstr="$(printf '%s\n' "$str" | tr "[:lower:]" "[:upper:]")" 54 | else 55 | newstr="$(printf '%s\n' "$str" | tr "[:upper:]" "[:lower:]")" 56 | fi 57 | [ "$str" != "$newstr" ] && exitcode=0 58 | [ -z "$o_quiet" ] && printf '%s\n' "$newstr" 59 | done 60 | return "$exitcode" 61 | } 62 | string_transform "$@" || exit $? 63 | -------------------------------------------------------------------------------- /bin/fishy/string-upper: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | SCRIPT_DIR=$(cd -- "$(dirname -- "$0")" 2>/dev/null && pwd) 4 | "$SCRIPT_DIR"/string-transform upper "$@" 5 | -------------------------------------------------------------------------------- /bin/fishy/string.lua: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env lua 2 | 3 | local cmd = nil 4 | local quiet = false 5 | local args = {} 6 | local parsing_flags = true 7 | 8 | -- Parse arguments 9 | local i = 1 10 | while i <= #arg do 11 | local a = arg[i] 12 | if parsing_flags then 13 | if a == "--" then 14 | parsing_flags = false 15 | elseif a == "-q" or a == "--quiet" then 16 | quiet = true 17 | elseif not cmd then 18 | cmd = a 19 | else 20 | table.insert(args, a) 21 | end 22 | else 23 | table.insert(args, a) 24 | end 25 | i = i + 1 26 | end 27 | 28 | if not cmd then 29 | io.stderr:write("Usage: str [-q|--quiet] [--] [strings...]\n") 30 | os.exit(1) 31 | end 32 | 33 | local function transform(line) 34 | if cmd == "upper" then 35 | return string.upper(line) 36 | elseif cmd == "lower" then 37 | return string.lower(line) 38 | else 39 | io.stderr:write("Unknown command: " .. tostring(cmd) .. "\n") 40 | os.exit(1) 41 | end 42 | end 43 | 44 | local did_transform = false 45 | 46 | if #args > 0 then 47 | for _, original in ipairs(args) do 48 | local transformed = transform(original) 49 | if not quiet then 50 | print(transformed) 51 | end 52 | if transformed ~= original then 53 | did_transform = true 54 | end 55 | end 56 | else 57 | for line in io.lines() do 58 | local transformed = transform(line) 59 | if not quiet then 60 | print(transformed) 61 | end 62 | if transformed ~= line then 63 | did_transform = true 64 | end 65 | end 66 | end 67 | 68 | if did_transform then 69 | os.exit(0) 70 | else 71 | os.exit(1) 72 | end 73 | -------------------------------------------------------------------------------- /bin/fix-bom: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | [ $# -gt 0 ] || exit 1 4 | export LANG=C LC_ALL=C 5 | 6 | # Make 'sed -i' work for both GNU and BSD 7 | sedi() { 8 | sed --version &>/dev/null && sed -i -- "$@" || sed -i "" -- "$@" 9 | } 10 | sedi '1s/^\xEF\xBB\xBF//' "$@" 11 | -------------------------------------------------------------------------------- /bin/git/git-branch-cleanup: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # shellcheck disable=SC3043 3 | 4 | ##? branch-cleanup: Remove branches no longer on remote 5 | main() { 6 | # https://stackoverflow.com/questions/7726949/remove-tracking-branches-no-longer-on-remote 7 | local defbranch 8 | defbranch="$(git symbolic-ref --short refs/remotes/origin/HEAD | sed 's|^origin/||' 2>/dev/null)" 9 | git checkout "${defbranch:-main}" >/dev/null 2>/dev/null && git fetch -p && git branch -vv | 10 | awk '/: gone]/{print $1}' | 11 | xargs git branch -d 12 | } 13 | main "$@" 14 | -------------------------------------------------------------------------------- /bin/git/git-cloner: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # shellcheck shell=sh disable=SC3043 3 | 4 | ##? cloner: A better git cloner. 5 | # - Support short user/repo form 6 | # - Default clone to ~/repos (configurable), not $PWD unless dir arg provided 7 | # - Add flags I always forget but 99% of the time want (--recurse-submodules) 8 | 9 | # Move the last arg into the $1 position and cycle the rest forward in order. 10 | # This is accomplished by cycling each arg one-by-one from the front to the back. Right 11 | # before the final move, the last arg will be the first, and the rest will be shifted 12 | # forward one (ie: 1 2 3 4 => 4 1 2 3). This will let you `set` new args, and then 13 | # `shift` the one that was in the last position, which is conveniently now $1. 14 | pop_prep() { 15 | local i 16 | i=0 17 | while [ $((i+=1)) -lt $# ]; do 18 | set -- "$@" "$1" 19 | shift 20 | done 21 | printf '%s\n' "$@" 22 | } 23 | 24 | # Take a repo and make it into the short user/repo form. 25 | to_short_repo() { 26 | [ $# -eq 1 ] || return 1 27 | local default_user 28 | default_user="$(git config mycustom.gitUser || git config user.name || whoami)" 29 | # Prepend default git user to always make 2+ fields and print user/repo form 30 | echo "${default_user}/${1}" | awk -F '[/:]' '{ print $(NF-1) "/" $NF }' 31 | } 32 | 33 | # Take a repo and determine its clone destination. 34 | to_repo_dir() { 35 | [ $# -eq 1 ] || return 1 36 | # Get the default repo dir, replacing ~ with $HOME 37 | local dir 38 | dir="$( (git config mycustom.repoPath || echo "$HOME/repos") | sed -e "s|^~|$HOME|" )" 39 | echo "${dir}/$( to_short_repo "$1" )" 40 | } 41 | 42 | # Take a repo and determine its URL. 43 | to_repo_url() { 44 | [ $# -eq 1 ] || return 1 45 | case $1 in (https://*|git@*) echo "$1"; return ;; esac 46 | 47 | local gitdomain gitprotocol repo 48 | gitdomain="$( git config mycustom.gitDomain || echo 'github.com' )" 49 | gitprotocol="$( git config mycustom.gitProtocol || echo 'https' )" 50 | repo="$( to_short_repo "$1" )" 51 | 52 | case $gitprotocol in 53 | (ssh*|git*) 54 | echo "${gitprotocol}@${gitdomain}:${repo}.git" 55 | ;; 56 | (*) 57 | echo "${gitprotocol}://${gitdomain}/${repo}" 58 | ;; 59 | esac 60 | } 61 | 62 | cloner() { 63 | if [ $# -eq 0 ]; then 64 | echo >&2 "clone: Expecting a repo argument. See 'git clone -h'." 65 | return 1 66 | fi 67 | 68 | local dir repo addflags debug 69 | 70 | # If there are multiple args, then the last arg could either be the repo, or the 71 | # optional destination path. If the latter, then pop_prep again. A final arg starting 72 | # with any of these symbols was likely intended to be a path not a repo: ~ / . $ 73 | if [ $# -gt 1 ]; then 74 | # shellcheck disable=SC2046 75 | set -- $(pop_prep "$@") 76 | case "$1" in 77 | ([./~\$]*) 78 | dir="$1" && shift 79 | # shellcheck disable=SC2046 80 | set -- $(pop_prep "$@") 81 | ;; 82 | esac 83 | fi 84 | 85 | # Ensure we have an explicit clone destination set, and pop off the repo. 86 | [ -z "$dir" ] && dir="$( to_repo_dir "$1" )" 87 | repo="$( to_repo_url "$1" )" 88 | shift 89 | 90 | # Now, reassemble the git command, add any additional flags 91 | addflags="$( git config mycustom.cloneAddFlags )" 92 | debug="$( git config mycustom.debug | tr '[:upper:]' '[:lower:]' )" 93 | case $debug in 94 | (t|true|1) 95 | echo "clone command modified to:" 96 | echo " command git clone $addflags $* $repo $dir" 97 | ;; 98 | esac 99 | command git clone "$addflags" "$@" "$repo" "$dir" 100 | } 101 | cloner "$@" 102 | -------------------------------------------------------------------------------- /bin/git/git-pushup: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # push a new branch to the remote 4 | # Quick way to resolve the annoying error: 5 | # 'fatal: The current branch foo has no upstream branch.' 6 | # Or, you could just set `push.autoSetupRemote = true` in gitconfig... 7 | git push --set-upstream "${1:-origin}" "$(git rev-parse --abbrev-ref HEAD)" 8 | -------------------------------------------------------------------------------- /bin/git/git-submodule-up: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | ##? git update-submod - if there are submodules, update them, commit, and push 3 | 4 | set -euo pipefail 5 | 6 | main() { 7 | local root_git_dir submod line num_changed behind 8 | local -a submods 9 | 10 | root_git_dir="$(git rev-parse --show-toplevel || exit 1)" 11 | cd "$root_git_dir" 12 | 13 | # Make sure the repo has submodules. 14 | if [ ! -r ".gitmodules" ]; then 15 | echo >&2 "No .gitmodules found" 16 | exit 1 17 | fi 18 | 19 | # Make sure the repo has no staged changes 20 | if ! git diff --exit-code --name-only --cached >/dev/null 2>&1; then 21 | echo >&2 "update-submod: Cannot run command with changes already staged" 22 | exit 1 23 | fi 24 | 25 | # Make sure the repo is up to date. 26 | behind="$(git rev-list --count 'HEAD..@{upstream}' 2>/dev/null)" 27 | if [[ -n "$behind" ]] && (( behind > 0 )); then 28 | echo >&2 "Your repo is $behind commits behind. Run 'git pull' before using this command." 29 | exit 1 30 | fi 31 | 32 | # What are the submodules? 33 | while IFS= read -r line; do 34 | submods+=("$line") 35 | done < <(git config --file .gitmodules --get-regexp path | awk '{ print $2 }') 36 | 37 | # Update the submodules 38 | git submodule update --remote --recursive --merge 39 | 40 | # See which submodules changed 41 | num_changed=0 42 | for submod in "${submods[@]}"; do 43 | if ! git diff --exit-code --name-only "$submod" >/dev/null 2>&1; then 44 | echo "Running: git add $submod" 45 | (( num_changed += 1 )) 46 | git add "$submod" 47 | else 48 | echo "Submodule was unchanged: $submod" 49 | fi 50 | done 51 | 52 | # Commit 53 | if (( num_changed == 0 )); then 54 | return 1 55 | elif (( num_changed == 1 )); then 56 | git commit -m "Update submodule" 57 | elif (( num_changed > 1 )); then 58 | git commit -m "Update submodules" 59 | fi 60 | 61 | # Push 62 | if (( num_changed > 0 )); then 63 | echo "Submodules updated. 'git push' when ready." 64 | fi 65 | } 66 | main "$@" 67 | -------------------------------------------------------------------------------- /bin/gitex: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # optionally, use !/usr/bin/env dash to really test POSIX 3 | ##? gitex - git extensions; useful for making git aliases that don't suck 4 | ##? usage: gitx 5 | ##? 6 | 7 | # To check, run: shellcheck -e SC3043 ~/bin/gitex 8 | 9 | # For testing... 10 | gitex_foo() { 11 | echo "foo called with $# params: $*" 12 | } 13 | 14 | # POSIX test for function existance. 15 | is_function() { 16 | [ "$#" -eq 1 ] || return 1 17 | type "$1" | sed "s/$1//" | grep -qwi function 18 | } 19 | 20 | ##? help: Display gitex help comments 21 | gitex_help() { 22 | # echo "$0" 23 | grep "^##?" "$0" | cut -c 5- 24 | } 25 | 26 | ##? branch-cleanup: Remove branches no longer on remote 27 | gitex_branch_cleanup() { 28 | # https://stackoverflow.com/questions/7726949/remove-tracking-branches-no-longer-on-remote 29 | local defbranch 30 | defbranch="$(gitex_branch_main 2>/dev/null)" 31 | git checkout "${defbranch:-main}" >/dev/null 2>/dev/null && git fetch -p && git branch -vv | 32 | awk '/: gone]/{print $1}' | 33 | xargs git branch -d 34 | } 35 | 36 | ##? branch-main: Get the name of the default branch for a repo (main, master, trunk, etc) 37 | gitex_branch_main() { 38 | # https://stackoverflow.com/questions/28666357/git-how-to-get-default-branch 39 | git symbolic-ref --short refs/remotes/origin/HEAD | sed 's|^origin/||' 40 | } 41 | 42 | ##? branch-name: Get the current branch name 43 | gitex_branch_name() { 44 | git branch --show-current 45 | } 46 | 47 | ##? browse: Open web browser to git remote URL 48 | gitex_browse() { 49 | local url 50 | url=$( 51 | git config "remote.${1:-origin}.url" | 52 | sed -e 's|^.*@|https://|' -e 's|.git$||' -e 's|:|/|2' 53 | ) 54 | git web--browse "$url" 55 | } 56 | 57 | ##? checkout-branches: Checkout and track all branches 58 | gitex_checkout_branches() { 59 | # https://stackoverflow.com/questions/67699/how-to-clone-all-remote-branches-in-git 60 | git branch -a | sed -n "/\\/HEAD /d; /\\/main$/d; /\\/master$/d; /remotes/p;" | xargs -L1 git checkout --track 61 | } 62 | 63 | ##? is-clean: Is the git repo clean 64 | gitex_is_clean() { 65 | test -z "$(git status --porcelain 2>/dev/null)" 66 | } 67 | 68 | ##? is-dirty: Is the git repo dirty 69 | gitex_is_dirty() { 70 | test -n "$(git status --porcelain 2>/dev/null)" 71 | } 72 | 73 | ##? lg: Print my preferred git log view. 74 | gitex_lg() { 75 | git log --all --decorate --oneline --graph 76 | } 77 | 78 | ##? log-pretty: Print a pretty log. 79 | gitex_log_pretty() { 80 | git log --graph --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) - %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) %C(dim white)- %an%C(reset)%C(auto)%d%C(reset)' --all 81 | } 82 | 83 | ##? pushup: Push a new branch to the remote 84 | gitex_pushup() { 85 | # Quick way to resolve the annoying error: 86 | # 'fatal: The current branch foo has no upstream branch.' 87 | # Or, you could just set `push.autoSetupRemote = true` in gitconfig... 88 | git push --set-upstream "${1:-origin}" "$(git rev-parse --abbrev-ref HEAD)" 89 | } 90 | 91 | ##? repodir: Print my preferred root repo directory. 92 | gitex_repodir() { 93 | (git config gitex.repodir || echo "$HOME/repos") | sed -e "s|^~|$HOME|" 94 | } 95 | 96 | ##? sha: Print the 7-char short git SHA, with a * indicating dirty. 97 | gitex_sha() { 98 | printf '%s' "$(git rev-parse --short HEAD)" 99 | gitex_is_dirty && echo '*' || echo 100 | } 101 | 102 | ##? whoami: Print my config's username and email. 103 | gitex_whoami() { 104 | git config user.name && git config user.email 105 | } 106 | 107 | # main gitex command 108 | gitex() { 109 | if [ "$#" -eq 0 ]; then 110 | echo >&2 "gitex: expecting a subcommand." 111 | return 1 112 | fi 113 | 114 | local subcmd="$1" 115 | if [ "$subcmd" = "-h" ] || [ "$subcmd" = "--help" ]; then 116 | # Support -h/--help flags 117 | subcmd="help" 118 | else 119 | # Make kebab-case-subcommands work. 120 | subcmd=$(printf '%s' "$subcmd" | tr '-' '_') 121 | fi 122 | 123 | # Call the subcommand if it exists. 124 | if is_function "gitex_${subcmd}"; then 125 | shift 126 | "gitex_${subcmd}" "$@" 127 | else 128 | echo >&2 "gitex: subcommand not found '$subcmd'." 129 | return 1 130 | fi 131 | } 132 | gitex "$@" 133 | 134 | # vim: set sw=2 sts=2 ts=8 et: 135 | -------------------------------------------------------------------------------- /bin/hello.zsh: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | 3 | function hello() { 4 | echo "hello ${1:-world}" 5 | } 6 | 7 | # Only run if NOT sourced 8 | if [[ $ZSH_EVAL_CONTEXT != *:file ]]; then 9 | hello "$@" 10 | fi 11 | echo $ZSH_EVAL_CONTEXT 12 | -------------------------------------------------------------------------------- /bin/linkify: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | sed -E 's#(/[^\(]+)\(([0-9]+),([0-9]+)\):#file:///\1:\2:\3 :#g' 3 | -------------------------------------------------------------------------------- /bin/macopts.zsh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env zsh 2 | 3 | # dotfiles references 4 | # https://github.com/pawelgrzybek/dotfiles/blob/master/setup-macos.sh 5 | # https://github.com/mathiasbynens/dotfiles/blob/master/.macos 6 | # https://github.com/geerlingguy/dotfiles/blob/master/.osx 7 | 8 | 9 | # --- General --- 10 | # install xcode command line tools 11 | xcode-select --install 12 | 13 | # rosetta 2 for intel chipset apps on the M1 14 | softwareupdate --install-rosetta --agree-to-license 15 | 16 | 17 | # --- Symlinks --- 18 | # sublime 19 | ln -s /Applications/Sublime\ Text.app/Contents/SharedSupport/bin/subl ~/bin 20 | 21 | # vscode 22 | ln -s /Applications/Visual\ Studio\ Code.app/Contents/Resources/app/bin/code ~/bin 23 | 24 | 25 | # --- Dock --- 26 | # https://developer.apple.com/documentation/devicemanagement/dock 27 | 28 | # System Preferences > Dock > Magnification: 29 | defaults write com.apple.dock magnification -bool true 30 | 31 | # Minimize windows into their application’s icon 32 | defaults write com.apple.dock minimize-to-application -bool true 33 | 34 | # Change minimize/maximize window effect from genie to scale 35 | defaults write com.apple.dock mineffect -string "scale" 36 | 37 | # move to left 38 | defaults write com.apple.dock orientation left 39 | 40 | 41 | # --- Keyboard --- 42 | # Disable press-and-hold for keys in favor of key repeat 43 | defaults write NSGlobalDomain ApplePressAndHoldEnabled -bool false 44 | 45 | # Or, do this for individual apps 46 | # defaults write com.sublimetext.3 ApplePressAndHoldEnabled -bool false 47 | # defaults write com.microsoft.VSCode ApplePressAndHoldEnabled -bool false 48 | 49 | # if you need to reset back to default 50 | # defaults delete -g ApplePressAndHoldEnabled 51 | 52 | defaults write -g InitialKeyRepeat -int 10 # normal minimum is 15 (225 ms) 53 | defaults write -g KeyRepeat -int 1 # normal minimum is 2 (30 ms) 54 | 55 | 56 | # --- Folders --- 57 | # Save screenshots to the downloads 58 | mkdir -p "$HOME/Screenshots" 59 | defaults write com.apple.screencapture location -string "$HOME/Screenshots" 60 | 61 | 62 | # --- Desktop & Screen Saver --- 63 | # Hot corners 64 | # Possible values: 65 | # 0: no-op 66 | # 2: Mission Control 67 | # 3: Show application windows 68 | # 4: Desktop 69 | # 5: Start screen saver 70 | # 6: Disable screen saver 71 | # 7: Dashboard 72 | # 10: Put display to sleep 73 | # 11: Launchpad 74 | # 12: Notification Center 75 | defaults write com.apple.dock wvous-br-corner -int 5 76 | defaults write com.apple.dock wvous-br-modifier -int 0 77 | 78 | 79 | # --- Misc --- 80 | # why does Mojave font rendering suck on external monitors? FixedIt! 81 | defaults write -g CGFontRenderingFontSmoothingDisabled -bool NO 82 | 83 | 84 | # --- Finder Preferences --- 85 | # Finder > View > Show Path Bar 86 | defaults write com.apple.finder ShowPathbar -bool true 87 | 88 | 89 | # --- Accessibility --- 90 | # Accessibility > Display > Cursor : Increase pointer size 91 | sudo defaults write com.apple.universalaccess mouseDriverCursorSize 1.8 92 | 93 | 94 | # --- Security & Privacy 95 | # Turn Firewall on 96 | sudo defaults write /Library/Preferences/com.apple.alf globalstate -int 1 97 | 98 | 99 | # --- Restart affected apps --- 100 | 101 | for app in \ 102 | "Activity Monitor" \ 103 | "Address Book" \ 104 | "Calendar" \ 105 | "cfprefsd" \ 106 | "Contacts" \ 107 | "Dock" \ 108 | "Finder" \ 109 | "Mail" \ 110 | "Messages" \ 111 | "Photos" \ 112 | "Safari" \ 113 | "SystemUIServer" \ 114 | "Terminal" \ 115 | "iCal"; do 116 | killall "${app}" &> /dev/null 117 | done 118 | echo "Done. Note that some of these changes require a logout/restart to take effect." 119 | -------------------------------------------------------------------------------- /bin/new_mac_config: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | 3 | # https://github.com/mathiasbynens/dotfiles/blob/main/.macos 4 | 5 | setopt extended_glob interactive_comments 6 | 7 | # 8 | # Menu bar 9 | # 10 | 11 | # Show volume in menu bar 12 | defaults write com.apple.systemuiserver.plist NSStatusItem\ Visible\ com.apple.menuextra.volume -bool true 13 | defaults write com.apple.systemuiserver.plist menuExtras -array-add "/System/Library/CoreServices/Menu Extras/Volume.menu" 14 | defaults write com.apple.systemuiserver.plist menuExtras -array-add "/System/Library/CoreServices/Menu Extras/Bluetooth.menu" 15 | 16 | killall SystemUIServer 17 | 18 | # 19 | # Trackpad 20 | # 21 | 22 | # App Expose 3 finger swipe??? 23 | 24 | # 25 | # Safari 26 | # 27 | 28 | defaults write com.apple.Safari HomePage -string "about:blank" 29 | 30 | #killall cfprefsd 31 | 32 | # 33 | # Restore apps 34 | # 35 | 36 | # Stop reopening apps on restart 37 | defaults write com.apple.loginwindow TALLogoutSavesState -bool false 38 | defaults write com.apple.loginwindow LoginwindowLaunchesRelaunchApps -bool false 39 | 40 | # 41 | # Dock 42 | # 43 | 44 | # https://developer.apple.com/documentation/devicemanagement/dock 45 | # System Preferences > Dock > Magnification: 46 | defaults write com.apple.dock magnification -bool true 47 | 48 | # Magnification large size 49 | defaults write com.apple.dock largesize -int 50 50 | 51 | # Minimize windows into their application’s icon 52 | defaults write com.apple.dock minimize-to-application -bool true 53 | 54 | # Change minimize/maximize window effect from genie to scale 55 | defaults write com.apple.dock mineffect -string scale 56 | 57 | # move to left 58 | defaults write com.apple.dock orientation left 59 | 60 | # Don't keep a spot for recent apps 61 | defaults write com.apple.dock show-recents -bool false 62 | 63 | # Remove icons from doc 64 | # clear items 65 | defaults write com.apple.dock persistent-apps -array 66 | defaults write com.apple.dock persistent-others -array 67 | 68 | # add back items 69 | dockapps=( 70 | Safari 71 | Music 72 | "Microsoft Outlook" 73 | Calendar 74 | Messages 75 | Notes 76 | Terminal 77 | "Visual Studio Code" 78 | ) 79 | for dockitem in $dockapps; do 80 | dockitem_path=( 81 | /System/Cryptexes/App/System/Applications/${dockitem}.app(N) 82 | {/System,}/Applications{/Utilities,}/${dockitem}.app(N) 83 | ) 84 | dockitem=$dockitem_path[1] 85 | [ -n "$dockitem" ] || continue 86 | defaults write com.apple.dock persistent-apps -array-add 'tile-datafile-data_CFURLString'$dockitem'_CFURLStringType0' 87 | done 88 | 89 | # Reset dock 90 | #killall Dock 91 | 92 | # 93 | # Finder 94 | # 95 | 96 | # Keep folders on top when sorting by name 97 | defaults write com.apple.finder _FXSortFoldersFirst -bool true 98 | 99 | # 100 | # Keyboard 101 | # 102 | 103 | # Use key repeat for press-and-hold 104 | # macOS handles pressing-and-holding of keys differently than I'd like. 105 | # Instead of the default, let's change it to repeat the key being pressed. 106 | 107 | # Disable press-and-hold for keys in favor of key repeat 108 | defaults write -g ApplePressAndHoldEnabled -bool false 109 | 110 | # Or, do this for individual apps 111 | #defaults write com.sublimetext.4 ApplePressAndHoldEnabled -bool false 112 | #defaults write com.microsoft.VSCode ApplePressAndHoldEnabled -bool false 113 | 114 | # If you need to reset back to default: 115 | # defaults delete -g ApplePressAndHoldEnabled 116 | 117 | # Speed of key Repeat/Delay 118 | defaults write -g InitialKeyRepeat -int 25 # normal minimum is 15 (225 ms) 119 | defaults write -g KeyRepeat -int 2 # normal minimum is 2 (30 ms) 120 | 121 | # 122 | # Mouse 123 | # 124 | 125 | # Accessibility > Display > Cursor : Increase pointer size 126 | sudo defaults write com.apple.universalaccess mouseDriverCursorSize 1.8 127 | 128 | # 129 | # Security & Privacy 130 | # 131 | 132 | # Turn Firewall on 133 | # sudo defaults write /Library/Preferences/com.apple.alf globalstate -int 1 134 | 135 | # 136 | # Screenshots 137 | # 138 | 139 | mkdir -p "$HOME/Screenshots" 140 | defaults write com.apple.screencapture location -string "$HOME/Screenshots" 141 | 142 | # 143 | # Screen Saver 144 | # 145 | 146 | # 0: no-op 147 | # 2: Mission Control 148 | # 3: Show application windows 149 | # 4: Desktop 150 | # 5: Start screen saver 151 | # 6: Disable screen saver 152 | # 7: Dashboard 153 | # 10: Put display to sleep 154 | # 11: Launchpad 155 | # 12: Notification Center 156 | 157 | # bottom right corner starts screen saver 158 | defaults write com.apple.dock wvous-br-corner -int 5 159 | defaults write com.apple.dock wvous-br-modifier -int 0 160 | 161 | # 162 | # Restart 163 | # 164 | 165 | macapps=( 166 | "Activity Monitor" 167 | "Address Book" 168 | Calendar 169 | cfprefsd 170 | Contacts 171 | Dock 172 | Finder 173 | Mail 174 | Messages 175 | Photos 176 | Safari 177 | SystemUIServer 178 | Terminal 179 | iCal 180 | ) 181 | for app in $macapps; do 182 | killall $app &>/dev/null 183 | done 184 | -------------------------------------------------------------------------------- /bin/new_mac_secrets: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | 3 | setopt extended_glob interactive_comments 4 | 5 | # ssh 6 | echo "make a new ssh key..." 7 | echo "ssh-keygen -t ed25519 -C "your_email@example.com"" 8 | echo "pbcopy < ~/.ssh/github_mattmc3.pub" 9 | echo "---------" 10 | 11 | # hostname 12 | echo "Set host name?" 13 | echo "sudo scutil --set ComputerName" 14 | echo "sudo scutil --set HostName" 15 | 16 | # gpg 17 | : ${GNUPGHOME:=~/.local/share/gnupg} 18 | if [[ ! -d $GNUPGHOME ]]; then 19 | mkdir -p $GNUPGHOME 20 | chmod 700 $GNUPGHOME 21 | fi 22 | 23 | command gpg --homedir "$GNUPGHOME" --full-generate-key 24 | -------------------------------------------------------------------------------- /bin/new_mac_setup: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | 3 | : ${HOMEBREW_PREFIX:=/opt/homebrew} 4 | : ${DOTFILES:=~/.config/dotfiles} 5 | 6 | # xdg 7 | export XDG_CONFIG_HOME=~/.config 8 | export XDG_CACHE_HOME=~/.cache 9 | export XDG_DATA_HOME=~/.local/share 10 | for _zdir in XDG_{CONFIG,CACHE,DATA}_HOME; mkdir -p ${(P)_zdir} 11 | 12 | # brew 13 | if [[ -d $HOMEBREW_PREFIX ]]; then 14 | eval "$($HOMEBREW_PREFIX/bin/brew shellenv)" 15 | else 16 | /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" 17 | 18 | eval "$($HOMEBREW_PREFIX/bin/brew shellenv)" 19 | 20 | # brew bundle 21 | # brew bundle dump --force --file=$DOTFILES/home/Brewfile 22 | brew bundle --file=$DOTFILES/config/homebrew/init.brewfile 23 | fi 24 | 25 | # install dotfiles repo 26 | if [[ ! -d $DOTFILES ]]; then 27 | git clone https://github.com/mattmc3/dotfiles $DOTFILES 28 | fi 29 | 30 | # stow 31 | cd $DOTFILES 32 | make stow 33 | 34 | # cleanup 35 | unset _zdir 36 | -------------------------------------------------------------------------------- /bin/otp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env fish 2 | 3 | function gpg 4 | set --local gpg_home $GNUPGHOME 5 | if not set -q GNUPGHOME 6 | set -q XDG_DATA_HOME 7 | and set gpg_home $XDG_DATA_HOME/gnupg 8 | or set gpg_home $HOME/.local/share/gnupg 9 | end 10 | command gpg --homedir $gpg_home $argv 11 | end 12 | 13 | function otp --description 'One-time passwords' 14 | # Set homes 15 | set --local secrets_home $SECRETS_HOME 16 | if not set -q SECRETS_HOME 17 | set -q XDG_DATA_HOME 18 | and set secrets_home $XDG_DATA_HOME/secrets 19 | or set secrets_home $HOME/.local/share/secrets 20 | end 21 | set --local otp_home $secrets_home/otp 22 | 23 | # requirements 24 | if not type -q oathtool 25 | echo >&2 "otp: 'oathtool' not found. Install oathtool or oath-toolkit, depending on your OS." 26 | return 1 27 | end 28 | if not type -q gpg 29 | echo >&2 "otp: 'gpg' not found. Install, and create a key with 'gpg --gen-key' if you don't already have one." 30 | return 1 31 | end 32 | 33 | # Set public key IDs 34 | set --local gpg_keys 35 | for pubkey in $secrets_home/pubkeys/*.asc 36 | set --append gpg_keys (gpg --show-keys --with-colons $pubkey | awk -F':' '/^pub/{print $5}') 37 | end 38 | 39 | # declare vars 40 | set --local usage "usage: otp [-h | --help] [-l | --list] [-a | --add] [-r | --remove] [--rekey] " 41 | set --local recipients 42 | for key in $gpg_keys 43 | set --append recipients --recipient $key 44 | end 45 | 46 | # parse arguments 47 | argparse --name=otp h/help l/list a/add r/remove rekey -- $argv 48 | or return 1 49 | 50 | if test -n "$_flag_help" 51 | echo "otp [OPTIONS] []" 52 | echo "flags:" 53 | echo " -h, --help Show help" 54 | echo " -l, --list List keys" 55 | echo " --rekey Rebuild encrypted OTPs" 56 | echo " -a, --add Add " 57 | echo " -r, --remove Remove " 58 | return 0 59 | else if test -n "$_flag_list" 60 | # list 61 | set --local files $otp_home/*.otp.asc 62 | if test (count $files) -eq 0 63 | echo >&2 "otp: No one-time password keys found." 64 | return 1 65 | end 66 | for file in $files 67 | path basename $file | string replace '.otp.asc' '' 68 | end 69 | return 70 | else if test -n "$_flag_rekey" 71 | # rekey 72 | set --local totpkey 73 | for file in $otp_home/*.otp.asc 74 | set totpkey (gpg --quiet --decrypt $file) 75 | echo $totpkey | gpg $recipients --armor --encrypt --output $file.new 76 | if test $status = 0 77 | mv -f $file.new $file 78 | else 79 | rm -f $file.new 80 | return 1 81 | end 82 | end 83 | else if test (count $argv) -eq 0 84 | echo >&2 "otp: Expecting argument." 85 | echo >&2 $usage 86 | return 1 87 | else if test -n "$_flag_add" 88 | read -s -l otp_secret --prompt-str="Enter the otp secret for '$argv': " 89 | command rm -f $otp_home/$argv.otp.asc 90 | echo $otp_secret | gpg $recipients --armor --encrypt --output $otp_home/$argv.otp.asc 91 | otp $argv 92 | else if not test -e $otp_home/$argv.otp.asc 93 | echo >&2 "otp: Key not found '$argv'." 94 | return 1 95 | else if test -n "$_flag_remove" 96 | command rm -f $otp_home/$argv.otp.asc 97 | else 98 | set --local totpkey (gpg $recipients --quiet --decrypt $otp_home/$argv.otp.asc) 99 | if type -q pbcopy 100 | oathtool --totp --b $totpkey | tee /dev/stderr | pbcopy 101 | else 102 | oathtool --totp --b $totpkey 103 | end 104 | end 105 | end 106 | otp $argv 107 | -------------------------------------------------------------------------------- /bin/palette: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env zsh 2 | 3 | for i in {0..255}; do 4 | print -Pn "%K{$i} %k%F{$i}${(l:3::0:)i}%f " ${${(M)$((i%6)):#3}:+$'\n'} 5 | done 6 | -------------------------------------------------------------------------------- /bin/pkgmgr: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | app_exists() { 4 | type $1 > /dev/null 2>&1 5 | return $? 6 | } 7 | 8 | ensure_fn_exists() { 9 | declare -f -F $1 > /dev/null 10 | return $? 11 | } 12 | 13 | gem_export() { 14 | gem list --local 15 | } 16 | 17 | gem_import() { 18 | awk '{ print $1 }' "$1" | xargs gem install --conservative 19 | } 20 | 21 | brew_export() { 22 | # brew is a pain... it dumps to a forced Brewfile, and is not consistently 23 | # sorted, making version controling your Brewfile tricky. #FixedIt 24 | brew update > /dev/null 25 | brew bundle dump --force 26 | brewfile="Brewfile" 27 | brewfile_tmp="Brewfile.tmp" 28 | grep '^tap\ ' "$brewfile" | sort > "$brewfile_tmp" 29 | grep '^brew\ ' "$brewfile" | sort >> "$brewfile_tmp" 30 | grep '^cask\ ' "$brewfile" | sort >> "$brewfile_tmp" 31 | grep '^mas\ ' "$brewfile" | sort >> "$brewfile_tmp" 32 | cat "$brewfile_tmp" 33 | rm "$brewfile_tmp" "$brewfile" 34 | } 35 | 36 | brew_import() { 37 | brew bundle --file="$1" 38 | } 39 | 40 | macosapps_import() { 41 | echo "No good way currently to import macos apps" 42 | } 43 | 44 | macosapps_export() { 45 | # get a list of the mac apps installed. Apps are really directories, so 46 | # don't descend into it. 47 | find /Applications -type d -not \( -path '*.app/*' -prune \) -name '*.app' | cut -d'/' -f3- | sort -f 48 | } 49 | 50 | pip_export() { 51 | pip$1 freeze 52 | } 53 | 54 | pip_import() { 55 | pip$2 install -r "$1" 56 | } 57 | 58 | npm_export() { 59 | npm ls -g --depth=0 60 | } 61 | 62 | npm_import() { 63 | awk 'NR>1{ print $2 }' "$1" | awk -F'@' '{ print $1 }' | xargs npm install -g 64 | } 65 | 66 | code_export() { 67 | code --list-extensions 68 | } 69 | 70 | code_import() { 71 | cat "$1" | xargs -L 1 code --install-extension 72 | } 73 | 74 | azuredatastudio_export() { 75 | azuredatastudio --list-extensions 76 | } 77 | 78 | usage() { 79 | echo "pkgmgr" 80 | echo "Export/Import package lists for various utilities" 81 | echo "" 82 | echo "Usage:" 83 | echo " pkgmgr import " 84 | echo " pkgmgr export " 85 | echo " pkgmrg list" 86 | echo " pkgmrg help" 87 | } 88 | 89 | main() { 90 | local cmd="$1" 91 | 92 | if [[ "$cmd" == "" ]]; then 93 | echo "Error: expecting command" >&2 94 | usage && exit 1 95 | fi 96 | 97 | if [[ "$cmd" == "help" ]]; then 98 | usage && exit 0 99 | fi 100 | 101 | if [[ "$cmd" == "list" ]]; then 102 | echo "azuredatastudio" 103 | echo "brew" 104 | echo "code" 105 | echo "gem" 106 | echo "macosapps" 107 | echo "npm" 108 | echo "pip" 109 | exit 0 110 | fi 111 | 112 | if [[ $cmd != "import" ]] && [[ $cmd != "export" ]]; then 113 | echo "Error: unexpected command: $cmd" >&2 114 | usage && exit 1 115 | fi 116 | 117 | local app="$2" 118 | if [[ "$app" == "" ]]; then 119 | echo "Error: expecting app" >&2 120 | usage && exit 1 121 | fi 122 | 123 | # pip2/3 support... 124 | local subargs= 125 | if [[ "$app" == pip* ]]; then 126 | subargs=${app##*pip} 127 | app=pip 128 | fi 129 | 130 | applist=( azuredatastudio brew code gem npm pip ) 131 | if [[ " ${applist[@]} " =~ " ${app} " ]]; then 132 | app_exists "$app" || { 133 | echo "Cannot find app $app" >&2 134 | exit 1 135 | } 136 | fi 137 | 138 | if [[ $cmd == "import" ]]; then 139 | filepath="$3" 140 | [[ -f "$filepath" ]] || { 141 | echo "import packages file not found: $filepath" >&2 142 | exit 1 143 | } 144 | ${app}_import "$filepath" $subargs 145 | else 146 | ${app}_export $subargs 147 | fi 148 | } 149 | main $@ 150 | -------------------------------------------------------------------------------- /bin/pocket2ffbookmarks: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # pocket2firefox_with_tags 4 | # Converts Pocket JSON to a Firefox-compatible HTML bookmarks file with tags. 5 | # 6 | 7 | INPUT_FILE="pocket.json" 8 | OUTPUT_FILE="bookmarks.html" 9 | 10 | # Check if the input file exists 11 | if [ ! -f "$INPUT_FILE" ]; then 12 | echo "Error: Input file '$INPUT_FILE' does not exist." 13 | exit 1 14 | fi 15 | 16 | echo "[+] Converting '$INPUT_FILE' to Firefox bookmarks file '$OUTPUT_FILE'..." 17 | 18 | # Generate HTML with tags 19 | jq -r ' 20 | def escape_html: 21 | gsub("&"; "&") | gsub("<"; "<") | gsub(">"; ">") | gsub("\""; """); 22 | 23 | [ 24 | .[] | { 25 | title: (if .resolved_title != null then .resolved_title else (if .given_title != null then .given_title else "Untitled" end) end) | escape_html, 26 | url: (if .resolved_url != null then .resolved_url else .given_url end), 27 | time_added: (if .time_added != null then (.time_added | tonumber | strftime("%Y-%m-%d %H:%M:%S")) else "Unknown Date" end), 28 | tags: (if .tags != null then (.tags | keys_unsorted | join(", ")) else "" end) 29 | } 30 | ] 31 | | "\n" + 32 | "\n" + 33 | "Bookmarks\n" + 34 | "

Bookmarks

\n" + 35 | "

\n" + 36 | (map("

\(.title)") | join("\n")) + 37 | "\n

" 38 | ' "$INPUT_FILE" > "$OUTPUT_FILE" 39 | 40 | if [ $? -eq 0 ]; then 41 | echo "[+] Firefox bookmarks file created successfully: $OUTPUT_FILE" 42 | else 43 | echo "[-] Error: Failed to create Firefox bookmarks file." 44 | exit 1 45 | fi 46 | -------------------------------------------------------------------------------- /bin/pocketdownload: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # 4 | # pocket2csv_with_paging 5 | # Adds paging to download all Pocket bookmarks. 6 | # 7 | 8 | read -r -d '' LOGO <<'EOF' 9 | ... _ _ ___ 10 | | | | | |__ \ 11 | _ __ ___ ___ | | __ ___ | |_ ) | ___ ___ __ __ 12 | | '_ \ / _ \ / __|| |/ // _ \| __| / / / __|/ __|\ \ / / 13 | | |_) || (_) || (__ | <| __/| |_ / /_| (__ \__ \ \ V / 14 | | .__/ \___/ \___||_|\_\\___| \__||____|\___||___/ \_/ 15 | | | 16 | |_| 17 | ... 18 | 19 | EOF 20 | echo "" 21 | echo "$LOGO" 22 | echo "" 23 | echo "" 24 | 25 | ## read -p '[1] Enter Your Pocket API Consumer Key: ' CONSUMER_KEY 26 | # Pocket API credentials 27 | CONSUMER_KEY="113484-c20eb68369f61b62ea28588" 28 | ## ACCESS_TOKEN="c776ede4-04a6-5e4d-7c61-e532b9&username=mattmc3%40gmail.com" 29 | 30 | read -r -d '' MY_DATA < "$OUTPUT_FILE" 79 | 80 | # Fetch bookmarks in pages 81 | OFFSET=0 82 | PAGE_SIZE=100 83 | echo "[+] Starting download of all Pocket bookmarks..." 84 | 85 | while true; do 86 | read -r -d '' MY_DATA < tmp.json && mv tmp.json "$OUTPUT_FILE" 119 | 120 | # Increment offset for the next page 121 | OFFSET=$((OFFSET + PAGE_SIZE)) 122 | done 123 | 124 | echo "[+] All bookmarks downloaded and saved to $OUTPUT_FILE." 125 | -------------------------------------------------------------------------------- /bin/prj: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # shellcheck disable=SC3043 3 | 4 | ##? prj - project jumper 5 | SCRIPT_PATH="$(realpath "$0")" 6 | 7 | # Check dependencies 8 | check_dependencies() { 9 | if ! command -v fzf >/dev/null; then 10 | echo "fzf command not found" >&2 11 | exit 1 12 | elif ! command -v fd >/dev/null; then 13 | echo "fd command not found" >&2 14 | exit 1 15 | fi 16 | } 17 | 18 | # Print usage information 19 | print_usage() { 20 | echo "prj: The project jumper" 21 | echo "usage: prj [-h] [-i ] []" 22 | } 23 | 24 | # Initialize sh/bash/zsh 25 | init_sh() { 26 | cat <&2 106 | exit 2 107 | ;; 108 | esac 109 | fi 110 | 111 | # Handle tilde expansion 112 | case "$PROJECT_DIR" in 113 | ~*) PROJECT_DIR="$HOME${PROJECT_DIR#~}" ;; 114 | esac 115 | 116 | # Check project directory exists 117 | if [ ! -d "$PROJECT_DIR" ]; then 118 | echo >&2 "prj: Project home directory not found '$PROJECT_DIR'" 119 | exit 1 120 | fi 121 | 122 | # Find and select project 123 | selection=$( 124 | fd --type d --hidden --max-depth 5 '\.git$' "$PROJECT_DIR" | 125 | sed -e "s|^$PROJECT_DIR/||" -e "s|/.git/$||" | 126 | sort -u | 127 | fzf --layout=reverse-list --query="$query" 128 | ) 129 | 130 | # Output the selected project directory 131 | if [ -n "$selection" ] && [ -d "$PROJECT_DIR/$selection" ]; then 132 | echo "$PROJECT_DIR/$selection" 133 | fi 134 | } 135 | 136 | # Run the script 137 | main "$@" 138 | -------------------------------------------------------------------------------- /bin/reference/emacs-plus.sh: -------------------------------------------------------------------------------- 1 | brew install emacs-plus@27 --without-spacemacs-icon 2 | ln -s /usr/local/opt/emacs-plus@27/Emacs.app /Applications 3 | -------------------------------------------------------------------------------- /bin/reference/git-fix-email.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # https://help.github.com/articles/changing-author-info/ 4 | 5 | # export GITFIX_OLD_EMAIL="foo@bar.com" 6 | # export GITFIX_NEW_EMAIL="foobar@baz.com" 7 | # export GITFIX_OLD_NAME="Namey Name" 8 | # export GITFIX_NEW_NAME="New Namey" 9 | 10 | git filter-branch --env-filter ' 11 | if [ "$GIT_COMMITTER_EMAIL" = "$GITFIX_OLD_EMAIL" ] 12 | then 13 | export GIT_COMMITTER_NAME="$GITFIX_NEW_NAME" 14 | export GIT_COMMITTER_EMAIL="$GITFIX_NEW_EMAIL" 15 | fi 16 | if [ "$GIT_AUTHOR_EMAIL" = "$GITFIX_OLD_EMAIL" ] 17 | then 18 | export GIT_AUTHOR_NAME="$GITFIX_NEW_NAME" 19 | export GIT_AUTHOR_EMAIL="$GITFIX_NEW_EMAIL" 20 | fi 21 | ' --tag-name-filter cat -- --branches --tags 22 | -------------------------------------------------------------------------------- /bin/repo: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env zsh 2 | ##? repo - Deal with git repos 3 | 4 | : ${REPO_HOME:=${XDG_CACHE_HOME:-$HOME/.cache}/repos} 5 | 6 | function __repo_help { 7 | echo "repo - Deal with git repos" 8 | echo "" 9 | echo "commands:" 10 | echo " help print this help" 11 | echo " home print repo home" 12 | echo " ls print repo list" 13 | echo " rm remove repo" 14 | echo " in install repo" 15 | echo " up update repos" 16 | echo "" 17 | echo "examples:" 18 | echo " repo in $newsha)" 28 | fi 29 | } 30 | 31 | function __repo_clone { 32 | local repo=$1 33 | local repodir=$REPO_HOME/$repo 34 | if [ -d $repodir ]; then 35 | echo "Found $repo..." 36 | return 37 | fi 38 | 39 | echo "Cloning $repo..." 40 | command git clone --quiet --depth 1 --recursive --shallow-submodules \ 41 | https://github.com/$repo $repodir 42 | 43 | local init=$repodir/${repo:t}.plugin.zsh 44 | if [[ ! -e $init ]]; then 45 | local -a initfiles=($repodir/*.{plugin.zsh,zsh-theme,zsh,sh}(N)) 46 | (( $#initfiles )) && ln -sf $initfiles[1] $init 47 | fi 48 | if [[ $repo == sorin-ionescu/prezto ]]; then 49 | for init in $repodir/modules/*/init.zsh; do 50 | ln -sf $init $init:h/${init:h:t}.plugin.zsh 51 | done 52 | fi 53 | echo "Cloned $repo." 54 | } 55 | 56 | function __repo { 57 | emulate -L zsh 58 | setopt local_options extended_glob no_monitor 59 | 60 | if [ "$#" -eq 0 ]; then 61 | __repo_help 62 | return 1 63 | fi 64 | 65 | local repo err=1 66 | local cmd=$1; shift 67 | 68 | # piped/redirected input 69 | if ! [ -t 0 ]; then 70 | local -a args=($@) 71 | local data 72 | while IFS= read -r data || [ -n "$data" ]; do 73 | data=${data%\#*} 74 | args+=($data) 75 | done 76 | set -- $args 77 | fi 78 | 79 | case "$cmd" in 80 | help|-h|--help) 81 | __repo_help 82 | ;; 83 | home) 84 | echo $REPO_HOME 85 | ;; 86 | ls|list) 87 | err=1 88 | for repo in $REPO_HOME/*/*/.git(/N); do 89 | echo ${repo:h:h:t}/${repo:h:t} 90 | err=0 91 | done 92 | return $err 93 | ;; 94 | up|update) 95 | echo "Checking for updates..." 96 | for repo in $(repo ls); do 97 | echo "$repo..." 98 | __repo_update $repo & 99 | done 100 | wait 101 | echo "Updates complete." 102 | ;; 103 | in|install) 104 | for repo in $@; do 105 | __repo_clone $repo & 106 | done 107 | wait 108 | ;; 109 | rm|del) 110 | local err=0 111 | for repo in $@; do 112 | if ! [[ "$REPO_HOME" =~ $HOME/* ]]; then 113 | echo >&2 "repo: \$REPO_HOME not set correctly '$REPO_HOME'." 114 | return 2 115 | elif ! [[ -d $REPO_HOME/$repo ]]; then 116 | echo "Repo not found '$repo'." 117 | err=1 118 | else 119 | command rm -rf -- $REPO_HOME/$repo 120 | fi 121 | done 122 | return $err 123 | ;; 124 | *) 125 | echo >&2 "repo: Unknown command '"$cmd"'" 126 | return 1 127 | ;; 128 | esac 129 | } 130 | __repo "$@" 131 | -------------------------------------------------------------------------------- /bin/subl_wait.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # https://gist.github.com/jpalmieri/ab767f81d2ee8bce3e7d 4 | subl -w -n $* 5 | -------------------------------------------------------------------------------- /bin/trash: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | ##? trash - Move a specified file to the trash 3 | 4 | if (( $# == 0 )); then 5 | echo >&2 "Usage: trash " 6 | return 1 7 | fi 8 | 9 | if [[ $OSTYPE != darwin* ]]; then 10 | echo >&2 "trash: macOS not detected." 11 | return 1 12 | fi 13 | 14 | local file files 15 | for file in $@; do 16 | if [[ -e $file ]]; then 17 | files+=("the POSIX file \"${file:A}\"") 18 | else 19 | echo >&2 "trash: No such file or directory '$file'." 20 | return 1 21 | fi 22 | done 23 | 24 | if (( $#files == 0 )); then 25 | echo >&2 'usage: trash ' 26 | return 64 # match rm's return code 27 | fi 28 | 29 | osascript 2>&1 >/dev/null -e "tell app \"Finder\" to move { "${(pj., .)files}" } to trash" 30 | 31 | # vim: ft=zsh sw=2 ts=2 et 32 | -------------------------------------------------------------------------------- /bin/upallthethings: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # homebrew 4 | brew update && brew upgrade && brew cleanup 5 | 6 | # python 7 | pip2 list --outdated | cut -d ' ' -f1 | xargs -n1 pip2 install -U 8 | pip3 list --outdated | cut -d ' ' -f1 | xargs -n1 pip3 install -U 9 | 10 | # node 11 | # https://docs.npmjs.com/getting-started/updating-global-packages 12 | npm update -g 13 | 14 | # ruby 15 | gem update 16 | gem cleanup 17 | -------------------------------------------------------------------------------- /bin/whichos: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | case "$OSTYPE" in 4 | solaris*) echo SOLARIS ;; 5 | darwin*) echo MACOS ;; 6 | linux*) echo LINUX ;; 7 | bsd*) echo BSD ;; 8 | msys*) echo WINDOWS ;; 9 | *) echo $OSTYPE ;; 10 | esac 11 | -------------------------------------------------------------------------------- /docs/emacs.md: -------------------------------------------------------------------------------- 1 | # Emacs 2 | 3 | ## Install 4 | 5 | ### Emacs Mac Port 6 | 7 | * [Emacs Mac port](https://github.com/railwaycat/homebrew-emacsmacport) 8 | 9 | ```sh 10 | brew tap railwaycat/emacsmacport 11 | brew install emacs-mac --with-native-comp --with-emacs-big-sur-icon --with-starter 12 | ``` 13 | 14 | Install in `/Applications`: 15 | 16 | ```sh 17 | osascript -e 'tell application "Finder" to make alias file to POSIX file "/opt/homebrew/opt/emacs-mac/Emacs.app" at POSIX file "/Applications"' 18 | ``` 19 | 20 | ## Prelude 21 | 22 | ```zsh 23 | export PRELUDE_INSTALL_DIR="$HOME/.config/emacs" && curl -L https://github.com/bbatsov/prelude/raw/master/utils/installer.sh | sh 24 | ``` 25 | 26 | ```zsh 27 | # Fixes for GPG signature errors 28 | EMACS_GPG_DIR=~/.config/emacs/elpa/gnupg 29 | mkdir -p $EMACS_GPG_DIR 30 | gpg --homedir $EMACS_GPG_DIR --list-keys 31 | chmod 700 $EMACS_GPG_DIR 32 | chmod 600 $EMACS_GPG_DIR/* 33 | ``` 34 | -------------------------------------------------------------------------------- /docs/git.md: -------------------------------------------------------------------------------- 1 | # git 2 | 3 | Reference for common stuff I never remember in git 4 | 5 | ## Fix a commit 6 | 7 | ### Accidental local commit 8 | 9 | Undo previous local commit: 10 | 11 | ```zsh 12 | git reset --soft HEAD~1 13 | ``` 14 | 15 | ## submodules 16 | 17 | ### add a submodule 18 | 19 | ```zsh 20 | cd $DOTFILES 21 | git submodule add git@github.com:mattmc3/zdotdir.git ./config/zsh 22 | git submodule add git@github.com:mattmc3/fishconf.git ./config/fish 23 | ``` 24 | 25 | ### update submodules 26 | 27 | ```zsh 28 | git submodule update --recursive --remote 29 | ``` 30 | 31 | ### remove submodules 32 | 33 | ```zsh 34 | # https://stackoverflow.com/a/36593218/8314 35 | local submodule="$1" 36 | if [[ ! -n "$submodule" || ! -d "$submodule" ]]; then 37 | >&2 echo "FAIL: No valid submodule specified" 38 | return 1 39 | fi 40 | 41 | # Remove the submodule entry from .git/config 42 | git submodule deinit -f "$submodule" 43 | 44 | # Remove the submodule directory from the superproject's .git/modules directory 45 | rm -rf ".git/modules/${submodule}" 46 | 47 | # Remove the entry in .gitmodules and remove the submodule directory located at path/to/submodule 48 | git rm -f "$submodule" 49 | ``` 50 | 51 | ## machine specific config 52 | 53 | config example: 54 | 55 | ``` 56 | # home machine 57 | [includeIf "gitdir:~/.dotfiles"] 58 | path = config_home.local 59 | # work machine 60 | [includeIf "gitdir:~/Projects/work/**"] 61 | path = config_work.local 62 | 63 | [alias] 64 | config-home = ! git config user.name "My Internet Name" && git config user.email "email@home.com" 65 | config-work = ! git config user.name "My Domain Name" && git config user.email "email@work.com" 66 | ``` 67 | 68 | config_home.local example: 69 | 70 | ``` 71 | [user] 72 | name = My Internet Name 73 | email = email@home.com 74 | ``` 75 | 76 | config_work.local example: 77 | 78 | ``` 79 | [user] 80 | name = My Domain Name 81 | email = email@work.com 82 | ``` 83 | 84 | ## branches 85 | 86 | Prune branches 87 | 88 | ```zsh 89 | local curbranch=$(git rev-parse --abbrev-ref HEAD) 90 | if [[ $curbranch != 'master' ]] || [[ $curbranch != 'main' ]]; then 91 | >&2 echo "This command requires you to be on the main branch." 92 | >&2 echo "please run: git checkout main" 93 | return 1 94 | fi 95 | git fetch -p && git branch -vv | awk '/: gone]/{print \$1}' | xargs git branch -d 96 | ``` 97 | 98 | ## Resources 99 | 100 | * [Detached HEAD](https://stackoverflow.com/questions/18770545/why-is-my-git-submodule-head-detached-from-master) 101 | -------------------------------------------------------------------------------- /docs/macos.md: -------------------------------------------------------------------------------- 1 | # macOS 2 | 3 | ## DefaultKeyBinding.dict 4 | 5 | ``` 6 | /* ~/Library/KeyBindings/DefaultKeyBinding.Dict 7 | 8 | https://gist.githubusercontent.com/trusktr/1e5e516df4e8032cbc3d/raw/ab7c868a8354219782b37971f984564c66a53d78/DefaultKeyBinding.dict 9 | 10 | This file remaps the key bindings of a single user on Mac OS X 10.5 to more 11 | closely match default behavior on Windows systems. This makes the Command key 12 | behave like Windows Control key. To use Control instead of Command, either swap 13 | Control and Command in Apple->System Preferences->Keyboard->Modifier Keys... 14 | or replace @ with ^ in this file. 15 | 16 | Here is a rough cheatsheet for syntax. 17 | Key Modifiers 18 | ^ : Ctrl 19 | $ : Shift 20 | ~ : Option (Alt) 21 | @ : Command (Apple) 22 | # : Numeric Keypad 23 | 24 | Non-Printable Key Codes 25 | 26 | Standard 27 | Up Arrow: \UF700 Backspace: \U0008 F1: \UF704 28 | Down Arrow: \UF701 Tab: \U0009 F2: \UF705 29 | Left Arrow: \UF702 Escape: \U001B F3: \UF706 30 | Right Arrow: \UF703 Enter: \U000A ... 31 | Insert: \UF727 Page Up: \UF72C 32 | Delete: \UF728 Page Down: \UF72D 33 | Home: \UF729 Print Screen: \UF72E 34 | End: \UF72B Scroll Lock: \UF72F 35 | Break: \UF732 Pause: \UF730 36 | SysReq: \UF731 Menu: \UF735 37 | Help: \UF746 38 | 39 | OS X 40 | delete: \U007F 41 | 42 | For a good reference see http://osxnotes.net/keybindings.html. 43 | 44 | NOTE: typically the Windows 'Insert' key is mapped to what Macs call 'Help'. 45 | Regular Mac keyboards don't even have the Insert key, but provide 'Fn' instead, 46 | which is completely different. 47 | */ 48 | 49 | { 50 | "@\UF72B" = "moveToEndOfDocument:"; /* Cmd + End */ 51 | "@\UF729" = "moveToBeginningOfDocument:"; /* Cmd + Home */ 52 | 53 | "\UF729" = "moveToBeginningOfLine:"; /* Home */ 54 | "\UF72B" = "moveToEndOfLine:"; /* End */ 55 | 56 | "$\UF729" = "moveToBeginningOfLineAndModifySelection:"; /* Shift + Home */ 57 | "$\UF72B" = "moveToEndOfLineAndModifySelection:"; /* Shift + End */ 58 | } 59 | ``` 60 | -------------------------------------------------------------------------------- /docs/readme.md: -------------------------------------------------------------------------------- 1 | # dotfiles 2 | 3 | My dotfiles 4 | 5 | ## Intro 6 | 7 | This repo is for storing my public config files, canonically called "dotfiles". Having dotfiles in a repo makes setup on a new machine just a simple `git clone` away. Some of the techniques and code are based on concepts from [this article][dotfiles-getting-started], [this article on bare repos](https://www.atlassian.com/git/tutorials/dotfiles), and the zillions of other [dotfile repos on GitHub][github-dotfiles]. 8 | 9 | ![Terminal][terminal_gif] 10 | 11 | ### Prereqs 12 | 13 | - git 14 | 15 | ## Bare repo 16 | 17 | ```zsh 18 | alias dotf='GIT_WORK_TREE=~ GIT_DIR=~/.dotfiles' 19 | alias dotfiles='git --git-dir=$HOME/.dotfiles --work-tree=$HOME' 20 | git clone --bare git@github.com:mattmc3/dotfiles $HOME/.dotfiles 21 | dotfiles checkout 22 | if [[ $? == 0 ]]; then 23 | echo "Checked out dotfiles."; 24 | else 25 | echo "Backing up pre-existing dot files."; 26 | dotfiles checkout 2>&1 | egrep "\s+\." | awk {'print $1'} | xargs -I{} mv {} .dotfiles.bak/{} 27 | fi 28 | ``` 29 | 30 | Local 31 | 32 | ```zsh 33 | alias dotloc='git --git-dir=$HOME/.dotfiles/.local --work-tree=$HOME' 34 | git clone --bare git@github.com:mattmc3/dotfiles.local $HOME/.dotfiles/.local 35 | dotloc checkout 36 | if [[ $? == 0 ]]; then 37 | echo "Checked out dotfiles."; 38 | else 39 | echo "Backing up pre-existing dot files."; 40 | dotloc checkout 2>&1 | egrep "\s+\." | awk {'print $1'} | xargs -I{} mv {} .dotfiles.local.bak/{} 41 | fi 42 | ``` 43 | 44 | ## Edit 45 | 46 | ```zsh 47 | alias dotty="GIT_WORK_TREE=~ GIT_DIR=~/.dotfiles" 48 | IDE=${VISUAL:-${EDITOR:-vim}} 49 | dotty $IDE ~ 50 | ``` 51 | 52 | ## Notes 53 | 54 | Certain legacy apps don't properly use .config, so anything that doesn't has a simple wrapper in `$HOME` that then sources the real files from `~/.config`. 55 | 56 | ## Resources 57 | 58 | - [Managing dotfiles with a bare git repo](https://www.atlassian.com/git/tutorials/dotfiles) 59 | - [Managing dotfiles with GNU Stow](https://venthur.de/2021-12-19-managing-dotfiles-with-stow.html) 60 | - [Using GNU Stow to Manage Symbolic Links for Your Dotfiles](https://systemcrafters.net/managing-your-dotfiles/using-gnu-stow/) 61 | 62 | [dotfiles-getting-started]: https://medium.com/@webprolific/getting-started-with-dotfiles-43c3602fd789#.vh7hhm6th 63 | [github-dotfiles]: https://dotfiles.github.io/ 64 | [homebrew]: https://brew.sh 65 | [rsync]: http://man7.org/linux/man-pages/man1/rsync.1.html 66 | [stow]: https://www.gnu.org/software/stow/ 67 | [terminal]: https://raw.githubusercontent.com/mattmc3/dotfiles/resources/images/zsh_terminal.png 68 | [terminal_gif]: https://raw.githubusercontent.com/mattmc3/dotfiles/resources/img/zdotdir.gif 69 | -------------------------------------------------------------------------------- /docs/taskpaper.md: -------------------------------------------------------------------------------- 1 | # TaskPaper 2 | 3 | Mac App config location: 4 | ~/Library/Containers/com.hogbaysoftware.TaskPaper3/Data/Library/Application Support/TaskPaper 5 | Brew Cask App config location: 6 | ~/Library/Application Support/TaskPaper 7 | -------------------------------------------------------------------------------- /docs/vim.md: -------------------------------------------------------------------------------- 1 | # vim 2 | 3 | ## Colemak 4 | 5 | One of the tricky elements of using Colemak is the vim arrow movements (HJKL) 6 | are positional instead of mnemonic, and those positions change from QWERTY. 7 | 8 | There are a few approaches that I can take to address this: 9 | 10 | 1. Ignore it and leave everything as-is 11 | 1. Minimally change it to make it tolerable 12 | 1. Change it entirely to make it sane. With a subtype of doing it in such a way 13 | that it's also okay to use in QWERTY mode in case I ever have to flip back. 14 | 15 | ### Ignore it 16 | 17 | This blog post(https://sermoa.wordpress.com/2011/12/16/colemak-and-vim-but-what-about-hjkl/) 18 | is a good advocacy for leaving the default nav of hjkl. 19 | 20 | ```vim 21 | " ^ 22 | " k Hint: The `h`{normal} key is at the left and moves left. 23 | " < h l > The `l`{normal} key is at the right and moves right. 24 | " j The `j`{normal} key looks like a down arrow. 25 | " v 26 | ``` 27 | 28 | ### Minimally change keys 29 | 30 | J is north of K in Colemak which makes it feel like a flight simulator. To fix 31 | this to at least make the keys positionally make sense, do the following: 32 | 33 | Right side QWERTY: 34 | 35 | ```text 36 | Y U I O P 37 | -H- -J- -K- -L- ; 38 | N M , . / 39 | ``` 40 | 41 | Right side Colemak: 42 | 43 | ```text 44 | -J- -L- U Y ; 45 | -H- N E I O 46 | -K- M , . / 47 | ``` 48 | 49 | .vimrc 50 | 51 | ```vim 52 | " ↑ 53 | " h 54 | " ← j l → 55 | " k 56 | " ↓ 57 | 58 | set langmap=jh,kj,hk 59 | ``` 60 | 61 | ### Change entirely 62 | 63 | One option is to mix QWERTY and Colemak positional 64 | 65 | ```vim 66 | " Remap for Colemak based on https://github.com/ohjames/colemak/blob/master/vimrc 67 | " rotate some keys about to get qwerty "hjkl" back for movement 68 | noremap n j 69 | noremap e k 70 | noremap i l 71 | 72 | " move these keys to their qwerty positions because they are 73 | " in the way of hjkl (and E for J) 74 | noremap k n 75 | noremap K N 76 | noremap u i 77 | noremap U I 78 | noremap l u 79 | noremap L U 80 | noremap N J 81 | noremap E K 82 | noremap I L 83 | 84 | " this is the only key that isn't in qwerty or colemak position 85 | noremap j e 86 | noremap J E 87 | ``` 88 | 89 | Another option is NEST: 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | ```vim 98 | " ↑ 99 | " e 100 | " ← s t → 101 | " n 102 | " ↓ 103 | noremap n j|noremap n j|noremap j 104 | noremap e k|noremap e k|noremap k 105 | noremap s h 106 | noremap t l 107 | 108 | noremap f e 109 | noremap k n 110 | noremap K N 111 | ``` 112 | 113 | Or, change NEST to mean (n)orth, (e)ast, (s)outh, wes(t): 114 | 115 | ```vim 116 | " ↑ 117 | " n 118 | " ← w e → 119 | " s 120 | " ↓ 121 | noremap n k|noremap n k|noremap k 122 | noremap e l 123 | noremap s j|noremap s j|noremap j 124 | noremap t h 125 | 126 | noremap f e 127 | noremap k n 128 | noremap K N 129 | ``` 130 | -------------------------------------------------------------------------------- /docs/xdg.md: -------------------------------------------------------------------------------- 1 | # XDG 2 | 3 | - [XDG app support][xdg-app-support]: App settings for XDG support 4 | 5 | [xdg-app-support]: https://wiki.archlinux.org/index.php/XDG_Base_Directory 6 | [xdg-basedirs]: https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html 7 | -------------------------------------------------------------------------------- /docs/zsh/completions.md: -------------------------------------------------------------------------------- 1 | # Completions 2 | 3 | Add user contributed completions to this directory. 4 | 5 | Read more about how Zsh completions work in this [how-to][1] article. 6 | 7 | 8 | [1]: https://github.com/zsh-users/zsh-completions/blob/master/zsh-completions-howto.org 9 | -------------------------------------------------------------------------------- /docs/zsh/readme.md: -------------------------------------------------------------------------------- 1 | # Zsh reference 2 | 3 | I can't always remember all the Zsh goodies, so here's all the wonderful stuff I have 4 | learned and references to things other's have provided. 5 | 6 | ## Bare Zsh 7 | 8 | Zsh can be run without RCs using the following command: 9 | 10 | ```zsh 11 | zsh -dfi 12 | ``` 13 | 14 | When run this way, be careful - all exported environment variables are still set. 15 | 16 | If you want to run a totally clean environment, you can with with `env -i`. 17 | 18 | ``` 19 | env -i zsh -dfi 20 | ``` 21 | 22 | ## $0 23 | 24 | `${BASH_SOURCE[0]` is `${(%):-%x}}` in Zsh 25 | 26 | For example: 27 | 28 | ```zsh 29 | # $ZDOTDIR/functions/foo 30 | #functon foo { 31 | 32 | # prints foo 33 | echo $0 34 | 35 | # prints $ZDOTDIR/functions/foo 36 | echo ${(%):-%x} 37 | 38 | #} 39 | ``` 40 | 41 | From `man zshmisc`: 42 | 43 | ```text 44 | %N The name of the script, sourced file, or shell function that zsh is currently executing, 45 | whichever was started most recently. If there is none, this is equivalent to the parameter 46 | $0. An integer may follow the '%' to specify a number of trailing path components to show; 47 | zero means the full path. A negative integer specifies leading components. 48 | 49 | %x The name of the file containing the source code currently being executed. This behaves as %N 50 | except that function and eval command names are not shown, instead the file where they were 51 | defined. 52 | ``` 53 | 54 | - [See here](https://stackoverflow.com/questions/9901210/bash-source0-equivalent-in-zsh) 55 | - or run `man zshmisc`. 56 | 57 | ## String functions 58 | 59 | If you want to replace '~' with '$HOME' in a variable, you can do this: 60 | 61 | ```zsh 62 | mydir='~/path/to/my/dir' 63 | mydir=${mydir:s/~/$HOME} 64 | echo $mydir 65 | ``` 66 | 67 | ## Globbing 68 | 69 | [Glob qualifiers][zsh-glob-qualifiers] are options tacked onto a wildcard pattern that 70 | filter or modify the match. Some examples: 71 | 72 | ```zsh 73 | cd $ZDOTDIR 74 | ``` 75 | 76 | Show directories with `/`: 77 | 78 | ```zsh 79 | $ echo *(/) 80 | plugins zshrc.d zfunctions 81 | ``` 82 | 83 | Show regular files with `.`: 84 | 85 | ```zsh 86 | $ echo *(.) 87 | .zshenv .zshrc 88 | ``` 89 | 90 | Show symlinks with `@`: 91 | 92 | ```zsh 93 | $ echo *(@) 94 | .zsh_history 95 | ``` 96 | 97 | Toggle qualifiers to work with symlinks `-`: 98 | 99 | ```zsh 100 | $ echo *(.-) 101 | .zshenv .zsh_history .zshrc 102 | ``` 103 | 104 | Exclude files with `^`: 105 | 106 | ```zsh 107 | $ # exclude dotfiles 108 | $ echo ^.* 109 | README.md 110 | ``` 111 | 112 | Null glob, or "don't error on zero results": 113 | 114 | ```zsh 115 | $ mkdir empty && cd empty 116 | $ echo * 117 | zsh: no matches found: * 118 | $ echo *(N) 119 | ``` 120 | 121 | Files over/unsder a certain size with `L[+|-]n`: 122 | 123 | ```zsh 124 | $ # files over 1k 125 | $ echo *(Lk+1) 126 | LICENSE README.md 127 | ``` 128 | 129 | ## Expansion Modifiers 130 | 131 | [Expansion modifiers][zsh-modifiers] change the path stored in a variable. 132 | 133 | Set a file path in a variable to play with (assumes OMZ installed): 134 | 135 | ```zsh 136 | cd $ZSH 137 | filepath=./plugins/extract/extract.plugin.zsh 138 | ``` 139 | 140 | `:a` will expand a relative filepath to an absolute one 141 | 142 | ```zsh 143 | $ echo $filepath 144 | ./plugins/extract/extract.plugin.zsh 145 | $ echo ${filepath:a} 146 | $ZSH/plugins/extract/extract.plugin.zsh 147 | ``` 148 | 149 | `:h` will remove the trailing pathname component, shortening the path by one directory 150 | level. This is the 'head' of the pathname, which works like `dirname`. 151 | 152 | ```zsh 153 | $ echo ${filepath:h} 154 | ./plugins/extract 155 | ``` 156 | 157 | `:r` will remove the file extension leaving the 'root' name. 158 | 159 | ```zsh 160 | $ echo ${filepath:r} 161 | ./plugins/extract/extract.plugin 162 | ``` 163 | 164 | `:t` will remove all leading path components leaving the final part, or 'tail'. This 165 | works like `basename`. 166 | 167 | ```zsh 168 | $ echo ${filepath:t} 169 | extract.plugin.zsh 170 | ``` 171 | 172 | `:u` will convert the variable to UPPERCASE. Conversely, `:l` will convert back to 173 | lowercase. 174 | 175 | ```zsh 176 | $ echo ${filepath:u} 177 | ./PLUGINS/EXTRACT/EXTRACT.PLUGIN.ZSH 178 | $ echo ${filepath:u:l} 179 | ./plugins/extract/extract.plugin 180 | ``` 181 | 182 | [zsh-modifiers]: http://zsh.sourceforge.net/Doc/Release/Expansion.html#Modifiers 183 | [filename-generation]: http://zsh.sourceforge.net/Doc/Release/Expansion.html#Filename-Generation 184 | [zsh-glob-qualifiers]: http://zsh.sourceforge.net/Doc/Release/Expansion.html#Glob-Qualifiers 185 | [glob-filter-stackexchange]: https://unix.stackexchange.com/questions/31504/how-do-i-filter-a-glob-in-zsh 186 | -------------------------------------------------------------------------------- /docs/zsh/zdotdir.md: -------------------------------------------------------------------------------- 1 | # ZDOTDIR 2 | 3 | > A simple guide to moving your Zsh files out of your `$HOME` 4 | 5 | This guide shows you how to move your Zsh files out of your home directory into a dedicated Zsh config directory. 6 | 7 | ## Pick a path 8 | 9 | Assuming you want to put your Zsh config in `~/.config/zsh`, run the following from an interactive Zsh session: 10 | 11 | ```zsh 12 | export ZDOTDIR=~/.config/zsh 13 | mkdir -p $ZDOTDIR 14 | ``` 15 | 16 | These commands will set the `ZDOTDIR` variable to your new Zsh home, and then ensure that the directory is properly created. 17 | 18 | ## Move your Zsh dotfiles 19 | 20 | ```zsh 21 | zdotfiles=( 22 | .zlog{in,out} 23 | .zprofile 24 | .zsh{env,rc,_history} 25 | ) 26 | for file in $zdotfiles 27 | do 28 | [[ -f ~/$file ]] && echo mv ~/$file $ZDOTDIR 29 | done 30 | ``` 31 | -------------------------------------------------------------------------------- /docs/zsh/zsh-optparse.md: -------------------------------------------------------------------------------- 1 | # Parsing Zsh options 2 | 3 | ## Manually 4 | 5 | ```zsh 6 | # Manual opt parsing example 7 | # 8 | # Features: 9 | # - supports short and long flags (ie: -v|--verbose) 10 | # - supports short and long key/value options (ie: -f | --filename ) 11 | # - supports short and long key/value options with equals assignment (ie: -f= | --filename=) 12 | # - does NOT support short option chaining (ie: -vh) 13 | # - everything after -- is positional even if it looks like an option (ie: -f) 14 | # - once we hit an arg that isn't an option flag, everything after that is considered positional 15 | function optparsing_demo() { 16 | local positional=() 17 | local flag_verbose=false 18 | local filename=myfile 19 | 20 | local usage=( 21 | "optparsing_demo [-h|--help]" 22 | "optparsing_demo [-v|--verbose] [-f|--filename=] []" 23 | ) 24 | opterr() { echo >&2 "optparsing_demo: Unknown option '$1'" } 25 | 26 | while (( $# )); do 27 | case $1 in 28 | --) shift; positional+=("$@"); break ;; 29 | -h|--help) printf "%s\n" $usage && return ;; 30 | -v|--verbose) flag_verbose=true ;; 31 | -f|--filename) shift; filename=$1 ;; 32 | -f=*|--filename=*) filename="${1#*=}" ;; 33 | -*) opterr $1 && return 2 ;; 34 | *) positional+=("$@"); break ;; 35 | esac 36 | shift 37 | done 38 | 39 | echo "--verbose: $flag_verbose" 40 | echo "--filename: $filename" 41 | echo "positional: $positional" 42 | } 43 | ``` 44 | 45 | ## With zparseopts 46 | 47 | ```zsh 48 | # zparseopts 49 | # 50 | # Resources: 51 | # - https://xpmo.gitlab.io/post/using-zparseopts/ 52 | # - https://zsh.sourceforge.io/Doc/Release/Zsh-Modules.html#index-zparseopts 53 | # 54 | # Features: 55 | # - supports short and long flags (ie: -v|--verbose) 56 | # - supports short and long key/value options (ie: -f | --filename ) 57 | # - does NOT support short and long key/value options with equals assignment (ie: -f= | --filename=) 58 | # - supports short option chaining (ie: -vh) 59 | # - everything after -- is positional even if it looks like an option (ie: -f) 60 | # - once we hit an arg that isn't an option flag, everything after that is considered positional 61 | function zparseopts_demo() { 62 | local flag_help flag_verbose 63 | local arg_filename=(myfile) # set a default 64 | local usage=( 65 | "zparseopts_demo [-h|--help]" 66 | "zparseopts_demo [-v|--verbose] [-f|--filename=] []" 67 | ) 68 | 69 | # -D pulls parsed flags out of $@ 70 | # -E allows flags/args and positionals to be mixed, which we don't want in this example 71 | # -F says fail if we find a flag that wasn't defined 72 | # -M allows us to map option aliases (ie: h=flag_help -help=h) 73 | # -K allows us to set default values without zparseopts overwriting them 74 | # Remember that the first dash is automatically handled, so long options are -opt, not --opt 75 | zmodload zsh/zutil 76 | zparseopts -D -F -K -- \ 77 | {h,-help}=flag_help \ 78 | {v,-verbose}=flag_verbose \ 79 | {f,-filename}:=arg_filename || 80 | return 1 81 | 82 | [[ -z "$flag_help" ]] || { print -l $usage && return } 83 | if (( $#flag_verbose )); then 84 | print "verbose mode" 85 | fi 86 | 87 | echo "--verbose: $flag_verbose" 88 | echo "--filename: $arg_filename[-1]" 89 | echo "positional: $@" 90 | } 91 | ``` 92 | 93 | ## Here are some examples of the manual parsing function in action... 94 | 95 | Call with no args 96 | 97 | ```zsh 98 | $ optparsing_demo 99 | --verbose: false 100 | --filename: myfile 101 | positional: 102 | ``` 103 | 104 | Call with both short and long options, as well as positional args 105 | 106 | ```zsh 107 | $ optparsing_demo --verbose -f test.txt foo 108 | --verbose: true 109 | --filename: test.txt 110 | positional: foo 111 | ``` 112 | 113 | Call with -- to pass positionals that look like flags 114 | 115 | ```zsh 116 | $ optparsing_demo --filename=test.txt -- -v --verbose -f --filename are acceptable options 117 | --verbose: false 118 | --filename: test.txt 119 | positional: -v --verbose -f --filename are acceptable options 120 | ``` 121 | 122 | Called incorrectly with positionals before intended opts 123 | 124 | ```zsh 125 | $ optparsing_demo do not put positionals before opts --verbose --filename=mynewfile 126 | --verbose: false 127 | --filename: myfile 128 | positional: do not put positionals before opts --verbose --filename=mynewfile 129 | ``` 130 | 131 | This method of opt parsing does not support flag chaining like getopt does 132 | 133 | ```zsh 134 | $ optparsing_demo -vh 135 | optparsing_demo: Unknown option '-vh' 136 | ``` 137 | 138 | --- 139 | 140 | ## Here are some examples of the zparseopt version in action... 141 | 142 | Call with no args 143 | 144 | ```zsh 145 | $ zparseopts_demo 146 | --verbose: 147 | --filename: myfile 148 | positional: 149 | ``` 150 | 151 | Call with both short and long options, as well as positional args 152 | 153 | ```zsh 154 | $ zparseopts_demo --verbose -f test.txt foo 155 | --verbose: --verbose 156 | --filename: test.txt 157 | positional: foo 158 | ``` 159 | 160 | Call with -- to pass positionals that look like flags 161 | 162 | ```zsh 163 | $ zparseopts_demo --filename test.txt -- -v --verbose -f --filename are acceptable options 164 | --verbose: 165 | --filename: test.txt 166 | positional: -v --verbose -f --filename are acceptable options 167 | ``` 168 | 169 | Called incorrectly with positionals before intended opts. If you want this, 170 | zparseopts supports it with the -E flag. 171 | 172 | ```zsh 173 | $ zparseopts_demo do not put positionals before opts --verbose --filename=mynewfile 174 | --verbose: 175 | --filename: myfile 176 | positional: do not put positionals before opts --verbose --filename=mynewfile 177 | ``` 178 | 179 | This method of opt parsing does supports flag chaining like getopt does 180 | 181 | ```zsh 182 | $ zparseopts_demo -vh 183 | zparseopts_demo [-h|--help] 184 | zparseopts_demo [-v|--verbose] [-f|--filename=] [] 185 | ``` 186 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | ##? dotfiles 2 | ##? 3 | ##? Usage: make 4 | ##? 5 | ##? Commands: 6 | 7 | .DEFAULT_GOAL := help 8 | 9 | ##? submodules update all submodules 10 | submodules: 11 | git submodule update --recursive --remote 12 | .PHONY : submodules 13 | 14 | ##? help show this message 15 | help: 16 | @grep "^##?" makefile | cut -c 5- 17 | .PHONY : help 18 | --------------------------------------------------------------------------------