Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ jobs:
nix build --no-link \
.#checks.x86_64-linux.nix-quality \
.#checks.x86_64-linux.lua-format \
.#checks.x86_64-linux.zsh-syntax
.#checks.x86_64-linux.zsh-syntax \
.#checks.x86_64-linux.bash-syntax

- name: Evaluate WSL configuration
run: nix eval --raw '.#nixosConfigurations.nixos-wsl.config.system.build.toplevel.drvPath'
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Local/work-specific configuration files
.zshenv.local
.bashrc.local
git/.config/git/config.local

# Herdr runtime state (written into the symlinked config dir; only config.toml is tracked)
Expand Down
3 changes: 3 additions & 0 deletions bash/.bash_profile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Login shells read this instead of ~/.bashrc, so source ~/.bashrc here to keep
# login and non-login interactive shells identical.
[ -f "$HOME/.bashrc" ] && . "$HOME/.bashrc"
115 changes: 115 additions & 0 deletions bash/.bashrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# Minimal bash configuration, kept as a portable fallback to zsh/.zshrc.
#
# Layout mirrors the zsh config: environment first (so non-interactive login
# shells get PATH too, the job zsh/.zshenv does), interactive-only setup after
# the guard. Login shells reach this file through ~/.bash_profile.

# ---------------------------------------------------------------------------
# Environment (mirrors zsh/.zshenv)
# ---------------------------------------------------------------------------
export EDITOR="nvim"
export VISUAL="nvim"
export DOTFILES="${DOTFILES:-$HOME/dotfiles}"

export PATH="$HOME/.local/bin:$PATH"
export PATH="$HOME/go/bin:$PATH"
# This is required for asdf (0.16 or later)
export PATH="${ASDF_DATA_DIR:-$HOME/.asdf}/shims:$PATH"
# reorder PATH to make sure Nix's home-manager PATH comes before
# system path, so it uses nix installed package first
export PATH="$HOME/.nix-profile/bin:$PATH"

export CLOUDSDK_PYTHON=/usr/bin/python3

# GPG TTY for commit signing. `tty` writes "not a tty" to stdout and fails when
# stdin is not a terminal, so assign only on success and keep any inherited value.
if __tty=$(tty 2>/dev/null); then
export GPG_TTY="$__tty"
fi
unset __tty

# Home Manager session variables, when this machine is managed by Nix.
# The first file sourced sets a guard, so the second is a no-op.
for __hm_vars in \
"$HOME/.nix-profile/etc/profile.d/hm-session-vars.sh" \
"/etc/profiles/per-user/$USER/etc/profile.d/hm-session-vars.sh"; do
[ -r "$__hm_vars" ] && . "$__hm_vars"
done
unset __hm_vars

# ---------------------------------------------------------------------------
# Interactive shells only
# ---------------------------------------------------------------------------
case $- in
*i*) ;;
*) return ;;
esac

# History. mcfly bails out with an error unless the file already exists, so
# create it here rather than waiting for the first shell to exit.
HISTFILE="${HISTFILE:-$HOME/.bash_history}"
[ -e "$HISTFILE" ] || (umask 077 && : > "$HISTFILE")
HISTSIZE=50000
HISTFILESIZE=100000
HISTCONTROL=ignoreboth:erasedups
HISTIGNORE="ls:ll:la:cd:pwd:exit:clear:history"
HISTTIMEFORMAT="%F %T "
shopt -s histappend cmdhist

# Shell behaviour (options unknown to bash 3.2 are skipped quietly)
shopt -s checkwinsize globstar autocd cdspell dirspell no_empty_cmd_completion 2>/dev/null

# vi keybindings, matching the zsh vi-mode plugin
set -o vi
# Keys bash leaves unbound in vi-insert but zsh's viins keymap provides
bind -m vi-insert '"\C-l": clear-screen' 2>/dev/null
bind -m vi-insert '"\C-a": beginning-of-line' 2>/dev/null
bind -m vi-insert '"\C-e": end-of-line' 2>/dev/null
bind -m vi-insert '"\C-k": kill-line' 2>/dev/null
# Open the current buffer line in $EDITOR, as ^x^e does in zsh
bind -m vi-insert '"\C-x\C-e": edit-and-execute-command' 2>/dev/null

# bash-completion (Nix profile, system, or Homebrew)
for __bc in \
"$HOME/.nix-profile/share/bash-completion/bash_completion" \
"/etc/profiles/per-user/$USER/share/bash-completion/bash_completion" \
/usr/share/bash-completion/bash_completion \
/opt/homebrew/etc/profile.d/bash_completion.sh \
/usr/local/etc/profile.d/bash_completion.sh; do
if [ -r "$__bc" ]; then
. "$__bc"
break
fi
done
unset __bc

# Prompt: user@host:cwd (git-branch)
__bash_git_branch() {
local branch
branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null) || return 0
printf ' (%s)' "$branch"
}
PS1='\[\e[32m\]\u@\h\[\e[0m\]:\[\e[34m\]\w\[\e[33m\]$(__bash_git_branch)\[\e[0m\]\$ '

# General aliases
alias v="nvim"

# eza as default lister
if command -v eza >/dev/null 2>&1; then
alias ls='eza --group-directories-first --icons=auto'
alias ll='eza -l --group-directories-first --icons=auto --git'
alias la='eza -la --group-directories-first --icons=auto --git'
alias lt='eza --tree --level=2 --icons=auto'
fi

# Load local-specific configuration if it exists. Deliberately before the two
# integrations below: on bash < 5.1 (macOS /bin/bash is 3.2) PROMPT_COMMAND is a
# plain string, so a bare assignment here would wipe their hooks. Both append to
# whatever it leaves behind, and it can still set MCFLY_*/_ZO_* to configure them.
[ -f "$DOTFILES/bash/.bashrc.local" ] && . "$DOTFILES/bash/.bashrc.local"

# zoxide: smarter cd, provides `z` and `zi`
command -v zoxide >/dev/null 2>&1 && eval "$(zoxide init bash)"

# mcfly: fuzzy ^R history search (after zoxide, so it wraps that prompt hook)
command -v mcfly >/dev/null 2>&1 && eval "$(mcfly init bash)"
10 changes: 6 additions & 4 deletions docs/README.nix.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ Before activation, customize `home.username` and `home.homeDirectory` in `home/d
### Development Tools
- **Editors**: Neovim
- **Terminal**: Herdr, Wezterm, Yazi
- **Shell**: Zsh with completion and syntax highlighting
- **Shell**: Zsh (primary, oh-my-zsh + mcfly) with a minimal Bash fallback (zoxide + mcfly)
- **Version Control**: Git, GitHub CLI, Lazygit
- **CLI Tools**: ripgrep, fd, bat, fzf, jq, and more
- **Rust Toolchain**: rustc, Cargo, Clippy, and rustfmt (managed by Nix)
Expand All @@ -105,6 +105,7 @@ Before activation, customize `home.username` and `home.homeDirectory` in `home/d
### Configuration Management
- **Modular**: Shared modules + platform-specific overrides
- **Symlinked**: Your existing dotfiles are symlinked (edit directly, no rebuild needed)
- **Stow-compatible**: each top-level config directory is also a GNU Stow package, so the same repo works on non-Nix machines (`stow bash zsh nvim`)
- **Reproducible**: Same environment across all machines
- **Declarative**: Everything in version control

Expand All @@ -117,7 +118,7 @@ dotfiles/
├── home/ # Home Manager configurations
│ ├── modules/ # Shared modules
│ │ ├── common.nix # Base settings
│ │ ├── shell.nix # Zsh configuration
│ │ ├── shell.nix # Zsh + Bash configuration
│ │ ├── dev-tools.nix # Development packages
│ │ ├── neovim.nix # Neovim + LSPs
│ │ └── terminal.nix # Herdr, Wezterm, Yazi
Expand All @@ -140,7 +141,8 @@ dotfiles/
│ ├── herdr/.config/herdr/
│ ├── wezterm/.config/wezterm/
│ ├── yazi/.config/yazi/
│ └── zsh/
│ ├── zsh/
│ └── bash/ # Minimal fallback shell
└── docs/
├── DEPLOYMENT.md # Detailed deployment guide
Expand Down Expand Up @@ -248,7 +250,7 @@ home-manager switch --rollback
**Current approach**: Manual management for simplicity
- Generate SSH keys manually on each machine: `ssh-keygen -t ed25519`
- Keep sensitive credentials outside version control
- Use local overrides (`.zshenv.local` pattern) for machine-specific secrets
- Use local overrides (`.zshenv.local` / `.bashrc.local` pattern) for machine-specific secrets

### Development Shells
Create project-specific environments:
Expand Down
11 changes: 11 additions & 0 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,17 @@
zsh -n ${self}/zsh/.zshrc
touch "$out"
'';

bash-syntax =
pkgs.runCommand "bash-syntax"
{
nativeBuildInputs = [ pkgs.bash ];
}
''
bash -n ${self}/bash/.bash_profile
bash -n ${self}/bash/.bashrc
touch "$out"
'';
}
);

Expand Down
1 change: 0 additions & 1 deletion home/modules/common.nix
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,5 @@
# Misc utilities
wget
curl
mcfly
];
}
25 changes: 17 additions & 8 deletions home/modules/shell.nix
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,17 @@

{
home = {
# Install oh-my-zsh package (not managed by Home Manager's programs.zsh.oh-my-zsh)
# This allows your .zshrc to have full control
packages = with pkgs; [
# Install oh-my-zsh package (not managed by Home Manager's programs.zsh.oh-my-zsh)
# This allows your .zshrc to have full control
oh-my-zsh

# Completions for the bash fallback (programs.bash is off, see below)
bash-completion

# Shell integrations wired up in zsh/.zshrc and bash/.bashrc
mcfly
zoxide
];

file = {
Expand All @@ -19,12 +26,14 @@
# Symlink .zshenv
".zshenv".source =
config.lib.file.mkOutOfStoreSymlink "${config.home.homeDirectory}/dotfiles/zsh/.zshenv";
};
};

# Bash configuration (fallback)
programs.bash = {
enable = true;
enableCompletion = true;
# Bash fallback. programs.bash stays disabled so these stay plain symlinks
# into the repo, which keeps them usable via GNU Stow on non-Nix machines.
".bashrc".source =
config.lib.file.mkOutOfStoreSymlink "${config.home.homeDirectory}/dotfiles/bash/.bashrc";

".bash_profile".source =
config.lib.file.mkOutOfStoreSymlink "${config.home.homeDirectory}/dotfiles/bash/.bash_profile";
};
};
}
8 changes: 6 additions & 2 deletions zsh/.zshenv
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,12 @@ export PATH="$HOME/go/bin:$PATH"
export PATH="$HOME/.nix-profile/bin:$PATH"
export CLOUDSDK_PYTHON=/usr/bin/python3

# GPG TTY for commit signing
export GPG_TTY=$(tty)
# GPG TTY for commit signing. `tty` writes "not a tty" to stdout when stdin is
# not a terminal, so assign only on success and keep any inherited value.
if __tty=$(tty 2>/dev/null); then
export GPG_TTY=$__tty
fi
unset __tty

# General aliases
alias v="nvim"
Expand Down
Loading