# My Z shell setup

I've been a [Fish shell](https://en.wikipedia.org/wiki/Fish_(Unix_shell)) user for years. It was my shell of choice on my Linux systems until I purchased my [MacBook Pro](https://blog.philipnewborough.co.uk/posts/my-macbook-pro-m5), when I switched to [Z shell](https://en.wikipedia.org/wiki/Z_shell).

As a fairly new Z shell user, I thought it might be good for me to document how I install and configure it, so that I can replicate my setup on new servers etc.

## Install

I run Debian on my servers, so adjust this command if you use a different Linux distro. I've included `git` and `curl` as Git is required to clone the Z shell scripts and `curl` is referenced in my `.zshrc` file.

```
sudo apt update
sudo apt install zsh git curl
```

## Clone zsh scripts from GitHub

Run the following commands to create a directory to hold the zsh scripts before cloning them from GitHub:

```
mkdir -p ~/.zsh
git clone https://github.com/sindresorhus/pure.git ~/.zsh/pure
git clone https://github.com/zsh-users/zsh-autosuggestions ~/.zsh/zsh-autosuggestions
git clone https://github.com/zsh-users/zsh-history-substring-search ~/.zsh/zsh-history-substring-search
git clone https://github.com/lukechilds/zsh-better-npm-completion ~/.zsh/zsh-better-npm-completion
```

## Create the .zshrc file

The `.zshrc` file is used to configure the shell session and make use of the above scripts. Run the command:

```
nano ~/.zshrc
```

And paste in the following:

```
# --- STARTUP SYSTEM INFO (Linux interactive shells only) ---
if [[ -o interactive && "$(uname -s)" == "Linux" ]]; then
  echo

  # Header
  print -P "%F{cyan}=== System Info ===%f"

  # Core info
  print -P "Host:    %F{green}%m%f"
  print -P "User:    %F{green}%n%f"
  print -P "Uptime:  %F{green}$(uptime -p)%f"
  print -P "Kernel:  %F{green}$(uname -r)%f"

  # OS info (safe fallback if file missing)
  if [[ -r /etc/os-release ]]; then
    os=$(awk -F= '/^PRETTY_NAME=/ {gsub(/"/,"",$2); print $2}' /etc/os-release)
    print -P "OS:      %F{green}$os%f"
  fi

  # RAM usage
  ram=$(free | awk '/^Mem:/ {used=$3; total=$2; pct=int(used/total*100); printf "%.1f/%.1fG (%d%%%%)", used/1024/1024, total/1024/1024, pct}')
  print -P "RAM:     %F{green}$ram%f"
  # Root disk usage (cleaner parsing)
  disk=$(df -h / | awk 'NR==2 {print $3 "/" $2 " (" $5 "%)"}')
  print -P "Disk:    %F{green}$disk%f"
  # Inode usage
  inode=$(df -i / | awk 'NR==2 {gsub(/%/,"",$5); print $3 "/" $2 " (" $5 "%%)"}')
  print -P "Inodes:  %F{green}$inode%f"
  echo
fi

# --- PATH CUSTOMISATION ---
# Ensure ~/bin is at the front of PATH (and avoid duplicates)
typeset -U path
path=(~/bin $path)

# --- HISTORY SETTINGS ---
# File location and size limits for command history
HISTFILE=~/.zsh_history
HISTSIZE=5000      # commands kept in memory
SAVEHIST=5000      # commands saved to file

# Share history across all terminal sessions in real time
setopt SHARE_HISTORY

# Skip saving duplicate consecutive commands
setopt HIST_IGNORE_DUPS

# --- PURE PROMPT SETUP ---
# Add Pure prompt functions to fpath if installed, then enable Pure theme
if [[ -d "$HOME/.zsh/pure" ]]; then
  fpath+=("$HOME/.zsh/pure")
  autoload -U promptinit; promptinit
  prompt pure
fi

# --- COMPLETION SETTINGS ---
# Enable Zsh's programmable completion system
autoload -Uz compinit && compinit

# Make completion case-insensitive (e.g. "doc" → "Documents")
zstyle ':completion:*' matcher-list 'm:{a-z}={A-Z}'

# --- SSH HOST COMPLETION ---
# Populate SSH/SCP completion from ~/.ssh/config (ignore wildcard entries)
if [ -f ~/.ssh/config ]; then
  h=($(grep -i "^Host " ~/.ssh/config | grep -v "*" | awk '{print $2}'))
  zstyle ':completion:*:*:ssh:*:hosts' hosts $h
  zstyle ':completion:*:*:scp:*:hosts' hosts $h
fi

# --- COMPLETION UI TWEAKS ---
# Enable interactive selection menu and improve descriptions
zstyle ':completion:*:*:ssh:*' menu select
zstyle ':completion:*' verbose yes
zstyle ':completion:*:descriptions' format '%B--- %d ---%b'

# --- NPM COMPLETION ---
# Load enhanced npm completion if available
[[ -f ~/.zsh/zsh-better-npm-completion/zsh-better-npm-completion.plugin.zsh ]] && \
  source ~/.zsh/zsh-better-npm-completion/zsh-better-npm-completion.plugin.zsh

# --- HISTORY SUBSTRING SEARCH ---
# Allows up/down arrows to search history by current input
if [[ -f ~/.zsh/zsh-history-substring-search/zsh-history-substring-search.zsh ]]; then
  source ~/.zsh/zsh-history-substring-search/zsh-history-substring-search.zsh

  # Bind arrow keys (terminfo first, fallback sequences if needed)
  bindkey "$terminfo[kcuu1]" history-substring-search-up
  bindkey "$terminfo[kcud1]" history-substring-search-down
  bindkey '^[[A' history-substring-search-up
  bindkey '^[[B' history-substring-search-down
fi

# --- AUTOSUGGESTIONS ---
# Fish-style inline suggestions based on history
if [[ -f ~/.zsh/zsh-autosuggestions/zsh-autosuggestions.zsh ]]; then
  source ~/.zsh/zsh-autosuggestions/zsh-autosuggestions.zsh

  # Subtle grey suggestion text
  ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE='fg=8'

  # Accept suggestion with right arrow
  bindkey '^[[C' autosuggest-accept
fi

# ---------------
# --- ALIASES ---
# ---------------

# --- Git helpers ---
alias gs='git status'
alias gd='git diff'
alias ga='git add'
alias gc='git commit'
alias gcm='git commit -m'
alias gl='git log --oneline --graph --decorate'
alias gp='git pull'
alias gps='git push'
alias gb='git branch'
alias gco='git checkout'

# File list helpers
alias ls='ls --color=auto'
alias ll='ls -lh --color=auto'
alias la='ls -lah --color=auto'

# --- OS-SPECIFIC HELPERS ---
case "$(uname -s)" in
  Darwin)
    # macOS
    alias ports='lsof -iTCP -sTCP:LISTEN -n -P'
    alias localip="ipconfig getifaddr en0"
    ;;
  Linux)
    # Linux
    alias ports='ss -tulpen'
    alias localip='hostname -I'
    ;;
esac

# Public IPv4 address
alias myip='curl -4 ifconfig.me && echo'
```

## Set Z shell as the default shell

Enter the following command to set Z shell as your default shell:

```
chsh -s $(which zsh)
```

**Note:** you'll be prompted for your user password to confirm the change.