Hello and welcome to my first blog post (we’re not counting posts further than 15 years in the past 😉). As a software developer I spend a considerable amount of time on the command-line in my terminal emulator. In this post we are going to take the plain old default terminal setup you get with macOS to a beautiful and more functional terminal setup. We’re assuming our starting point is a fresh install of macOS Sonoma.
Enough prolog, let’s dive right into it!
Accompanying YouTube Video
I made a YouTube video in which I take you through all the steps of this blog post and also demonstrate some of the cool functionality you get. Feel free to watch it and leave me a comment, if you want to.
Installing Homebrew
To install the Terminal app, the font and some other tools, we’re going to use a package manager. Homebrew is a very popular package manager for macOS. Installation is very easy. We just open a terminal emulator and paste the command below into it and start the installation by pressing “return”. macOS comes with a pre-installed terminal emulator, that listens to the really simple but extremely fitting name: “Terminal.app”.
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
We’ll be prompted for our password during installation. Don’t worry, if you see nothing happening, while typing in your password. It’s very common on the command-line to not show any kind of feedback, during password dialogs. Also, we will have to confirm the installation of the “Xcode Command Line Tools”, if you haven’t installed them already. Depending on the speed of your computer and your internet connection, this can take a few (or many) minutes.
To add Homebrew to your PATH, every time you startup your shell we do the following:
echo >> "$HOME/.zprofile"
echo 'eval "$(/opt/homebrew/bin/brew shellenv)"') >> "$HOME/.zprofile"
eval "$(/opt/homebrew/bin/brew shellenv)"
Now we are ready to run Homebrew’s command-line interface brew
.
After the installation is finished, the first thing I always do, is to turn of Homebrew’s analytics:
brew analytics off
You can of course leave them enabled, if you want to.
At this point, we should have a fully functioning Homebrew installation. Yay, congratulations! From now on, we can easily install all kinds of software using the brew
command. And that’s exactly what we’re going to do to level up our terminal setup.
Installing WezTerm
That’s where the foundation of our command-line setup comes into play: a better terminal emulator. There are quite a few possible candidates: the tried and true iTerm2 or some more modern and very popular alternatives like Alacritty or kitty. There’s also the new kid on the block: Ghostty written in Zig. It is developed by Mitchell Hashimoto, a co-founder of HashiCorp. I really want to try this out, but as the time of writing Ghostty is still in private beta and unfortunately I’ didn’t score an invite, yet. We’ll probably take it for a spin in the near future. Stay tuned for it!
But there’s no need to be upset. We will use the awesome WezTerm as our new terminal emulator. WezTerm is a fast, GPU-accelerated powerful cross-platform terminal emulator that runs on macOS, but also on Linux, FreeBSD and even Windows. It is written in Rust and boasts cool and super-useful features like a built-in terminal multiplexer, support for ligatures, a searchable scrollback just to name a few. It even supports multiple image protocols. It features relatively sane keybindings out of the box, is highly configurable via a Lua configuration file and even offers hot reloading of config changes. It’s a great piece of kit!
Enough praise for WezTerm. We’re going to put Homebrew to good use for the first time now and install WezTerm right from our current terminal. Run the following command:
brew install --cask wezterm
After the installation is finished we can finally close Terminal.app and start our shiny new terminal emulator. So let’s launch WezTerm to go on with the setup.
As a security measurement macOS wants us to confirm, that we really want to open WezTerm. We sure do, and so we confidently click on the “Open” button. Time to enjoy using your new terminal emulator!
You might think: “This doesn’t look much better than Terminal.app after all…” and I would totally agree with you. But WezTerm is very customizable. Let’s start configuring it. But first we are going to install the font we want to use in our setup.
Installing JetBrains Mono Nerd Font
Let’s leverage Homebrew again. A quick brew install --cask font-jetbrains-mono-nerd-font
and we’re ready to use our newly installed font.
Configuring WezTerm
WezTerm is configured using a Lua configuration File. We’ll create this file at ~/.config/wezterm/wezterm.lua
. Here’s what I have in my config with some comments for further explanation:
-- Helper function:
-- returns color scheme dependant on operating system theme setting (dark/light)
local function color_scheme_for_appearance(appearance)
if appearance:find "Dark" then
return "Tokyo Night"
else
return "Tokyo Night Light (Gogh)"
end
end
-- Pull in WezTerm API
local wezterm = require 'wezterm'
-- Initialize actual config
local config = {}
if wezterm.config_builder then
config = wezterm.config_builder()
end
-- Appearance
config.font = wezterm.font 'JetBrainsMono Nerd Font'
config.font_size = 14.0
config.color_scheme = color_scheme_for_appearance(wezterm.gui.get_appearance())
config.window_decorations = "RESIZE"
config.hide_tab_bar_if_only_one_tab = true
config.native_macos_fullscreen_mode = false
-- Keybindings
config.keys = {
-- Default QuickSelect keybind (CTRL-SHIFT-Space) gets captured by something
-- else on my system
{
key = 'A',
mods = 'CTRL|SHIFT',
action = wezterm.action.QuickSelect,
},
}
-- Return config to WezTerm
return config
This config is relatively small, because I like most of WezTerm’s default keybindings and settings. For those shiny icons in the terminal prompt, we use JetBrains Mono
in the patched Nerd Font
version, which we installed before with font size 14. This is currently my favorite monospace font. You can of course install any other Nerd Font and use that, if you want to. A quick
brew search --cask nerd
will give you a list of installable fonts that you can easily install with the brew
command.
I just have set up the beautiful color scheme Tokyo Night and it’s light counterpart, respectively. Configured like this, WezTerm dynamically switches between the light and dark themes, depending on the theme setting on the operating system level. So if I switch between Dark
and Light
in macOS’ Appearance settings, Wezterm’s theme automatically switches, too. I often use this feature during changing lighting conditions. When it’s really bright and the sun is shining, I switch to Light
mode and when it gets a little bit more gloomy, I prefer the Dark
setting.
We remove the default window decorations but are keeping the window resizable with the value RESIZE
for the window_decorations
setting and hide the tab bar, if we only have one tab open. Also we don’t want to use macOS’ native fullscreen mode.
WezTerm in Action
I want to show you a few of WezTerm’s features. I use these all the time and find them very useful.
Splitting Windows
WezTerm enables you to split your terminal windows. When you open a new WezTerm window it contains exactly one pane, that takes up all of the available space inside the window. You can then split this pane into smaller panes, either horizontally or vertically. These newly created panes can then be split times and times again. WezTerm’s default keybinds for splitting are the following:
ALT-CTRL-SHIFT-"
: Splits pane verticalALT-CTRL-SHIFT-%
: Splits pane horizontalCTRL-SHIFT-Z
: Toggles pane’s zoom state, which means you can toggle the pane between taking up the complete window or just being it’s actual sizeCTRL-SHIFT-LeftArrow/DownArrow/UpArrow/RightArrow
: Switches focus to from currently active pane to pane in given directionALT-CTRL-SHIFT-LeftArrow/DownArrow/UpArrow/RightArrow
: Resizes the currently active pane in the given direction
Quick Select Mode
Quick Select mode let’s you quickly highlight text in your terminal, that matches commonly copied patterns and prefixes them with a prefix of one or two characters. Typing these characters copies the corresponding text into your clipboard.
To see how this looks in practice, I encourage you to take a look at the YouTube video I made related to this blog post or visit WezTerm’s official documentation on Quick Select Mode. A quick summary of the default shortcuts:
CTRL-SHIFT-Space
: Activate Quick Select Mode (I’ve bound this toCTRL-SHIFT-A
in our config file earlier).character-prefix
: Copy corresponding highlighted patternESC
: Deactivate Quick Select Mode
Copy Mode
Copy mode enables you to select and copy text to the clipboard all while just using your keyboard. Some relevant default keybindings are:
CTRL-SHIFT-X
Activate CopyMode in CopyModeEsc
exits CopyModeh
,j
,k
,l
orLeftArrow
,DownArrow
,UpArrow
,RightArrow
, to move around by characterw
,e
,b
to move by word- Other Vim motion keybinds to move around like
CTRL-U
orCTRL-D
- Toggle selection modes, like visual modes in vim
v
,SHIFT-V
,CTRL-V
, - Move to other ends of selection:
o
,SHIFT-O
y
to copy to system clipboard
The full list of default keybinds can be found in WezTerm’s official documentation on Copy Mode or you can of course create your own keybinds.
Installing Zsh Plugins Using Homebrew
We’ll just install two plugins, that I think are essential. These are zsh-autosuggestions and zsh-syntax-highlighting. We’re not even going to use a special plugin manager for Zsh. Instead we’re using Homebrew again to install the plugins:
brew install zsh-autosuggestions zsh-syntax-highlighting
Then we’ll add the following lines to the end of our .zshrc
:
source /opt/homebrew/share/zsh-autosuggestions/zsh-autosuggestions.zsh
source /opt/homebrew/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh
After that we have to restart WezTerm or we can manually source ~/.zshrc
to activate the plugins.
[!NOTE] If you receive the “highlighters directory not found” error message, you may need to add the following to your ~/.zshenv:
export ZSH_HIGHLIGHT_HIGHLIGHTERS_DIR=/opt/homebrew/share/zsh-syntax-highlighting/highlighters
Installing Starship
To enhance our terminal experience even further, we need a better prompt. Starship is a really fast and very customizable shell prompt, that works on most common shells and operating systems. It is written in Rust and comes with a nice default configuration. To install it we once again use our trusty friend Homebrew and cast the following spell:
brew install starship
After installing Starship, we need to add following line to the end of our .zshrc
:
eval "$(starship init zsh)"
Now just restart your Terminal and you have your new prompt! To see Starship in action, I shamelessly point you to the related YouTube video I made again.
Installing eza
To finish up for today, we are going to replace the good old ls
command with a modern alternative called eza. You probably know the drill by now:
brew install eza
That’s all you really have to do, to now use eza
. I like to add a few aliases to my .zshrc
, to keep using the muscle memory I built up over the years and effortlessly use of the icons and built-in tree-functionality:
# eza (better `ls`)
alias l="eza --icons"
alias ls="eza --icons"
alias ll="eza -lg --icons"
alias la="eza -lag --icons"
alias lt="eza -lTg --icons"
alias lt1="eza -lTg --level=1 --icons"
alias lt2="eza -lTg --level=2 --icons"
alias lt3="eza -lTg --level=3 --icons"
alias lta="eza -lTag --icons"
alias lta1="eza -lTag --level=1 --icons"
alias lta2="eza -lTag --level=2 --icons"
alias lta3="eza -lTag --level=3 --icons"
Where To Go From Here
This was just the tip of the iceberg. We barely scratched the surface of everything that’s possible in the terminal.
fzf is a powerful and very flexible fuzzy finder for the command-line. zoxide, bat and fd are just a few examples of modern replacements for standard command-line tools like ls
, cat
and find
.
There are terminal multiplexers out there, that are independent of the terminal emulator you use.tmux is probably the most popular, but there’s also zellij written in Rust that is gaining more followers. You could also take a look at good old GNU Screen.
Cool TUIs) like lazygit or the awesome terminal JSON viewer fx can really make your work easier and more enjoyable.
And then there’s Neovim, a Vim-fork, that is very extensible with plugins written in Lua and can be configured to exactly match your needs.
I will be posting more content about some of those things. I hope you enjoyed this little journey and we’ll meet again, soon.