Skip to content

Configuration for Alacritty, tmux, Zsh, Neovim, and various other tools

Notifications You must be signed in to change notification settings

adgoudz/dotfiles

Repository files navigation

Environment

Overview

This project exists for personal reasons, but occasionally I'm asked how I configure my development environment. I use these dotfiles to quickly set up my environment and achieve feature parity on different Unix-like operating systems.

Dotfile Management

Using this Repository

Tools & Configuration

Dotfile Management

The developer community offers several dotfile managers and other great ideas for how to manage dotfiles. While I'm biased toward my strategy, feel free to ignore this if some other system is going to level up your productivity (xkcd #1205 outlines my favorite approach to measuring this).

Assuming I have a package manager installed (either Homebrew or a well-supported native option), the first tools I install are:

  • GNU Stow
  • Git (if necessary)

Stow answers the question of how to expose this configuration to various tools after cloning this repository. Familiarity with package managers and Git is assumed, but both have excellent documentation for anyone just getting started.

I chose Stow based on these requirements:

  1. The tool should be easy to bootstrap on popular Unix-like operating systems
    As a GNU tool, Stow is consistently available with package managers. It's also easy to install from source if necessary (it's just a Perl module).

  2. The learning curve for the tool should be shallow
    Stow follows the Unix philosophy of doing one thing and doing it well, so it's easy to master.

  3. Configuration for the tool should be optional, not required
    My Stow configuration is limited to ignore lists and resource files, both of which are optional.

  4. The tool should support managing dotfiles for multiple hosts and environments
    I'll talk about how Stow can support this under Environment-Specific Configuration.

GNU Stow

Stow was created to solve a problem unrelated to dotfile management:

Stow addresses the need to administer, upgrade, install, and remove files in independent software packages without confusing them with other files sharing the same file system space.

More specifically, it lets you install Perl into a directory like /usr/local/stow/perl and create symlinks that make it appear as if its files were installed under these directories:

/usr/local
├── bin                  # Executable binaries
├── lib                  # Libraries
└── man                  # Man(ual) pages

This aligns to the Filesystem Hierarchy Standard and makes it easier for other tools to find the Perl installation (e.g., man perlrun).

If you wanted to uninstall a tool that was automatically installed in these directories, you'd traditionally need to remove each file manually, assuming you knew which files needed to be removed. You might've had access to a make target that did this for you if you were lucky. Stow, however, can remove its symbolic links and completely uninstall Perl with a single command.

Today it is less common to install software this way, given the wide availability of mature package managers. Dotfile management is primarily about managing symlinks, however, and Stow handles this well.

Usage

Let's say we wanted to share a Git global ignore file across multiple development hosts. We'd first create an ignore file in the following directory structure below our home directory. Stow refers to some of these directories by logical names:

/Users/Andrew            # The "target" directory
└── dotfiles             # The "stow" directory
    └── git              # A "package" directory
        └── .config
            └── git
                └── ignore

The physical names of the stow and package directories are flexible. However, the name of the stow directory will typically match the name of your Git repository, and I choose to organize package directories by the tools I'm configuring.

Next, we can use a single Stow command to expose this file to Git. The git argument for this command refers to the package directory and the -v option allows us to see what Stow is doing:

~/dotfiles $ stow -v git
LINK: .config/git => ../dotfiles/git/.config/git

You can see that Stow creates one symlink to mirror the contents of the git package directory within our target directory (two levels higher). This is exactly where Git expects to find the global ignore file:

/Users/Andrew            # The "target" directory
└── .config
    └── git -> ../../dotfiles/git/.config/git

Stow is powerful enough to work with existing directories in the target directory (e.g., .config) and even manages symlinks that overlap with other package directories. This concept is referred to as tree folding, which you can read about in the documentation.

Stow can create symlinks in any target directory using the -t option, including grandparent or sibling directories. This gives us the flexibility to locate our dotfiles directory somewhere else in the file system, including directories within other stow directories (more on this below).

Using This Repository

This repository uses a few Git submodules and they need to be initialized after cloning:

~/dotfiles $ git submodule update --recursive --init

I also use a Stow resource file to implicitly set my target directory for stow commands, which makes it easier to work with nested stow directories. Before running any other commands in this repository, I effectively set up Stow using Stow:

/Users/Andrew/dotfiles/local/home/macos $ stow -vt /Users/Andrew stow
LINK: .stowrc => dotfiles/local/home/macos/stow/.stowrc

If you're forking this repository, .stowrc should be modified to refer to your target directory.

Environment-Specific Configuration

The directory structure of this repository resembles the following:

.
├── tool-a               #
├── tool-b               # Multiple package directories
├── tool-c               #
│
├── local
│   ├── home
│   │   ├── macos        # A nested stow directory for MacOS packages
│   │   │   ├── tool-a
│   │   │   ├── tool-b
│   │   │   └── stow
│   │   └── ubuntu       # A nested stow directory for Ubuntu packages
│   │       ├── tool-a
│   │       └── stow
│   └── work
│       └── centos       # A nested stow directory for CentOS packages
│           ├── tool-a
│           └── stow
│
└── etc                  # An ignored directory for location-agnostic configuration

By using nested stow directories, I'm able to layer configurations based on my current environment or host. I prefer to use separate directories for my personal work and my day job, but any system can be used here.

Using Git as an example again, I maintain a global .gitconfig file that I use in all of my environments and a host-specific file that my .gitconfig includes via the include.path directive. I've named the latter gitconfig.inc.

Git expects this global file to be located in the home directory, so I've added it to the Git package with the global ignore file that I introduced above:

.                        # The top-level stow directory
└── git                  # The package directory for git
    ├── .config
    │   └── git
    │       └── ignore   # The global ignore file I introduced earlier
    └── .gitconfig

The following command creates the appropriate link to my .gitconfig, in addition to creating a link to the directory containing the global ignore file:

~/dotfiles $ stow -v git
LINK: .gitconfig => ../dotfiles/git/.gitconfig
LINK: .config/git => ../dotfiles/git/.config/git

Next, gitconfig.inc is located in a package under local/home/macos, and I've chosen to symlink it in .config/git with Git's other configuration:

local/home/macos         # The nested stow directory
└── git                  # A MacOS-specific package directory for git
    └── .config
        └── git
            └── gitconfig.inc

To create the appropriate link to this file, I cd to the nested stow directory and repeat the stow command above. Remember that a Stow resource file implicitly sets the target directory to my home directory:

~/dotfiles/local/home/macos $ stow -v git
UNLINK: .config/git
MKDIR: .config/git
LINK: .config/git/ignore => ../../dotfiles/git/.config/git/ignore
LINK: .config/git/gitconfig.inc => ../../dotfiles/local/home/macos/git/.config/git/gitconfig.inc

The resulting directory tree will look like this:

/Users/Andrew            # The "target" directory
└── .config
    └── git
        ├── ignore -> ../../dotfiles/git/.config/git/ignore
        └── gitconfig.inc -> ../../dotfiles/local/home/macos/git/.config/git/gitconfig.inc

You might notice that Stow replaces the .config/git symlink created in the first step with a directory, and then symlinks the individual files from both the top-level package and the nested package. This is automatic when Stow recognizes the original symlink, which is made possible by including an empty .stow file in each stow directory (see Configuring Stow below).

Alternative Layout

Local configuration can also be organized under a single package:

local/home               # The nested stow directory
└── macos                # A package directory for all configuraton used on MacOS
    └── .config
        ├── git
        └── zsh

This reduces the installation of local configuration to a single command:

~/dotfiles/local/home $ stow -v macos

It's also possible to write a script that simplifies the process of stowing local packages. I set up new environments so infrequently, however, that I don't mind running stow for a small number of local packages.

Encryption

Stow doesn't address the need to maintain private keys or other secrets. One option is to encrypt them manually with PGP, commit them, and then decrypt them when setting up a new host. However, this assumes that the PGP keys are manually copied to each host.

Stow's lack of support for encryption is a trade-off between simplicity and comprehensive functionality (see my requirements at the start of this README).

Configuring Stow

The following Stow-specific files are used in this repository:

  • ./<package>/.stow-local-ignore

    This ignore list is required when a package directory contains files that shouldn't be symlinked. It uses the Perl regular expression syntax.

  • ./local/<stow-directory>/stow/.stowrc

    This resource file makes it possible to define default command-line options (e.g., the target directory).

  • .stow, ./local/<stow-directory>/.stow

    These empty files help Stow work with multiple stow directories.

Tools & Configuration

The remainder of this README covers the software I use most and their corresponding configuration files. I use brew to install almost everything on both MacOS and Linux-based hosts.

Note that my configuration is very opinionated and I've written most of it from scratch to fit my needs (with plenty of ideas borrowed from the community). While everything should just work, it's probably only useful as an example and I didn't write it to be copied as-is.

Terminal

alacritty/alacritty
Alacritty is a fast terminal emulator. It's also very simple (to a fault, some might say), so those who expect support for window tabs and other basic functionality may find it harder to use.

tmux/tmux
Alacritty eschews tabs in favor of pairing the emulator with tmux, which multiplexes a single terminal to simulate panes and windows. There's a learning curve for tmux, but it allows me to use a consistent terminal environment across most emulators (along with a few other nice features).

gnachman/iterm2
In the off-chance I'm unable to run Alacritty, I've backed up some iTerm2 configuration that closely resembles my Alacritty settings.

Configuration

Plugins

tmux-plugins/tpm
TPM is the standard plugin manager for tmux. I currently use it for:

  • tmux-plugins/tmux-resurrect
    This lets you recreate an entire Tmux session after a restart, including windows, current directories, and even Neovim sessions (see vim-obsession under Editor).

  • christoomey/vim-tmux-navigator
    This works together with a Neovim plugin to enable moving between Neovim and tmux windows with the same keyboard shortcuts. I'll talk more about this below.

Shell

zsh-users/zsh
Z Shell (Zsh) was a gateway drug of sorts for a generation of command-line users. It provides a programming language like Bash with features like tab completion and themeable prompts, transforming a command line into a powerful editor. The cool kids might be using fish, but I like Zsh for its active development community and its similarities to POSIX shells.

sorin-ionescu/prezto
One of the most popular projects on GitHub is a configuration and plugin manager called Oh My Zsh (OMZ). I used OMZ for a few years before I ultimately dropped it for Prezto, which was created after its author couldn't convince Robby Russell to simplify the framework. While the Prezto community is significantly less active than OMZ's, my command prompt loads more quickly with Prezto.

Configuration

Usage Global Script Local Script
Environment variables for all shells Not used .zshenv
Configuration for login shells (includes $path) .zprofile .config/zsh/zprofile.inc
Configuration for interactive shells .zshrc .config/zsh/zshrc.inc
Prezto configuration .zpreztorc Not used

See the Prezto documentation and chapter 2 of the Zsh guide for an explanation of these files.

Editor

neovim/neovim
Neovim began as a fork of Vim in 2014 with a faster plugin system, a built-in terminal emulator, and many other features. I'll only use Vim if I'm on a host where I can't install Neovim, but since this happens often when I log in to remote servers, my Neovim configuration is backwards-compatible with Vim. My configuration will also apply Neovim's defaults in Vim so that the editing behavior is identical between the two.

Configuration

If you're viewing .vimrc in Neovim, use zo and zc in normal mode to open and close folds.

Plugins

junegunn/vim-plug
vim-plug is one of several good options for plugin management with support for both Neovim and Vim. My preferred plugins are installed in my .vimrc, the most important of which are:

  • vim-airline/vim-airline
    This provides visual cues and context-specific information in Neovim's status line. See Themes below.

  • tpope/vim-obsession
    This wraps Neovim's :mksession to transparently save windows, tabs, and buffers. By pairing this with tmux-resurrect, you can automatically restore your editors when you restore your tmux session.

  • christoomey/vim-tmux-navigator
    As mentioned above, this works together with a set of tmux key bindings to enable moving between Neovim and tmux windows with the same keyboard shortcuts.

Themes

Theme in normal mode Theme in command mode Theme in insert mode Theme in replace mode Theme in visual-line mode

I use custom themes for tmux, Zsh, and Neovim, inspired by Powerline (a collection of status line plugins written in Python) and powerlevel10k (a Zsh theme). My theme for Neovim was created for the vim-airline plugin and my prompt theme was created for Prezto.

prompt-shadow

While Powerline and powerlevel10k are both powerful and extensible, I prefer not to use them for a few reasons:

  • Powerline didn't support Neovim at the time I switched from Vim. Powerline is also a heavyweight framework that requires background Python processes, and I've found vim-airline to be faster and more reliable.

  • powerlevel10k targets the Zsh prompt only. I prefer a minimal prompt theme, so the overhead of another large dependency doesn't seem necessary to me.

Fonts

JetBrains Mono Dark JetBrains Mono Light

The themes above use glyphs (icons) available with Nerd Fonts, a collection of well-known fonts patched with glyphs from Powerline, FontAwesome, and other icon-based fonts. I use JetBrains Mono, however, any font from the collection should be compatible.

Configuration

Each theme is self-contained in the following files:

Tool Configuration
tmux .tmux.conf
Zsh .zprezto/modules/prompt/functions/prompt_andrew_setup (at adgoudz/prezto)
Neovim .vimrc

Color Scheme

prompt-shadow

I use a custom 16-color scheme modeled on Base16 and inspired by Solarized and Tomorrow Night. I've named it "Astra", and while I've adapted it to almost every tool I use, I need to make time to contribute it back to Base16 tinted-theming.

The scheme is configured in each of the following:

Tool Configuration
Alacritty .config/alacritty/alacritty.yml
Neovim .vim/colors/base16-astra.vim
vim-airline .vim/autoload/airline/themes/base16_astra.vim

Other Tools

  • asdf-vm/asdf
    One version manager to rule them all.

  • junegunn/fzf
    A fantastic fuzzy-finder for your file system and almost anything else you can think of.

  • burntsushi/ripgrep
    A regex search tool. Like grep, ag, and pt, but faster.

  • rupa/z
    No more creating aliases for cd-ing into your favorite directories.

  • htop-dev/htop
    An interactive process viewer. Like top, but fancier.

About

Configuration for Alacritty, tmux, Zsh, Neovim, and various other tools

Topics

Resources

Stars

Watchers

Forks