success_logo

Your form has successfully submitted

One of our teammates will get back to you soon.

Supercharge your terminal - The essentials

In this tutorial, I go through the basics of setting up oh-my-zsh, tmux, and additional quality-of-life features with as little configuration as possible to get you started with a cool-looking terminal packed with features.


Throughout my career as a software developer, I’ve used a lot of IDEs, tools and operating systems. But the only thing that hasn't changed is the terminal shell. It’s part of our daily lives, even if we want it or not.Over the years, I’ve seen new people using the default bash shell that comes with the OS and now I think to myself how much they are missing out on some “quality of life” features. For this, I’ve created this guide that can help you turn a boring black and white terminal into a powerful, easy-to-use tool that also looks pleasant to the eyes.

I have decided to make a 2 part tutorial to keep things as simple as possible and avoid cramming everything into a huge wall of text. This is the first part, which is about the essentials. I’ll go through the most useful stuff with as little configuration as possible to get you started very quickly with sane defaults. The second one will be about optimization where I’ll touch on more advanced stuff like custom shell functions and configurations to remove the extra bloat of features and only use the things we need.

Requirements

So, to start the customization process we need a few things first:

Terminal Emulators

I don’t use any specific terminal emulator, so I think whichever you prefer is fine. I usually use the one that comes by default with the system. On MacOS I prefer iTerm2 just because I’m used to it, but the default terminal will work just fine.

ZSH

Most Linux distributions come with the Bash shell by default. While this is fine for remote servers or docker containers which don't need much user interaction or customization, developers can benefit from the added features and extensibility of ZSH. It is built on top of the Bash shell but with added support for plugins and themes.

Note: For MacOS users, ZSH comes built-in by default.

To install it, you just need to install the correct package of your OS package manager. In Debian-based distributions for example, you can install it like this:

$ sudo apt install zsh 

After that, you need to change your current shell to use ZSH:

$ chsh -s /usr/bin/zsh 

Now, as it is, it’s not better than the previous Bash shell. It’s just a standard white text on black background with almost no extra functionality, so let’s change that!

Antigen

To get some nice things like autocompletion, syntax highlighting and themes we need to install some plugins first.

The easiest way to do this is by installing a plugin manager. Personally, I use antigen as I never had any issues with it. We can install it using curl like this:

$ curl -L git.io/antigen > antigen.zsh 

With the requirements out of the way let's proceed with the configuration.

Look and feel

Oh My Zsh

Probably the most popular and widely used ZSH framework (just look at the number of forks and stars in the Github repo, it’s even more popular than the Linux Kernel!). A ZSH framework is just a collection of functions, features (plugins) and themes which aim to work out of the box with very little effort and thus, avoiding to deal with manual configurations and integrations that could take hours to get them running together.

It already comes preconfigured with some defaults, so we just need to enable it with antigen. There are 2 ways to configure antigen, my preferred (and also recommended) is to use ~/.antigenrc with the following content:

antigen use oh-my-zsh
antigen apply

We also need to source and initialize the antigen script so, open the ~/.zshrc file (should be created by default when changing shells), remove all the content from it and add the following text:

source ~/antigen.zsh
# Initialize antigen using the configuration from ~/.antigenrc
antigen init ~/.antigenrc

This is the minimal configuration possible and it already comes with plenty of features and with a much nicer theme than the default bash prompt. Here we are just loading the antigen script with oh-my-zsh. The last instruction should always be antigen apply, any antigen command after it will be ignored.

Note: Depending on where your antigen.zsh file is, you should change the source path to the correct one. If you installed it using curl, it will probably be in ~/antigen.zsh. Or if you used Homebrew on MacOS it will probably be on this location:

source $(brew --prefix)/share/antigen/antigen.zsh

Theme

If you don’t like the built-in theme, you can change it to one of the hundreds of other bundled themes or external themes. My personal favorites are Spaceship for its simplicity and Powerlevel10k for its sheer amount of features and customization.

To change it, just add this line above the antigen apply line:

antigen theme spaceship-prompt/spaceship-prompt

Which matches the syntax user/repo from github and it must contain a .zsh-theme file.

Functionality

Built-in plugins

To start adding some better quality of life features, we need to open the antigen configuration file to manage the plugins. So, let’s start by enabling some plugins with the following lines after antigen use oh-my-zsh in the ~/.antigenrc file:

# Creates useful git aliases
antigen bundle git

# Creates useful docker aliases
antigen bundle docker

# Automatically starts the ssh-agent and loads the credentials defined in  
# ~/.ssh
antigen bundle ssh-agent

These are some plugins that already come bundled with oh-my-zsh but disabled by default, so if there’s no path, antigen will try to look for them on the local oh-my-zsh installation. To configure it further, there’s a ton of other plugins that offer aliases for almost any command you can think about: ansible, brew, python, node, etc.

External plugins

These are plugins that don't come bundled with oh-my-zsh and need to be installed separately, but antigen will do that for us. So, let’s add them to ~/.antigenrc

# add some aliases and integration with the exa command
antigen bundle zpm-zsh/ls
# enable auto-suggestions as you type based on history
antigen bundle zsh-users/zsh-autosuggestions
# add auto-completions for popular tools like nvm, bundle, etc.
antigen bundle zsh-users/zsh-completions
# syntax highlighting for commands: green when it exists, red otherwise.
antigen bundle zsh-users/zsh-syntax-highlighting
# fuzzy search while typing
antigen bundle zsh-users/zsh-history-substring-search |

Set up keys for fuzzy search

The zsh-history-substring-search plugin requires an additional configuration after antigen has been applied, so, open the ~/.zshrc file and add the following lines after antigen init:

| typeset -g -A key

key[Up]="${terminfo[kcuu1]}"
key[Down]="${terminfo[kcud1]}"
[[ -n "${key[Up]}"   ]] && bindkey -- "${key[Up]}"
history-substring-search-up
[[ -n "${key[Down]}" ]] && bindkey -- "${key[Down]}"
history-substring-search-down

What we are doing here is just defining the UP and DOWN arrow keys to be used for the fuzzy search. So, the way this actually works is that you enter some text on the command line, then if you hit the UP key, it will search the previous command used that contains the typed string. While the DOWN key will let you navigate to the next in the history.

The exa command

Another useful tool I want to talk about briefly is exa. It is basically an improved “ls” command for listing files that offers additional features like git status, human readable file size, icons and colors. Remember the zpm-zsh/ls plugin we installed earlier? Well, it will create “ls” functions using the exa command if available.

Exa is already available in the official repositories of most Linux distributions so we can just install it with the corresponding package manager:

$ apt install exa

Before we continue we need to fix some issues. If you try to run the “ls” command on the terminal it will throw this error:

exa: Option --color has no "tty" setting (choices: always, auto, never)

This is happening because oh-my-zsh, by default, creates aliases for the “ls” command that conflicts with the pm-zsh/ls plugin. To fix this, we need to remove those aliases. The easiest way to do this is to add the following content at the end of the .zshrc file:

# Disabling conflicting oh-my-zsh aliases
unalias ls 2>/dev/null
unalias la 2>/dev/null
unalias ll 2>/dev/null
# ls and ll are functions aliased to use exa by the ls plugin
alias llt='ll --tree'
alias llti='ll --tree --git-ignore'
alias lla='ll -a' 

I also added some useful aliases that I use frequently. If we open a new shell, we can see the new aliases working as expected:

Multiplexing (tmux)

The real power of the terminal comes with this very handy tool that lets us divide the current terminal window into different panes and sessions. Think of it as having tiles inside the same terminal instance that we can easily jump back and forth between them, instead of having several terminal windows scattered all over the screen that we need to manually click and select each of them to see what’s the correct one.

Note: Terminal emulators like iTerm2 already come with some features like split panes, history search, clipboard copy/paste, etc. that are also present on tmux. Since this guide is terminal agnostic, I want to have the same features regardless of the emulator, so it can be used anywhere.

To get started, tmux is available an any major Linux distro as well as Homebrew:

$ sudo apt install tmux  # or brew install tmux

The tmux configuration is very extensive and it could take hours to go through each one of the options, but I found that this configuration works well out of the box (and comes with a nice status line to boot!) and pretty much skips the entire process of configuring tmux manually, saving a lot of time. The previous link shows detailed steps on the installation and features it offers, but in summary you just need to checkout the GitHub repo and copy the configuration files to your home directory:

$ cd
$ git clone https://github.com/gpakosz/.tmux.git
$ ln -s -f .tmux/.tmux.conf
$ cp .tmux/.tmux.conf.local 

Now, to make it work, you need to type tmux on the terminal. If it’s successful, you will see a nice status line in the bottom of your terminal window. To close it, you need to type exit on the prompt and you will return to the previous shell session. But typing tmux and exit every time you open a terminal prompt can become cumbersome really fast. So, we can add an antigen plugin to the ~/.antigenrc file we created earlier to make it open automatically, as well as closing the terminal window when we exit tmux for a seamless experience:

antigen bundle tmux

We also need to set this variable for tmux to auto start/exit on ~/.zshrc:

ZSH_TMUX_AUTOSTART=true
# ZSH_TMUX_AUTOQUIT=true # By default, it's the same value as autostart |

For changes to take effect, you need to log out and log in or just reload the .zshrc file:

$ source ~/.zshrc

Next time you open a terminal window, you will see the tmux status line at the bottom:

If you want it to look like the one from the GitHub repo, you need to install a powerline font:

$ sudo apt install fonts-powerline

Note: On macOS there’s no package for it on the brew repositories. Instead, we need to install manually from GitHub:

git clone https://github.com/powerline/fonts.gitcd fonts./install.sh

After the installation is complete, we can safely remove the repo afterwards:

cd ..
rm -rf fonts

And finally, we need to make the following changes on the ~/.tmux.cong.local file. There is a shortcut to edit this file by pressing the tmux prefix ( Ctrl + a ) then e. It will open it on your default editor (vi/vim/nano) and will source the file automatically upon exit:

Basically, commenting the default left/right separators and uncommenting the powerline ones. Before closing it, we can enable additional features:

  • Start with mouse mode enabled:
set -g mouse on
  • Increase history buffer size:
set -g history-limit 10000
  • Disable confirmation when closing panes and windows
# disable prompt confirmation
bind-key & kill-window
bind-key x kill-pane
  • Enable copy-to-clipboard on selection:
tmux_conf_copy_to_os_clipboard=true  # Default false

You will also need to install xclip to get this to work:

$ sudo apt install xclip

After that, you will see the updated status line:

Here’s a quick breakdown of the status line:

  1. Name of the current tmux session (defaults to 0). If you open another terminal window, it will be 1, then 2, and so on.
  2. Time the session has been open. It will usually reset after a restart or logout.
  3. Active tabs. The current tab will show as blue, while the rest are shown in gray.
  4. Status icons. It will show when the mouse is enabled, a keyboard when prefix is pressed (Ctrl + a) and other icons whether your laptop is charging or on battery.
  5. Current date and time.
  6. Current user and network name of the device.

We can disable some of those options if we don’t need them or add new ones like CPU stats, weather, etc. on the ~/.tmux.conf.local file.

Quick tmux tutorial

Tmux is all about keyboard shortcuts and to execute any action you need to first press the “prefix” shortcut. The default one is Ctrl + b, but there’s also an alternative on this config, Ctrl + a which I prefer since it’s easier to press. With this configuration both options are valid, so you can use whichever one suits you. You will see a keyboard icon on the status line when the prefix was pressed.

The most important actions are opening panes and tabs. 

  • To create a tab inside the same terminal window, you need to press prefix c which means Ctrl + a then c.
  • To create panes in the current tab you need to press prefix - to divide it horizontally or prefix _ to divide it vertically.
  • All panes can be divided into more panes vertically or horizontally.

To close panes just press Ctrl + d.

Other useful notes:

  • prefix Ctrl + lnavigates between tabs. Note that for this shortcut you can hold Ctrl then press a (for the prefix), and while still holding Ctrl you can press l so it’s easier to memorize.
  • While in the prefix mode, you can navigate panes with the arrow keys.
  • prefix Ctrl + <arrow_key> resizes the current pane in the arrow direction. You can quickly press the same arrow key several times while holding the Ctrl key.
  • You can use the mouse to navigate and resize the panes instead of the keys.
  • Pressing prefix Ctrl + <arrow_key> will make the cursor jump to the next pane that’s in the arrow direction. Note that if you are still holding Ctrl after pressing the prefix will instead resize the pane, but letting go of Ctrl and then pressing an arrow key will jump to the next pane.
  • Selecting text with the mouse automatically copies the content into the clipboard (if you have xclip installed and the option enabled on the tmux config).
  • Pressing prefix z will maximize the selected pane, pressing again will return back to normal.
  • There are a lot more other features you can check up on gpakosz’s github repo.

Closing thoughts

It can be very daunting and time consuming to play around with all the options that oh-my-zsh and tmux offers. But, with as little configuration as possible, now you have a fully featured terminal with nice aesthetics that you can tell, by a simple glance, what’s going on in the screen without having to carefully read the text as if it were just white text on black background. It can take some time to get used to the new shortcuts and features, but when you do, you will realize that all the efforts were worth it and you'll no longer want to get back to the plain old bash shell.

For the sake of completeness, here you can find the final files used in this tutorial.

The next part of the tutorial will focus on managing your configurations (dotfiles) and how to reduce the configuration bloat through the use of the fish shell and custom scripts, since most of the functions are already built-in.

Published on: Feb. 27, 2023

Written by:


Martin Mena

Martin Mena