Setup macOS 2021 For Optimal Command Line Productivity

Setup Modern Command Line Tools

here’s a quick guide for setting up modern command line environments on a fresh macOS Monterey 12+ as of late 2021.


stop saving screenshots directly to destop

We no longer need to defaults write to stop all screenshots going to ~/Desktop/ by default. Instead, just do a regular CMD+SHIFT+5 then click the lower screen toolbar Options menu, and select a better directory for all future screen captures!

install homebrew:

install modern tools:

# Fix macOS awful built in tools they refuse to update because they are a
# multi-trillion dollar company refusing to confront modern licenses or
# just outright pay for public use of software written by individuals.
# mac /bin/ls is awful, so coreutils ls is better (installed as 'gls').
# mac rsync stopped updating in 2006(!) so install the latest version manually.
# install modern langs/dependencies/utils/extensions for multiple needs too.
brew install zsh-autosuggestions zsh-completions bash bash-completion@2 tmux coreutils fswatch
brew install ripgrep neovim bat fzf fd jq git awk yt-dlp diff-so-fancy exiftool autossh rename
brew install openblas cmake libxml2 apache-arrow openssl ffmpeg pandoc kerl aspell
brew install awscli nmap rsync sassc watch
brew install dnsmasq htop wget
brew install ansible cowsay pv

# instead of homebrew pyenv, you may want to clone `pyenv` from the main repo
# because `pyenv` often adds new release spec files to their repo weeks before cutting
# new official releases for homebrew. They should eventually refactor releases
# to be independent from the code releases themselves, right?
# You can also hack around homebrew delayed updates by finding the version file from
# the main `pyenv` repo and copying the spec into homebrew dir:
# /opt/homebrew/opt/pyenv/plugins/python-build/share/python-build
brew install zig rust lua luarocks pyenv npm rebar perl zlib ctags

# fix autocomplete permission to not warn on startup
chmod -R go-w '/opt/homebrew/share/zsh'
chmod -R 755 /opt/homebrew/share

# install pyenv shell environment helpers
echo 'eval "$(pyenv init --path)"' >> ~/.zprofile
echo 'eval "$(pyenv init -)"' >> ~/.zshrc

# reload settings into current console
source ~/.zshrc ~/.zprofile

configure things good

# install good helpers for things
npm install -g uglify-js 

# install python versions you like to run:
pyenv install 3.10.2
pyenv global 3.10.2

# configure git properly along with good helpers
git config --global "Matt Stancliff"
git config --global ""

# put all your dirty files in here (.DS_Store, tags, __pycache__, etc)
git config --global core.excludesfile ~/.gitignore_global

# recent git releases enabled auto-pager for "git branch" which is hella'nnoying
git config --global pager.branch false
git config --global init.defaultBranch main

# stop git from dropping commit messages because the editor return code isn't stable
git config --global core.editor nvim -f

git config --global alias.llog "log --pretty=fuller"
git config --global alias.logs "log --graph --pretty=format:'%C(magenta)%h%Creset -%C(red)%d%Creset %s %C(dim green)(%cr) %C(cyan)<%an>%Creset' --abbrev-commit"
git config --global alias.rl "reflog --format='%C(auto)%h %<|(20)%gd %C(blue)%cr%C(reset) %gs (%s)'"

git config --global alias.tagdate 'log --date-order --graph --tags --simplify-by-decoration --pretty=format:"%ai %h %d"'
git config --global alias.branchbydate "for-each-ref --count=30 --sort=-committerdate refs/heads/ --format='%(refname:short)'"
git config --global alias.branchcolor '!for ref in $(git for-each-ref --sort=-committerdate --format="%(refname)" refs/heads/ refs/remotes ); do git log -n1 $ref --pretty=format:"%Cgreen%cr%Creset %C(yellow)%d%Creset %C(bold blue)<%an>%Creset%n" | cat ; done | awk '"'! a["'$0'"]++'"

# short for "github-add". usage: git gha [github user] [reponame]
git config --global alias.gha '!f() { git remote add $1$1/$2.git; }; f'

# short for "git pull request". usage: git gpr [github issue-id] [local name]
git config --global alias.gpr '!f() { git fetch origin pull/$1/head:$2; }; f'

git config --global core.pager "diff-so-fancy | bat -p"
git config --global interactive.diffFilter "diff-so-fancy --patch"

# Note: if you don't like the light color shading from these defaults,
#       edit ~/.gitconfig and remove section: [color "diff-highlight"]
diff-so-fancy --set-defaults

setup global python dev/experiment environment

configure optimal DNS performance, in /opt/homebrew/etc/dnsmasq.conf add:

brew edit dnsmasq and change service launch to (may need to monitor updates and re-change if versions flip underneath you):

start local dns resolver with performance and content fixes

then go to network settings and fix your DNS server to

flush all DNS caches:

set up neovim for modern editing:

configure neovim with modern plugins

tell neovim to load plugins on startup in ~/.config/nvim/init.vim

run in nvim after the files are in place (may require run/exit/run again):

Install good shell defaults and auto-helper scripts

~/.zshrc updates:

# many themes, but my requirements are:
# prompt must include hostname
# prompt must include full path (not just current directory)
# any metadata like current branches/repos in prompt must not make the prompt line "too long"
# no date/time in prompt

# zsh has an awful tab completion bug unless this is defined

# tab complete the entire first suggestion by default instead
# of stalling out and requiring a second tab for "menu select"
setopt menu_complete

alias ls="gls --color=auto"
alias moretty="sudo sysctl -w kern.tty.ptmx_max=768"
alias nolo='exiftool -GPSLongitude= -GPSLatitude='
alias po=poetry
alias goodnight='pmset displaysleepnow'
alias pi='echo "scale=60; 4*a(1)" | bc -lq'
alias vim=nvim

# stop warnings from autocomplete files having weird permissions

# completions from brew zsh-completions
if type brew &>/dev/null; then
  FPATH=$(brew --prefix)/share/zsh-completions:$FPATH

  autoload -Uz compinit

# extract frames from a video to individual image files.
# usage: toImgs [movie path] [prefix for output files]
function toImgs() {
    # the "-r 7" says dump 7 images per second of video.
    # You can increase or decrease 'r N' as necessary.
    ffmpeg -i "$1" -r 7 -qscale:v 2 "$2"-%0000d.jpg

# add a console "note" command to open a markdown file in the
# current directory named with the current date and any suffix
# provided as arguments to the command.
# usage: note shopping list
function note() {
    if [[ ! -z "$*" ]]; then
        # Use all arguments as trailing name for note
        # (spaces replaced by dashes)
        note_name="-${*// /-}"
    nvim $(date "+%Y-%m-%d")$

# create directory and jump into it with one command
function ccd() {
    mkdir -p "$1"
    cd "$1"

# get the binary log of a number
# if you like using 'l' as the default 'ls' shorthand, don't do this i guess.
unalias l
function l()  {
     echo "scale=10; l($1)/l(2)" | bc -lq

# do a 2^x
function 2x()  {
    echo "2^$1" | bc -lq                 

# do a e^x
function e()  {
    echo "e($1)" | bc -lq                 

edit kphoen theme ~/.oh-my-zsh/themes/kphoen.zsh-theme for more compactness:

try to pre-trigger all the macOS directory protection warnings up front

In your home directory, run “find .” or “fd > /dev/null” and accept all OS warnings about allowing Terminal to access your directories so future usage doesn’t unexpectedely encounter errors. You’ll also get an OS warning if you access any remote disks and also local disks in /Volumes/ from a terminal session too.

Install better terminal fonts:

Other recent setup problems:

many python packages still don’t have arm64/M1 binaries yet, so pip/poetry will try to build from source and we need extra arguments for the bulids to find our homebrew locations:

compiling some python packages (scipy specifically) requires:

You can also currently install a scipy 1.8.0 prerelease arm binary package, but arm binary packages don’t exist for current fully released versions (but manually installing custom binaries from other sources breaks poetry deps in a dozen different ways too; best to wait for a new official release to get projects working again).

python package numba is limited to llvm10 which homebrew won’t provide for us, so we need to build it manually: download llvm10, build, then provide extra build environment options where needed:

oh, and of course there’s also a bug with LLVM 10 they never fixed where it uses a bad libxml2 link, so you need to make sure you have libxml2 installed from brew then:

Now you have llvm-config at ~/build/llvm-10.0.1.src/bin/llvm-config and you can re-try your failed numba dependency building/installing with:

erlang versions