# Emacs style bindkey -e zle -N edit-command-line bindkey '^xe' edit-command-line bindkey '^x^e' edit-command-line # Vi style: # zle -N edit-command-line # bindkey -M vicmd v edit-command-line bindkey \^U backward-kill-line # Enable Ctrl-x-e to edit command line autoload -U edit-command-line # completions. Homebrew keeps them under its own prefix, which differs by # machine -- /opt/homebrew on Apple Silicon, /usr/local on Intel -- and formulae # install into share/zsh/site-functions, not the share/zsh-completions this # hardcoded until 2026-09-21. That path existed on neither Mac, so every # brew-installed completion (_brew, _bat, _deno, ...) was silently missing. # Probed rather than asked of `brew --prefix`, which would fork on every shell, # and done here because compinit below is the only moment fpath is read. for _fp in \ "${HOMEBREW_PREFIX:-/opt/homebrew}/share/zsh/site-functions" \ "${HOMEBREW_PREFIX:-/opt/homebrew}/share/zsh-completions" \ /usr/local/share/zsh/site-functions \ /usr/local/share/zsh-completions do [[ -d "$_fp" ]] && fpath=("$_fp" $fpath) done unset _fp # fix delete bindkey "^[[3~" delete-char bindkey "^[3;5~" delete-char # Caps Lock is F20 (hammerspoon). A terminal with no tmux in front of zsh, like # Alacritty, sends it as ESC[34~. Nothing binds that, so zsh split it and left a # `~` at the prompt for every key repeat. Binding the whole sequence to nothing # makes zsh consume it as one key. Wispr Flow reads the key itself. bindkey -s '^[[34~' '' # chpwd() { ls -A; } # Auto ls after changing directory. CDPATH=~ # Check ~ for directories after checking . (`c/d/` matches `./c*/d*/`, then tries `~/c*/d*/`). setopt no_auto_menu # don't complete on ambiguous cases setopt interactive_comments # Allow comments in the terminal. setopt BANG_HIST # Treat the '!' character specially during expansion. setopt EXTENDED_HISTORY # Write the history file in the ":start:elapsed;command" format. setopt INC_APPEND_HISTORY # Write to the history file immediately, not when the shell exits. setopt SHARE_HISTORY # Share history between all sessions. setopt HIST_EXPIRE_DUPS_FIRST # Expire duplicate entries first when trimming history. setopt HIST_IGNORE_DUPS # Don't record an entry that was just recorded again. setopt HIST_IGNORE_ALL_DUPS # Delete old recorded entry if new entry is a duplicate. setopt HIST_FIND_NO_DUPS # Do not display a line previously found. setopt HIST_IGNORE_SPACE # Don't record an entry starting with a space. setopt HIST_SAVE_NO_DUPS # Don't write duplicate entries in the history file. setopt HIST_REDUCE_BLANKS # Remove superfluous blanks before recording entry. # setopt HIST_VERIFY # Don't execute immediately upon history expansion. # setopt HIST_BEEP # Beep when accessing nonexistent history. # don't fret if globbing patterns can't be expanded, just # use them as is. useful for curl commands with '?' # https://superuser.com/questions/982110/how-can-i-disable-globbing-for-url-arguments-in-zsh setopt NO_NOMATCH # disable case sensitivity zstyle ':completion:*' matcher-list 'm:{a-zA-Z}={A-Za-z}' # don't ask "do you wish to see all NNN possibilities" export LISTMAX=0 # if command -v startship # then # eval "$(starship init zsh)" local pure_src="$HOME/src/sindresorhus/pure" if [[ -d "$pure_src" ]] then fpath=("$pure_src" "$fpath[@]") autoload -U promptinit promptinit prompt pure # PURE_PROMPT_SYMBOL='∴' else # PROMPT="$SUPLEMENT%F{8}%1~%f ∴ " PROMPT="%F{244}%1~%f ∴ " fi # Use modern completion system autoload -Uz compinit compinit -u zstyle ':completion:*' auto-description 'specify: %d' zstyle ':completion:*' completer _expand _complete _correct _approximate zstyle ':completion:*' format 'Completing %d' zstyle ':completion:*' group-name '' zstyle ':completion:*' menu select=2 command -v dircolors >/dev/null 2>&1 && eval "$(dircolors -b)" zstyle ':completion:*:default' list-colors ${(s.:.)LS_COLORS} zstyle ':completion:*' list-colors '' zstyle ':completion:*' list-prompt %SAt %p: Hit TAB for more, or the character to insert%s zstyle ':completion:*' matcher-list '' 'm:{a-z}={A-Z}' 'm:{a-zA-Z}={A-Za-z}' 'r:|[._-]=* r:|=* l:|=*' zstyle ':completion:*' menu select=long zstyle ':completion:*' select-prompt %SScrolling active: current selection at %p%s zstyle ':completion:*' use-compctl false zstyle ':completion:*' verbose true zstyle ':completion:*:*:kill:*:processes' list-colors '=(#b) #([0-9]#)*=0=01;31' zstyle ':completion:*:kill:*' command 'ps -u $USER -o pid,%cpu,tty,cputime,cmd' # Recommended by Docker autocompletion # https://docs.docker.com/compose/completion/ # fpath=(~/.zsh/completion $fpath) # autoload -Uz compinit && compinit -i autoload run-help HELPDIR=/usr/local/share/zsh/help # function that sources the given file if it exists source_if_exists() { if [[ -f "$1" ]] then source "$1" fi } source "$HOME/.profile" # fzf setup (must come after .profile which sets up PATH for brew) brew_prefix="$(brew --prefix 2>/dev/null || true)" if [[ -n "$brew_prefix" ]] then # Setup fzf if [[ ! "$PATH" == *opt/fzf/bin* ]]; then export PATH="$PATH:$brew_prefix/opt/fzf/bin" fi # Auto-completion [[ $- == *i* ]] && source "$brew_prefix/opt/fzf/shell/completion.zsh" 2> /dev/null # Key bindings source "$brew_prefix/opt/fzf/shell/key-bindings.zsh" elif [[ "$(uname)" == "Linux" ]] && command -v fzf > /dev/null then # check if file exists before sourcing with zsh source_if_exists /usr/share/doc/fzf/examples/key-bindings.zsh source_if_exists /usr/share/doc/fzf/examples/completion.zsh source_if_exists /usr/share/fzf/shell/key-bindings.zsh fi export FZF_COMPLETION_OPTS="--border --info=inline ${FZF_COMPLETION_OPTS:-}" setup_dir_hashes() { local src="$HOME/src" if [ -d /Volumes/Sense/src ] then src=/Volumes/Sense/src fi # Named directories for the checkouts this account works in, ~dot and the # rest. Only those that exist: zsh prints a warning for a hash -d to a # missing path, and which projects a machine has is the machine's business. # Not `local path`: in zsh that is tied to $PATH, and assigning to it in the # loop would blank PATH for the rest of this function, sourced fragment # included. local name dir for name dir in \ dot "$src/soarez/dot" \ cs "$src/soarez/cloud-setup" do [ -d "$dir" ] && hash -d "$name=$dir" done # More of them, for whatever this machine works on, from a file another layer # links in. Same shape: `hash -d name=path`, one per line, zsh syntax. local extra="${XDG_CONFIG_HOME:-$HOME/.config}/shell/dir-hashes.zsh" [ -r "$extra" ] && source "$extra" } setup_dir_hashes # ~/bin is prepended to PATH in config/env (which, unlike the line that used to # be here, skips it when the directory doesn't exist). export COURSIER_CREDENTIALS=~/.config/coursier/credentials.properties # ## Support .envrc files: https://direnv.net/docs/hook.html # eval "$(direnv hook zsh)" # ## https://www.jenv.be # eval \"$( jenv init - )\"