A comprehensive dotfile configuration for Linux featuring a Hyprland Wayland desktop (waybar, kitty, wofi), Neovim, Tmux, and Zsh with Oh My Zsh. Uses GNU Stow for symlinking and a one-shot, distro-aware installer that also pulls in every system package.
- Prerequisites
- Quick Start
- Desktop (Hyprland)
- Setup Instructions
- Reference Guide
- Custom Keymaps
- Plugin Configuration
- Tmux Configuration
- Getting Help
- Plugin Management
- External Tools
Just git and a supported distro. The installer bootstraps everything else
(GNU Stow, zsh, neovim, tmux, the Hyprland desktop stack, fonts, oh-my-zsh,
oh-my-posh) through your package manager.
Supported distros: Fedora (dnf — fully verified) and Debian/Ubuntu
(apt — best-effort; the Hyprland ecosystem needs a recent release, see
packages/debian.txt).
git clone --recursive https://github.com/Sean-Leishman/dotfiles.git
cd dotfiles
./install.shThe Neovim config is a git submodule (Sean-Leishman/nvim), so clone with
--recursive. Already cloned without it? Rungit submodule update --init --recursive(the installer also does this for you).
That single command, on a fresh machine:
- Detects your distro and installs everything in
packages/<distro>.txt. - Refreshes the font cache (waybar's Nerd Font icons).
- Installs oh-my-zsh + zsh plugins + oh-my-posh (skipped if already present).
- Backs up any pre-existing real dotfiles to
~/.dotfiles-backup-<timestamp>/, then symlinks every package into$HOMEwith GNU Stow.
It is idempotent — safe to re-run. Afterwards:
chsh -s "$(command -v zsh)", log out, and pick the Hyprland session (or
run Hyprland from a TTY).
| Path | Purpose |
|---|---|
install.sh |
one-shot bootstrap: distro-detect → packages → fonts → shells → stow |
packages/fedora.txt |
dnf package list (verified on Fedora 44) |
packages/debian.txt |
apt package list (best-effort) |
<pkg>/ |
a GNU Stow package whose tree mirrors $HOME |
Stow only a subset by overriding the package list (comma-separated):
STOW_FOLDERS=bash,hypr,waybar ./install.shPersonal scripts: drop executables in bin/.local/scripts/ — once bin is
stowed they land on $PATH via ~/.local/scripts.
A Wayland desktop on Hyprland, using the new Lua config format
(hypr/.config/hypr/hyprland.lua):
- Compositor: Hyprland · hyprpaper (wallpaper) · hyprpolkitagent · xdg-desktop-portal-hyprland
- Bar: waybar — Embark theme, Cascadia Code NF font, verified Nerd Font icons (
waybar/.config/waybar/) - Launcher / terminal / files: wofi · kitty · Thunar
- Notifications: dunst
No-nest launch wrapper: bash/.bash_profile defines a Hyprland()
function that starts the compositor with a deliberately invalid
WAYLAND_DISPLAY. When another compositor (e.g. GNOME) is running on another
VT, this makes Hyprland's nested-backend probe fail so it comes up DRM-only on
the real panel instead of also rendering a phantom output into the other
session. Hyprland then exports its own WAYLAND_DISPLAY for child apps.
./install.sh handles the steps below automatically. They're documented here
for reference / manual setup.
Neovim is installed by the package step, and its config is the
Sean-Leishman/nvim submodule (lazy.nvim,
pinned via lazy-lock.json). Plugins install themselves on first launch — just
open nvim. To work on the config, edit inside nvim/.config/nvim/ (it's a
submodule, so commit/push there, then bump the pointer in this repo).
Installed automatically (idempotently) by install.sh. Manual equivalent:
sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"- Normal mode - Navigate and manipulate text
- Insert mode - Type and edit text
- Visual mode - Select text
| Key | Action |
|---|---|
i |
Insert before cursor |
I |
Insert at beginning of line |
a |
Insert after cursor |
A |
Insert at end of line |
o |
New line below and insert |
O |
New line above and insert |
| Key | Action |
|---|---|
v |
Character-wise visual |
V |
Line-wise visual |
<C-v> |
Block visual |
| Key | Action |
|---|---|
h j k l |
Left, down, up, right |
w |
Next word start |
b |
Previous word start |
e |
End of word |
9 |
Beginning of line (remapped from 0) |
0 |
End of line (remapped from $) |
gg |
File start |
G |
File end |
<C-d> |
Scroll down half page |
<C-u> |
Scroll up half page |
{ |
Previous paragraph |
} |
Next paragraph |
| Command | Action |
|---|---|
ci{ |
Change inside braces |
ca( |
Change around parentheses |
di" |
Delete inside quotes |
da' |
Delete around single quotes |
yt{ |
Yank until next { |
dt' |
Delete until next ' |
| Key | Action |
|---|---|
x |
Delete character |
d |
Delete (combine with motions) |
y |
Yank/copy (combine with motions) |
p |
Paste after |
P |
Paste before |
u |
Undo |
<C-r> |
Redo |
/{pattern} " Search forward
?{pattern} " Search backward
n " Next match
N " Previous match
* " Search word under cursor forward
# " Search word under cursor backward:%s/{search}/{replace}/g " Replace all in file
:%s/{search}/{replace}/gc " Replace all with confirmation
:{start},{end}s/{search}/{replace}/g " Replace in rangeOur configuration includes these search enhancements:
set ignorecase smartcase " Smart case sensitivity
set incsearch hlsearch " Incremental search with highlightingClear search highlighting: <leader><CR>
:r {filename} " Insert file contents
:r !{command} " Insert command output
<leader>ps " Project-wide search (grep)| Key | Action |
|---|---|
gV |
Reselect last visual selection |
Y |
Yank to end of line |
<leader><leader> |
Switch between last two buffers |
<leader><CR> |
Clear search highlighting |
| Key | Action |
|---|---|
<leader>pf |
Fuzzy find files |
<leader>gf |
Find Git tracked files |
| Key | Action |
|---|---|
<leader>a |
Add file to Harpoon |
<C-h> <C-t> <C-n> <C-s> |
Navigate marked files |
<C-e> |
Open Harpoon quick menu |
| Command | Action |
|---|---|
cs"' |
Change " to ' |
cs({ |
Change ( to { |
ds' |
Delete surrounding ' |
ysiw] |
Surround word with [] |
yss" |
Surround line with "" |
| Key | Action |
|---|---|
<leader>u |
Toggle undo tree |
| Key | Action |
|---|---|
gd |
Go to definition |
gD |
Go to declaration |
gi |
Go to implementation |
go |
Go to type definition |
gr |
List references |
K |
Show documentation |
gs |
Show signature help |
<F2> |
Rename symbol |
<F3> |
Format buffer |
gl |
Show diagnostics |
[d ]d |
Navigate diagnostics |
| Key | Action |
|---|---|
<C-y> |
Accept completion |
<C-e> |
Cancel completion |
<Up> <Down> |
Navigate completions |
| Key | Action |
|---|---|
<C-y> |
Accept suggestion |
<C-]> |
Dismiss suggestion |
<M-[> <M-]> |
Cycle suggestions |
<M-Right> |
Accept next word |
<M-C-Right> |
Accept next line |
- Prefix key:
Ctrl-a(instead of defaultCtrl-b) - Escape time: Instant key registration
- New windows: Open in current path
- Auto-renumber: Windows renumber after closing
- History: 10,000 line scrollback buffer
# Sessions
tmux new -s session_name # Create named session
tmux attach -t session_name # Attach to session
tmux list-sessions # List sessions
# Windows & Panes
Ctrl-a c # New window
Ctrl-a % # Split vertically
Ctrl-a " # Split horizontally
Ctrl-a [0-9] # Switch to window number| Type | Prefix | Example |
|---|---|---|
| Normal mode | (none) | :help x |
| Visual mode | v_ |
:help v_u |
| Insert mode | i_ |
:help i_META |
| Command-line | : |
:help :quit |
| Options | ' |
:help 'textwidth' |
:LspInstall {server} " Install LSP server
:Mason " Open Mason package manager
:Copilot " Copilot commandsPlugins are managed with Packer. After making changes:
- Source the config:
:so - Sync plugins:
:PackerSync
ps aux | fzf # Search processes with fuzzy finding