Skip to main content

Setting Up a Modern WSL Development Environment

·1790 words·9 mins
Thorsten Lenzen
Author
Thorsten Lenzen
Coding, Devops and Homelab maniac…

If you’re using Windows Subsystem for Linux (WSL) for development, you might be working with the default bash shell and standard Unix utilities. While functional, there’s a whole ecosystem of modern CLI tools that can dramatically improve your productivity and make your terminal experience more enjoyable.

In this comprehensive guide, I’ll walk you through setting up a modern, efficient WSL development environment. We’ll replace default tools with more powerful alternatives, add intelligent features like fuzzy finding and autosuggestions, and create a workflow that feels fast and intuitive.

Table of Contents
#

  1. Setting up Zsh
  2. Installing Starship Prompt
  3. Adding Neovim
  4. Fuzzy Finding with fzf
  5. Modern CLI Tool Replacements
  6. WSL-Specific Configuration

Setting up Zsh
#

Why Zsh?
#

While bash is ubiquitous and perfectly capable, Zsh (Z Shell) offers enhanced features like better tab completion, spelling correction, and a rich plugin ecosystem. Combined with Oh-My-Zsh, it becomes a powerful foundation for your terminal setup.

Installation
#

First, install Zsh:

sudo apt update
sudo apt install zsh

Next, make Zsh your default shell:

chsh -s $(which zsh)

You’ll need to restart your terminal for this change to take effect. When you open a new terminal, Zsh will greet you with a configuration wizard.

Oh-My-Zsh
#

Oh-My-Zsh is a delightful community-driven framework for managing your Zsh configuration. It comes with thousands of helpful functions, plugins, and themes.

Install it with:

sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"

Essential Plugins
#

Two plugins that I consider essential for any Zsh setup:

zsh-autosuggestions
#

This plugin suggests commands as you type based on your command history. It’s like having autocomplete for your entire terminal history.

Install it:

git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions

Then add it to your plugins list in ~/.zshrc:

plugins=( 
    # other plugins...
    zsh-autosuggestions
)

zsh-syntax-highlighting
#

This plugin provides real-time syntax highlighting for commands as you type them. Valid commands appear in one color, invalid ones in another. It’s a simple visual cue that prevents many typos.

Install it:

git clone https://github.com/zsh-users/zsh-syntax-highlighting.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting

Add it to your plugins list in ~/.zshrc:

plugins=( 
    # other plugins...
    zsh-syntax-highlighting
)

Installing Starship Prompt
#

Starship is a minimal, blazing-fast, and customizable prompt for any shell. It shows you relevant information about your current directory, git status, programming language versions, and more—all in a clean, informative format.

Installation
#

Install Starship with:

sudo curl -sS https://starship.rs/install.sh | sh

Then add this line to the end of your ~/.zshrc:

eval "$(starship init zsh)"

Configuration
#

Create the configuration file:

mkdir -p ~/.config && touch ~/.config/starship.toml

You can customize Starship extensively by editing ~/.config/starship.toml. Check out the Starship documentation for configuration options.

Adding Neovim
#

Neovim is a modern, extensible text editor built on Vim’s foundation. Even if you prefer VS Code or another IDE, having a capable terminal editor is invaluable.

sudo apt-get update
sudo apt-get install neovim

Fuzzy Finding with fzf
#

What is fzf?
#

fzf (fuzzy finder) is a game-changer for command-line productivity. It’s a general-purpose command-line fuzzy finder that lets you quickly search through files, command history, processes, and more. Instead of typing exact paths or scrolling through history, you can type a few characters and instantly filter through thousands of items.

Installation
#

# Clone repo
git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf
# Install fzf
~/.fzf/install

The installer will ask you a few questions about key bindings and shell integration—I recommend saying yes to all of them.

Enhancing fzf with fd
#

By default, fzf uses the find command to search for files. We can supercharge it by using fd, a modern alternative that’s faster and more user-friendly.

Install fd:

sudo apt install fd-find

Add this configuration to your ~/.zshrc:

# -- Use fd instead of fzf --
export FZF_DEFAULT_COMMAND="fdfind --hidden --strip-cwd-prefix --exclude .git"
export FZF_CTRL_T_COMMAND="$FZF_DEFAULT_COMMAND"
export FZF_ALT_C_COMMAND="fdfind --type=d --hidden --strip-cwd-prefix --exclude .git"

# Use fd (https://github.com/sharkdp/fd) for listing path candidates.
# - The first argument to the function ($1) is the base path to start traversal
# - See the source code (completion.{bash,zsh}) for the details.
_fzf_compgen_path() {
  fdfind --hidden --exclude .git . "$1"
}

# Use fd to generate the list for directory completion
_fzf_compgen_dir() {
  fdfind --type=d --hidden --exclude .git . "$1"
}

Using fzf
#

Here are the key combinations you’ll use constantly:

Key CombinationDescription
CTRL-tLook for files and directories
CTRL-rLook through command history
EnterSelect the item
Ctrl-j or Ctrl-n or Down arrowGo down one result
Ctrl-k or Ctrl-p or Up arrowGo up one result
TabMark a result
Shift-TabUnmark a result
cd **TabOpen up fzf to find directory
export **TabLook for env variable to export
unset **TabLook for env variable to unset
unalias **TabLook for alias to unalias
ssh **TabLook for recently visited host names
kill -9 **TabLook for process name to kill to get pid
any command (like nvim or code) + **TabLook for files & directories to complete command

Git Integration with fzf-git
#

If you work with Git (and who doesn’t?), fzf-git adds fuzzy finding to Git operations like switching branches, viewing commits, and more.

Install it:

git clone https://github.com/junegunn/fzf-git.sh.git

Add this to your ~/.zshrc (make sure it comes after the fd configuration):

source ~/fzf-git.sh/fzf-git.sh

fzf-git Key Bindings
#

KeybindDescription
CTRL-GFLook for git files with fzf
CTRL-GBLook for git branches with fzf
CTRL-GTLook for git tags with fzf
CTRL-GRLook for git remotes with fzf
CTRL-GHLook for git commit hashes with fzf
CTRL-GSLook for git stashes with fzf
CTRL-GLLook for git reflogs with fzf
CTRL-GWLook for git worktrees with fzf
CTRL-GELook for git for-each-ref with fzf

Modern CLI Tool Replacements
#

Now let’s replace some traditional Unix utilities with modern, feature-rich alternatives. These tools maintain backward compatibility while adding colors, better formatting, and additional features.

bat (Better cat)
#

bat is a cat clone with syntax highlighting, Git integration, and automatic paging. It makes reading code and log files in the terminal much more pleasant.

Install it:

sudo apt install bat

Note: On Ubuntu/Debian, the command is batcat due to a naming conflict.

Installing a Custom Theme
#

To make bat even better, you can install custom themes. Here’s how to install the popular Tokyo Night theme:

First-time setup—create the themes directory:

mkdir -p "$(bat --config-dir)/themes"

Navigate to it:

cd "$(bat --config-dir)/themes"

Download your chosen theme (must be a .tmTheme file):

curl -O https://raw.githubusercontent.com/folke/tokyonight.nvim/main/extras/sublime/tokyonight_night.tmTheme

Build the cache:

bat cache --build

Finally, configure bat in your ~/.zshrc:

export BAT_THEME=tokyonight_night
alias cat="batcat"

Now when you use cat, you’ll get beautiful syntax highlighting!

delta (Better git diff)
#

Delta provides syntax highlighting and side-by-side diffs for Git. It transforms the standard git diff output into something genuinely pleasant to read.

Download the .deb file from the releases page:

sudo dpkg -i git-delta_0.18.2_arm64.deb

Add this configuration to your ~/.gitconfig:

[core]
    pager = delta

[interactive]
    diffFilter = delta --color-only

[delta]
    navigate = true    # use n and N to move between diff sections
    side-by-side = true

    # delta detects terminal colors automatically; set one of these to disable auto-detection
    # dark = true
    # light = true

[merge]
    conflictstyle = diff3

[diff]
    colorMoved = default

eza (Better ls)
#

eza is a modern replacement for ls with colors, icons, Git integration, and tree views. It makes directory listings much more informative and visually appealing.

Installation
#

First, ensure you have gpg:

sudo apt update
sudo apt install -y gpg

Then install eza:

sudo mkdir -p /etc/apt/keyrings
wget -qO- https://raw.githubusercontent.com/eza-community/eza/main/deb.asc | sudo gpg --dearmor -o /etc/apt/keyrings/gierens.gpg
echo "deb [signed-by=/etc/apt/keyrings/gierens.gpg] http://deb.gierens.de stable main" | sudo tee /etc/apt/sources.list.d/gierens.list
sudo chmod 644 /etc/apt/keyrings/gierens.gpg /etc/apt/sources.list.d/gierens.list
sudo apt update
sudo apt install -y eza

Create an alias in ~/.zshrc:

alias ls="eza --color=always --long --git --all --icons=always --no-time"

Setting Up fzf Previews
#

Now that you have eza and bat installed, let’s combine them with fzf to create rich previews. When you search for files, you’ll see syntax-highlighted previews; when browsing directories, you’ll see their contents.

Add this to your ~/.zshrc:

show_file_or_dir_preview="if [ -d {} ]; then eza --tree --color=always {} | head -200; else bat -n --color=always --line-range :500 {}; fi"

export FZF_CTRL_T_OPTS="--preview '$show_file_or_dir_preview'"
export FZF_ALT_C_OPTS="--preview 'eza --tree --color=always {} | head -200'"

# Advanced customization of fzf options via _fzf_comprun function
# - The first argument to the function is the name of the command.
# - You should make sure to pass the rest of the arguments to fzf.
_fzf_comprun() {
  local command=$1
  shift

  case "$command" in
    cd)           fzf --preview 'eza --tree --color=always {} | head -200' "$@" ;;
    export|unset) fzf --preview "eval 'echo ${}'"         "$@" ;;
    ssh)          fzf --preview 'dig {}'                   "$@" ;;
    *)            fzf --preview "$show_file_or_dir_preview" "$@" ;;
  esac
}

This configuration intelligently shows either file contents or directory trees depending on what you’re previewing.

zoxide (Better cd)
#

zoxide is a smarter cd command that learns your habits. It remembers which directories you use most frequently and lets you jump to them with just a few characters. No more typing out long paths!

Install it:

curl -sSfL https://raw.githubusercontent.com/ajeetdsouza/zoxide/main/install.sh | sh

Add this to the end of your ~/.zshrc:

export PATH=$PATH:/home/toto/.local/bin
eval "$(zoxide init zsh)"
alias cd="z"

After using it for a while, you can jump to frequently-used directories with just z proj instead of cd ~/Documents/projects/my-project.

WSL-Specific Configuration
#

Accessing an SD Card from WSL
#

If you need to access external drives like SD cards from WSL, here’s how to mount them.

Assuming your SD card appears as D: in Windows, first create a mount point:

sudo mkdir /mnt/d

Mount the SD card:

sudo mount -t drvfs D: /mnt/d

Automatic Mounting at Startup
#

To mount automatically when you start your terminal, first configure sudo to not require a password for the mount command:

sudo visudo

Add this line at the end, replacing your_username with your actual username:

your_username ALL=(ALL) NOPASSWD: /bin/mount

Then add this line to your ~/.zshrc:

sudo mount -t drvfs D: /mnt/d

Conclusion
#

You now have a modern, productive WSL development environment! Here’s what we’ve accomplished:

  • Zsh with Oh-My-Zsh: A powerful shell with autosuggestions and syntax highlighting
  • Starship: A beautiful, informative prompt
  • fzf: Fuzzy finding for files, directories, Git operations, and command history
  • Modern CLI tools: bat, delta, eza, and zoxide for an enhanced terminal experience
  • Rich previews: Integrated file and directory previews in fzf

The beauty of this setup is that it’s all modular. You don’t have to adopt everything at once—start with the tools that appeal to you most and gradually add more as you get comfortable.

Next Steps
#

  • Explore Starship configurations to customize your prompt
  • Dive into Oh-My-Zsh plugins—there are hundreds to discover
  • Configure Neovim with modern plugins like LSP support
  • Explore advanced fzf usage and custom scripts
  • Share your dotfiles in a Git repository for easy syncing across machines

Happy coding!