Tripping on Code

My ZSHRC setup

July 25, 2026

As a developer, I spend a lot of time on the terminal. My .zshrc file has evolved over the years and will continue evolving. The purpose of this post is to share my findings to help new users.

I did not like oh-my-zsh. I felt like it added too much bloat. I like the idea of only having the features I want.

Folder Structure

I don't like having all my configurations in a single file. I like my config to be modular. This way, all configs related to a tool live together.

In my home directory, I have a .zshrc, a .zshenv and a .zprofile file. I also have a directory called .zsh/. This directory contains one file per tool. Eg. .zsh/fzf-setup.sh.

.Zshrc

Basic Options

The following set some basic options. Options such as auto cd, ignore dups etc. They also enable a shared history and save the history into a history file.

setopt autocd
setopt HIST_IGNORE_DUPS
setopt AUTO_PUSHD
setopt PUSHD_IGNORE_DUPS
HISTFILE=~/.zsh_history
HISTSIZE=10000

SAVEHIST=10000
setopt SHARE_HISTORY

Completion Styles

First, we need to load the completion initializer. autoload -Uz compinit does that. Running compinit initializes the completion functions.

Now to set completion behavoir. First thing we do is enable menu completion. This shows multiple options that we can navigate through when tab completion is invoked. We do that using the following line

zstyle ':completion:*' menu select`

Next, we set up completion strategies. The strategies we enable are the following

  • expand - Perform shell expansion
  • complete - Use normal completion
  • ignored - Fallback to ignored items
  • correct - To minor fixes on spelling. i.e replaces the word with one with the correct spelling
  • approxmiate - Do fuzzy matching. i.e error tolerant correction.
zstyle ':completion:*' completer _expand _complete _ignored _correct _approximate

Next, we provide options to allow substring matches as well rules on how to select the correct matcher first

# Insert longest unambigous prefix first instead of jumping to a corrected guess
zstyle ':completion:*' insert-unambiguous true

# Make case insensitive match as well as a substring match
zstyle ':completion:*' matcher-list 'm:{a-zA-Z}={A-Za-z}' 'l:|=* r:|=*'

Finally, we ask zsh to cache the completion data so that expensive completions are not computed again and again.

zstyle ':completion:*' use-cache on
zstyle ':completion:*' cache-path ~/.zsh/cache

Make the prompt look pretty

I am a big fan of pure. So The next couple of lines set it up to use pure prompt

autoload -U promptinit; promptinit
prompt pure

Enable Line Editor

When writing complex commands in the terminal, Writing it in a text editor like nvim or vim is easier. Pressing Ctrl+X e opens the current line in a text editor.

autoload edit-command-line
zle -N edit-command-line
bindkey '^Xe' edit-command-line

Persist SSH agent across terminals

I use ssh-agent extensively to manage ssh keys. But I don't want a separate ssh-agent to run for every invocation of zsh. The following code sets the ssh agent environemnt variables rather than running ssh-agent every time.

# Persist ssh-agent across terminals
SSH_ENV="$HOME/.ssh/agent-env"
if [ -f "$SSH_ENV" ]; then
    source "$SSH_ENV" > /dev/null
fi
if [ -z "$SSH_AUTH_SOCK" ] || ! ssh-add -l &>/dev/null; then
    eval $(ssh-agent -s) > /dev/null
    echo "export SSH_AUTH_SOCK=$SSH_AUTH_SOCK" > "$SSH_ENV"
    echo "export SSH_AGENT_PID=$SSH_AGENT_PID" >> "$SSH_ENV"
    chmod 600 "$SSH_ENV"
fi

Zsh Modules

Below are files in my .zsh folder. I will describe a module, what it does and follow it up with my config.

Fzf

Fzf is a command line fuzzy finder. Fzf can be used as a standalone tool or it can be integrated into zsh or other shells. This allows us to have keyboard shortcuts to autocomplete items in the shell.

My .zsh/fzf-setup.sh file is as follows

if command -v fzf &> /dev/null
then
    export FZF_DEFAULT_OPTS="--extended"
    export FZF_DEFAULT_COMMAND="fd --type f --strip-cwd-prefix"
    export FZF_COMPLETION_OPTS='--border --info=inline'
    export FZF_CTRL_T_COMMAND="$FZF_DEFAULT_COMMAND"
    export FZF_ALT_C_COMMAND="fd --type d --strip-cwd-prefix"
    export FZF_CTRL_T_OPTS="--preview='$HOME/.zsh/helpers/fzf-preview.sh {}' --height=100%"
    # export FZF_CTRL_T_OPTS="--preview='bat -n --color=always {}' --height=100% --bind shift-up:preview-page-up,shift-down:preview-page-down"
    source "$HOME/.zsh/helpers/fzf-git.sh"
    source <(fzf --zsh)
else
    echo "FZF is not installed."
fi

_fzf_compgen_dir() {
  fd --type d --hidden --follow . "$1"
}

_fzf_compgen_path() {
  fd --hidden --follow . "$1"
}

These settings do the following.

  • Configures Ctrl+T to show all files in fzf including previews using bat
  • Configures Alt+C to show all directories in fzf
  • Configure Cttrl+R to show the history in fzf

LSD Aliases

lsd improves the directory listing to show icons and much more useful information. So in my .zsh/lsd-setup.sh, I alias ls to use lsd behind the scenes.

if command -v lsd &> /dev/null
then
    alias ls='lsd -a'
    alias ll='lsd -la'
    alias la='lsd -la'
    alias lt='lsd --tree --depth 2'
else
    echo "LSD is not installed. using ls instead"
fi

Git Aliases

I create a lot of aliases for commonly run git commands. Many of these are inspired from oh-my-zsh's git module. The comments in the code below explain what they do. This is in a file called .zsh/setup-git.sh


# Navigate to the source directory
alias 2src='cd ~/Source'

# Navigate to the root of the git repo
function 2root() {
  ROOT=$(git rev-parse --show-toplevel 2> /dev/null)
  cd "$ROOT" || echo "Not inside a git repository"
}

alias g='git'
compdef g=git

alias gs='git status'
compdef _git gs=git-status

alias ga='git add'
compdef _git ga=git-add

alias gpl='git pull'
compdef _git gpl=git-pull

alias gph='git push'
compdef _git gph=git-push

alias gcob='git checkout -b'
compdef _git gcob=git-checkout

alias gco='git checkout'
compdef _git gco=git-checkout

# Range-diff from main
alias grd='git range-diff main...'

# Range diff from origin/branch
alias grdo='git range-diff @{u}...'

# Git branch shows good colored output
alias gbr="git for-each-ref --sort=-committerdate refs/heads --format='%(authordate:short) %(color:red)%(objectname:short) %(color:yellow)%(refname:short)%(color:reset) (%(color:green)%(committerdate:relative)%(color:reset))'"
compdef _git gbr=git-branch

function gphu()
{
    local BRANCH=`git rev-parse --abbrev-ref HEAD`
    git push -u origin $BRANCH
}


Zoxide Setup

Zoxide calls itself a "smart cd command" and it lives up to it's name. To quote their github page, "It remembers which directories you use most frequently, so you can "jump" to them in just a few keystrokes. zoxide works on all major shells."

To explain how this works, I frequently access the ~/Source/TrippingOnCode/blog directory a lot. Once zoxide is setup and it knows what directories I access, just typing cd blog in the home directory navigates me to ~Source/TrippingOnCode/blog directory. zoxide gets smarter the more you cd into other directories.

if command -v zoxide &> /dev/null
then
    # Zoxide with cd causes partial completion to not work properly
    if [[ -z "${CLAUDECODE}" ]]; then
        eval "$(zoxide init --cmd cd zsh)"
    fi

else
    echo "Zoxide is not installed. using cd instead"
fi