jonaustin.dev

CLI Part 2: History & Config


Zsh Configuration

In the last post we setup a basic Zsh configuration, with:

In this post we’ll look at adding some core zsh configuration to finish the foundation of a good shell experience:

History

One of the primary benefits of Zsh over Bash is a better history experience.

These options add some improvements to zsh’s base history setup:

# History
export HISTSIZE=100000      # Nearly infinite history; essential to building a cli 'library' to use with fzf/etc
export SAVEHIST=100000
setopt share_history        # share it across sessions
setopt extended_history     # add timestamps to history
setopt hist_ignore_all_dups # don't record dupes in history
setopt hist_ignore_space    # remove command line from history list when first character on the line is a space
setopt hist_reduce_blanks   # remove superflous blanks

Sharing and keeping history

A key feature of Zsh, which makes enhancements such as fishshell-style-completions or a tool such as fzf so powerful, is the ability to keep all history from every terminal session.

Combined with enhancements like those mentioned, this allows easy search of your command history, potentially going back years.

Over time this allows the lazy-building of a library of commands:

Searching History with Control-r

Even without taking advantage of a fuzzy search tool like fzf, extensive history is useful via built-in history search.

Simply hit Control-r and start typing.

Note: this functionality is actually part of readline, so it works in any program that makes use of that library, including zsh and bash.

Sane Defaults

Environment variables

Specifically better defaults for:

# Environment variables
export PAGER='less'
# --RAW-CONTROL-CHARS:   translate raw escape sequences to colors
# --squeeze-blank-lines: no more than one blank line in a row
# --quit-on-intr:        quit on interrupt, e.g. C-c
# --quit-if-one-screen:  quit if content fills less than the screen
# --no-init:             don't clear screen on exit
# --mouse:               support mouse - only less version >=551 (`brew install less` on mac)
export LESS='--RAW-CONTROL-CHARS --squeeze-blank-lines --quit-on-intr --quit-if-one-screen --no-init' # --mouse
export TERM=xterm-256color # True Color support in terminals and TUI programs that support it (e.g. vim)
export LC_ALL=en_US.UTF-8
export LANG=en_US.UTF-8

setopt

These options are a bit arcane, so we’re not going to go in-depth with explanations.

They can be helpful, but feel free to skip these at first.

# setopts
setopt auto_cd              # type bare dir name and cd to it e.g. `$ /`
setopt complete_in_word     # don't move cursor to end of line on completion
setopt interactive_comments # allow comments even in interactive shells.
unsetopt beep               # don't bloody beep
unsetopt bg_nice            # don't re-nice bg procs to lower priority
unsetopt correct            # don't autocorrect spelling for args
unsetopt correct_all        # don't autocorrect spelling for args
unsetopt flow_control       # disable ^S/^Q flow control
unsetopt hup                # don't send the HUP signal to running jobs when the shell exits.
unsetopt list_beep          # don't beep on ambiguous completions
unsetopt local_options      # allow funcs to have their own setopts (i.e. don't change globally)
unsetopt local_traps        # allow funcs to have their own signal trap opts (i.e. don't change globally)
typeset -U PATH             # remove duplicate paths

Conclusion

This should set you up with a base zsh with good defaults and a nice playground for expansion with powerlevel10k. Next we’ll look at adding a Zsh Framework to make it easy to add plugins and keep them updated.

Here’s what your ~/.zshrc should now look like:

source ~/.zinit/bin/zinit.zsh

# enable completions
autoload -Uz compinit && compinit -du
autoload -U bashcompinit && bashcompinit # support bash completions

# theme framework
zplugin light "romkatv/powerlevel10k"

# To customize prompt, run `p10k configure` or edit ~/.p10k.zsh.
[[ ! -f ~/.p10k.zsh ]] || source ~/.p10k.zsh

# History
export HISTSIZE=100000      # Nearly infinite history; essential to building a cli 'library' to use with fzf/etc
export SAVEHIST=100000
setopt share_history        # share it across sessions
setopt extended_history     # add timestamps to history
setopt hist_ignore_all_dups # don't record dupes in history
setopt hist_ignore_space    # remove command line from history list when first character on the line is a space
setopt hist_reduce_blanks   # remove superflous blanks

# Environment variables
export PAGER='less'
# --RAW-CONTROL-CHARS:   translate raw escape sequences to colors
# --squeeze-blank-lines: no more than one blank line in a row
# --quit-on-intr:        quit on interrupt, e.g. C-c
# --quit-if-one-screen:  quit if content fills less than the screen
# --no-init:             don't clear screen on exit
# --mouse:               support mouse - only less version >=551 (`brew install less` on mac)
export LESS='--RAW-CONTROL-CHARS --squeeze-blank-lines --quit-on-intr --quit-if-one-screen --no-init' # --mouse
export TERM=xterm-256color # True Color support in terminals and TUI programs that support it (e.g. vim)

export LC_ALL=en_US.UTF-8
export LANG=en_US.UTF-8

# setopts
setopt auto_cd              # type bare dir name and cd to it e.g. `$ /`
setopt complete_in_word     # don't move cursor to end of line on completion
setopt interactive_comments # allow comments even in interactive shells.
unsetopt beep               # don't bloody beep
unsetopt bg_nice            # don't re-nice bg procs to lower priority
unsetopt correct            # don't autocorrect spelling for args
unsetopt correct_all        # don't autocorrect spelling for args
unsetopt flow_control       # disable ^S/^Q flow control
unsetopt hup                # don't send the HUP signal to running jobs when the shell exits.
unsetopt list_beep          # don't beep on ambiguous completions
unsetopt local_options      # allow funcs to have their own setopts (i.e. don't change globally)
unsetopt local_traps        # allow funcs to have their own signal trap opts (i.e. don't change globally)
typeset -U PATH             # remove duplicate paths

#cli #zsh