diff --git a/README.md b/README.md index ba0e045..5616204 100644 --- a/README.md +++ b/README.md @@ -28,10 +28,12 @@ sudo nixos-rebuild switch --flake .# darwin-rebuild switch --flake .#lyrathorpe-mac ``` -## Keybindings +## Shell environment & keybindings -All Sway / tmux / foot / zsh keyboard shortcuts are documented in -[`lyrathorpe/home/KEYBINDINGS.md`](./lyrathorpe/home/KEYBINDINGS.md). +- Interactive shell features (zsh, tmux, git, ssh, CLI tools, auto-tmux): + [`lyrathorpe/home/README.md`](./lyrathorpe/home/README.md). +- All Sway / tmux / foot / zsh keyboard shortcuts: + [`lyrathorpe/home/KEYBINDINGS.md`](./lyrathorpe/home/KEYBINDINGS.md). ## Login / greeter diff --git a/flake.lock b/flake.lock index 581ed2b..822ec07 100644 --- a/flake.lock +++ b/flake.lock @@ -150,6 +150,26 @@ "type": "github" } }, + "nix-index-database": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1780816331, + "narHash": "sha256-0BYqs8yKWkOz2Q7+SP18N5E5gmDKSo6LSxIVIa0wWes=", + "owner": "nix-community", + "repo": "nix-index-database", + "rev": "1a2ea89c917781e88508d9fd2b507f2d2a0e173c", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nix-index-database", + "type": "github" + } + }, "nixos-apple-silicon": { "inputs": { "flake-compat": "flake-compat", @@ -231,6 +251,7 @@ "home-manager": "home-manager", "nix-darwin": "nix-darwin", "nix-homebrew": "nix-homebrew", + "nix-index-database": "nix-index-database", "nixos-apple-silicon": "nixos-apple-silicon", "nixos-wsl": "nixos-wsl", "nixpkgs": "nixpkgs", diff --git a/flake.nix b/flake.nix index 07ee130..d36170b 100644 --- a/flake.nix +++ b/flake.nix @@ -28,6 +28,12 @@ url = "gitlab:rycee/nur-expressions?dir=pkgs/firefox-addons"; inputs.nixpkgs.follows = "nixpkgs"; }; + # Prebuilt nix-index database so "command not found -> which package + # provides it" works immediately (no manual `nix-index` run). See shell.nix. + nix-index-database = { + url = "github:nix-community/nix-index-database"; + inputs.nixpkgs.follows = "nixpkgs"; + }; }; outputs = diff --git a/lyrathorpe/home/KEYBINDINGS.md b/lyrathorpe/home/KEYBINDINGS.md index dc9a4cf..2382edc 100644 --- a/lyrathorpe/home/KEYBINDINGS.md +++ b/lyrathorpe/home/KEYBINDINGS.md @@ -133,16 +133,21 @@ Prefix is **`Ctrl`+`b`** (default). Copy mode uses **vi** keys. | --- | --- | | `Ctrl`+`b` then `v` | Split into left/right panes | | `Ctrl`+`b` then `s` | Split into top/bottom panes | +| `Ctrl`+`h`/`j`/`k`/`l` | Move between panes — and into/out of vim splits — seamlessly (vim-tmux-navigator, no prefix) | | `Alt`+`←`/`→`/`↑`/`↓` | Switch pane by direction (no prefix needed) | | `Ctrl`+`b` then `[` | Enter copy mode (then vi motions; `Space`/`Enter` to select/copy) | | `Ctrl`+`b` then `z` | Zoom / unzoom the focused pane | | `Ctrl`+`b` then `c` | New window | | `Ctrl`+`b` then `n` / `p` | Next / previous window | | `Ctrl`+`b` then `d` | Detach | +| `Ctrl`+`b` then `Ctrl`+`s` / `Ctrl`+`r` | Save / restore the session (resurrect; continuum also auto-saves and restores on start) | | Mouse | Enabled — click to focus, drag borders, scroll, select | > The stock split keys `%` and `"` are unbound; use `v` / `s` above. `Ctrl`+`b` > then `s` is therefore a split, not the session tree. +> +> Sessions persist across reboots (resurrect + continuum). Terminals auto-start +> tmux; `NO_TMUX=1 ` opens a bare shell instead. --- diff --git a/lyrathorpe/home/README.md b/lyrathorpe/home/README.md new file mode 100644 index 0000000..0307a28 --- /dev/null +++ b/lyrathorpe/home/README.md @@ -0,0 +1,135 @@ +# Interactive shell environment + +Everything the shell, terminal multiplexer, git and ssh do beyond their defaults, +and where each is defined. All of it is managed declaratively through +home-manager — edit the listed file and rebuild, never the generated dotfiles. + +Keyboard shortcuts have their own reference: [`KEYBINDINGS.md`](./KEYBINDINGS.md). + +| Area | Defined in | +| --- | --- | +| zsh, CLI tools, tmux, ssh, auto-tmux | [`shell.nix`](./shell.nix) | +| git (+ delta, commitizen) | [`git.nix`](./git.nix) | +| vim | [`editor.nix`](./editor.nix) | +| GUI apps, GTK/Firefox theming, cursor | [`desktop.nix`](./desktop.nix) (graphical hosts only) | + +Shared by every host via [`default.nix`](./default.nix); the work box also layers +[`../../system/modules/work/default.nix`](../../system/modules/work/default.nix) +on top (work email, its own ssh config, extra packages). + +--- + +## zsh + +| Feature | Notes | +| --- | --- | +| oh-my-zsh | plugins `git`, `man`, `sudo` (Esc-Esc to prepend sudo), `colored-man-pages`, `extract`; theme `robbyrussell` | +| Autosuggestion | fish-style history suggestions as you type (→ to accept) | +| Syntax highlighting | commands coloured by validity as you type | +| Completion | menu completion; the dump is rebuilt on every activation (see Maintenance) | +| History | 100k in-memory/on-disk, deduped, space-prefixed commands ignored, timestamped, **shared live across sessions** | +| History substring search | type a fragment, then ↑/↓ cycles matching past commands — works in foot, iTerm2 and the Linux TTY (both CSI and SS3 arrow encodings bound) | +| Prompt | hostname is prefixed when over SSH | + +**Aliases:** `ls`/`ll`/`la`/`lt` → `eza` (icons + git), `cls` → `clear`. git aliases live in git.nix (below). + +## CLI tools + +| Tool | What it gives you | +| --- | --- | +| `fzf` | `Ctrl-R` fuzzy history, `Ctrl-T` file picker, `Alt-C` fuzzy cd | +| `zoxide` | `z ` jumps to frecent directories | +| `direnv` + `nix-direnv` | per-project environments auto-loaded on `cd` (cached Nix dev shells) | +| `eza` | modern `ls` (drives the ls aliases) | +| `bat` | syntax-highlighting pager; behaves like `cat` when piped | +| `nix-index` | `command-not-found`: an unknown command tells you which Nix package provides it (prebuilt DB, no manual indexing) | +| `comma` (`,`) | run an uninstalled program once: `, cowsay hi` | +| `nh` | nicer `nixos-rebuild`/`home-manager` with diffs; `$NH_FLAKE` set to the repo. No scheduled GC (it could reap paths a running generation still references) — collect garbage manually with `nh clean all` / `nix-collect-garbage -d` | + +## tmux + +**Auto-start:** opening any interactive terminal — foot, iTerm2, the WSL shell, the +Linux console — drops you straight into a tmux session named `main` (attach if it +exists, else create). Panes run a plain non-login zsh. It deliberately does **not** +fire for SSH sessions, VS Code's integrated terminal, already-inside-tmux, or +non-interactive shells. Escape hatch: `NO_TMUX=1 ` opens a bare shell. + +| Setting | Value | +| --- | --- | +| Mode keys | vi | +| Mouse | on | +| Scrollback | 500000 lines | +| `escape-time` | 10ms (the 500ms default lagged vim's ESC) | +| `focus-events` | on (vim autoread) | +| `base-index` / `pane-base-index` | 1 | +| Splits | `prefix s` vertical, `prefix v` horizontal (stock `%`/`"` unbound) | +| Pane nav | `Alt`+arrows (no prefix) | +| Terminal | `default-terminal tmux-256color`; truecolor advertised per outer terminal (`foot*`, `xterm-256color`/iTerm2) via `terminal-features … RGB` | +| Clipboard | `set-clipboard on`; foot `terminal-features` advertise truecolor/sync/OSC52/title/cursor | + +**Plugins:** `sensible`, `vim-tmux-navigator` (Ctrl-h/j/k/l across vim ↔ tmux), +`yank`, `catppuccin` (Mocha statusline), `resurrect` + `continuum` +(sessions auto-save and restore across reboots). The statusline draws Nerd-Font +glyphs — see Fonts. + +## Fonts + +**JetBrainsMono Nerd Font** is installed on every host (in `common-nixos.nix`, +because tmux runs everywhere; the Mac installs it to `/Library/Fonts` via the +Darwin config). foot uses it as its main font automatically. iTerm2's font is a +GUI setting — set it to *JetBrainsMono Nerd Font* (Settings → Profiles → Text → +Font) so the tmux statusline glyphs render instead of `?`. + +## git + +Pager is **delta**. **commitizen** is installed on every host; `cz` defaults to +Conventional Commits. + +| Aliases | | +| --- | --- | +| `st` `co` `sw` `br` `ci` | status / checkout / switch / branch / commit | +| `last` `unstage` | last commit / unstage | +| `lg` | graph log, all branches | +| `cz` `cc` | `git cz ` (e.g. `git cz c`) and `git cc` → commitizen prompt | + +| Behaviour | | +| --- | --- | +| Pulls | rebase, with autostash + autosquash | +| Fetch | prune deleted remote branches | +| Conflicts | `zdiff3` (shows the common ancestor) | +| Diffs | histogram algorithm, colour-moved | +| `rerere` | remembers + replays conflict resolutions | +| Commit editor | full diff shown (`commit.verbose`) | +| Misc | branches sorted by date, `column.ui = auto`, `help.autocorrect = prompt`, `push.autoSetupRemote` | +| Global ignores | `result`, `result-*`, `.direnv`, `*.swp`, `.DS_Store` | +| Signing | SSH commit + tag signing (`mkDefault`, so a host without the key in its agent can disable it). Personal email `iam@emmathe.dev`; the work box overrides email + signing. | + +## ssh + +| Feature | Notes | +| --- | --- | +| ssh-agent | runs on Linux (launchd on macOS); keys added on **first use** so the passphrase is typed once per login session — this also feeds git commit signing | +| macOS | `UseKeychain` caches the passphrase in the login keychain (guarded by `IgnoreUnknown`, so a non-Apple `ssh` skips it instead of erroring) | +| Gitea remote | `code.emmathe.dev` → `HostName 10.187.1.76` (DNS-override), `Port 30009`, user `git`, dedicated key, `identitiesOnly` | +| Defaults | the module's deprecated default block is opted out; equivalents kept under `settings."*"` | + +The **work box keeps its own `~/.ssh/config`** (home-manager's `programs.ssh` is +forced off there) but still runs the agent. + +## Maintenance behaviours + +- **zcompdump reset** — `~/.zcompdump*` is removed on every activation, so a stale + dump (pointing at `/nix/store` paths a rebuild or a manual GC removed) can't + break completion with `_git: function definition file not found`. +- **GC** — no scheduled timer; collect garbage deliberately (`nh clean all` / + `nix-collect-garbage -d`) when no important session is running. + +## Per-host differences + +| | Personal Linux (sway) | macOS | Work WSL (EDaaS) | +| --- | --- | --- | --- | +| Auto-tmux | yes (foot/TTY) | yes (iTerm2) | yes (WSL shell) | +| git email | `iam@emmathe.dev` | `iam@emmathe.dev` | `…@citrix.com` (work) | +| ssh config managed | yes | yes | no (keeps corporate config) | +| ssh-agent | yes | launchd | yes (work module) | +| GUI / theming (desktop.nix) | yes | no | no | diff --git a/lyrathorpe/home/editor.nix b/lyrathorpe/home/editor.nix index de6216b..188375d 100644 --- a/lyrathorpe/home/editor.nix +++ b/lyrathorpe/home/editor.nix @@ -10,6 +10,7 @@ vim-fugitive vim-indent-guides catppuccin-vim + vim-tmux-navigator # Ctrl-h/j/k/l moves between vim splits and tmux panes ]; settings = { expandtab = false; diff --git a/lyrathorpe/home/git.nix b/lyrathorpe/home/git.nix index 8aca636..2b1f819 100644 --- a/lyrathorpe/home/git.nix +++ b/lyrathorpe/home/git.nix @@ -1,6 +1,11 @@ # Version control: git + delta pager + commitizen. The work host layers # commit signing and an email override on top (see work/default.nix). -{ pkgs, fullName, ... }: +{ + pkgs, + lib, + fullName, + ... +}: { home.packages = [ pkgs.commitizen @@ -11,13 +16,65 @@ package = pkgs.gitFull; settings = { user.name = fullName; - push = { - autoSetupRemote = true; + # Personal identity. mkDefault so the work module overrides it on the work + # host (and to merge cleanly with that plain definition there). + user.email = lib.mkDefault "iam@emmathe.dev"; + push.autoSetupRemote = true; + init.defaultBranch = "main"; + + # Rebase-centric pulls (matches the "always a branch, linear history" + # workflow); stash/restore and reorder fixups automatically. + pull.rebase = true; + rebase = { + autoStash = true; + autoSquash = true; }; - init = { - defaultBranch = "main"; + + fetch.prune = true; # drop deleted remote-tracking branches + merge.conflictStyle = "zdiff3"; # show the common ancestor in conflicts + diff = { + algorithm = "histogram"; + colorMoved = "default"; }; + rerere.enabled = true; # remember + replay conflict resolutions + commit.verbose = true; # full diff in the commit-message editor + branch.sort = "-committerdate"; # most-recent branches first + column.ui = "auto"; + help.autocorrect = "prompt"; + + alias = { + st = "status"; + co = "checkout"; + sw = "switch"; + br = "branch"; + ci = "commit"; + last = "log -1 HEAD"; + unstage = "reset HEAD --"; + lg = "log --graph --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) %C(dim white)- %an%C(reset)%C(auto)%d%C(reset)' --all"; + # commitizen (Conventional Commits, its default ruleset): `git cz c` -> + # `cz commit`, `git cz bump`, etc. `git cc` is a shortcut for the prompt. + cz = "!cz"; + cc = "!cz commit"; + }; + + # SSH commit signing on personal hosts too (the work module sets the same + # on the work host). mkDefault so a host without the key in its ssh-agent + # can override to false -- otherwise commits there would fail. Reuses the + # existing ssh key; a dedicated personal key can be swapped in later. + gpg.format = "ssh"; + user.signingkey = "key::ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAJMVgeRKnfX1G8coU3nAobI485aeUpGTMqH7+zbKI8o emma.thorpe@cloud.com"; + commit.gpgsign = lib.mkDefault true; + tag.gpgsign = lib.mkDefault true; }; + + # Global ignore file (~/.config/git/ignore). + ignores = [ + "result" + "result-*" + ".direnv" + "*.swp" + ".DS_Store" + ]; }; programs.delta = { diff --git a/lyrathorpe/home/shell.nix b/lyrathorpe/home/shell.nix index f9ce679..eae0552 100644 --- a/lyrathorpe/home/shell.nix +++ b/lyrathorpe/home/shell.nix @@ -1,6 +1,17 @@ # Interactive shell: zsh + tmux. Wanted on every host. -{ lib, ... }: { + lib, + pkgs, + inputs, + ... +}: +{ + imports = [ + # Prebuilt nix-index database -> working command-not-found + # ("cmd not found -> which nix package provides it"), no manual indexing. + inputs.nix-index-database.homeModules.default + ]; + programs.zsh = { enable = true; enableCompletion = true; @@ -21,35 +32,151 @@ "^[OB" ]; }; - history.append = true; + history = { + append = true; # append, don't overwrite, on shell exit + size = 100000; # in-memory (HISTSIZE) + save = 100000; # on-disk (SAVEHIST) + ignoreDups = true; # drop consecutive duplicates + ignoreSpace = true; # leading-space commands stay out of history + expireDuplicatesFirst = true; + share = true; # live-share history across sessions + extended = true; # record timestamps + }; oh-my-zsh = { enable = true; plugins = [ "git" "man" + "sudo" # double-Esc prefixes the last command with sudo + "colored-man-pages" + "extract" # `extract ` for any format ]; theme = "robbyrussell"; }; syntaxHighlighting.enable = true; - # Prefix the prompt with the hostname over SSH. - initContent = lib.mkOrder 1500 '' - if [ "$SSH_CLIENT" ] || [ "$SSH_TTY" ]; then - export PS1="%M $PS1" - fi - ''; - envExtra = '' - alias cls=clear - ''; + initContent = lib.mkMerge [ + # Auto-start tmux in every interactive terminal -- foot, iTerm2, the WSL + # shell, the Linux console -- so a new terminal lands straight in the + # multiplexer (session "main": attach if present, else create). Panes run + # a plain non-login zsh (tmux's default-command "${SHELL}"). Order 200 + # runs before oh-my-zsh/compinit so the exec replaces the shell before + # that setup is wasted. Guards, each preventing a real breakage: + # interactive only -> don't hijack scp / `ssh host cmd` / scripted shells + # $TMUX empty -> a pane's zsh won't re-exec tmux (infinite loop) + # not SSH -> don't force inbound SSH logins into a server tmux + # not VS Code -> its integrated terminal manages itself + # tmux on PATH -> a failed exec would otherwise kill the login shell + # $NO_TMUX unset -> escape hatch: `NO_TMUX=1 ` opens a bare shell + (lib.mkOrder 200 '' + if [[ $- == *i* ]] \ + && [[ -z "$TMUX" ]] \ + && [[ -z "$NO_TMUX" ]] \ + && [[ -z "$SSH_CONNECTION" && -z "$SSH_TTY" ]] \ + && [[ "$TERM_PROGRAM" != "vscode" ]] \ + && command -v tmux >/dev/null 2>&1; then + exec tmux new-session -A -s main + fi + '') + # Prefix the prompt with the hostname over SSH (mkAfter). + (lib.mkOrder 1500 '' + if [ "$SSH_CLIENT" ] || [ "$SSH_TTY" ]; then + export PS1="%M $PS1" + fi + '') + ]; + shellAliases = { + # eza's zsh integration also defines these; set explicitly so the + # icons/git intent is obvious. + ls = "eza --icons --git"; + ll = "eza --icons --git -l"; + la = "eza --icons --git -la"; + lt = "eza --icons --git --tree"; + cls = "clear"; + }; + }; + + # Fuzzy finder: Ctrl-R fuzzy history, Ctrl-T files, Alt-C cd. + programs.fzf = { + enable = true; + enableZshIntegration = true; + }; + + # Frecency directory jumping: `z `. + programs.zoxide = { + enable = true; + enableZshIntegration = true; + }; + + # Per-project environments auto-loaded on cd, with the Nix dev-shell cache. + programs.direnv = { + enable = true; + nix-direnv.enable = true; + }; + + # Modern ls (drives the ls aliases above). + programs.eza = { + enable = true; + git = true; + icons = "auto"; # boolean form is deprecated + }; + + # Syntax-highlighting pager, used as `bat` (acts like cat when piped). + programs.bat.enable = true; + + # command-not-found backed by the prebuilt nix-index DB (module imported + # above). `comma` runs an uninstalled program once: `, cowsay hi`. + programs.nix-index.enable = true; + programs.nix-index-database.comma.enable = true; + + # Nicer nixos-rebuild/home-manager (diffs) + $NH_FLAKE. No automatic clean: + # the scheduled GC's only benefit is reclaiming disk, but it can reap store + # paths the current generation still references (notably on nix-darwin, where + # it broke completion by removing an in-use oh-my-zsh). GC manually instead: + # `nh clean all` / `nix-collect-garbage -d` when nothing important is running. + programs.nh = { + enable = true; + flake = "$HOME/code/nixfiles"; }; programs.tmux = { enable = true; reverseSplit = true; - terminal = "tmux-direct"; + # tmux-256color (not tmux-direct): the standard inside-tmux terminfo. + # tmux-direct's capabilities desync zsh's line redraw on some terminals + # (e.g. iTerm2 -> duplicated chars on Tab, stray newlines). Truecolor is + # advertised per outer terminal via the RGB terminal-features below. + terminal = "tmux-256color"; newSession = true; keyMode = "vi"; historyLimit = 500000; mouse = true; + escapeTime = 10; # was the 500ms default -> laggy ESC in vim + focusEvents = true; # let vim see focus changes (autoread) + baseIndex = 1; # sets both base-index and pane-base-index + + plugins = with pkgs.tmuxPlugins; [ + sensible + vim-tmux-navigator # Ctrl-h/j/k/l across vim splits and tmux panes + yank + { + # Catppuccin Mocha statusline (v2 API: flavour + window options must be + # set before the plugin loads, which home-manager does for plugin + # extraConfig; the status modules below go in the main extraConfig, + # which HM appends after all plugins). + plugin = catppuccin; + extraConfig = '' + set -g @catppuccin_flavor 'mocha' + set -g @catppuccin_window_status_style 'rounded' + ''; + } + resurrect # save/restore sessions + { + plugin = continuum; # auto-save + restore on tmux start (after resurrect) + extraConfig = '' + set -g @continuum-restore 'on' + ''; + } + ]; # `reverseSplit = true` already binds s -> vertical and v -> horizontal # split (the dotfiles' vim-style splits). extraConfig = '' @@ -66,6 +193,10 @@ bind -n M-Up select-pane -U bind -n M-Down select-pane -D + # Truecolor for the outer terminals (foot reports xterm-ish too; iTerm2 is + # xterm-256color). Without this, with tmux-256color as default-terminal, + # 24-bit colour would be quantised to 256. + set -as terminal-features ",xterm-256color:RGB" # Tell tmux which capabilities the foot terminal supports, so truecolor, # synchronised output, the system clipboard (OSC 52), window titles and # cursor styling all pass through. @@ -75,6 +206,78 @@ set -as terminal-features ",foot*:title" set -as terminal-features ",foot*:ccolour" set -as terminal-features ",foot*:cstyle" + + # No home-manager options for these. + set -g renumber-windows on + set -g set-clipboard on + + # Catppuccin v2 statusline. Must run after the plugin has loaded; + # home-manager appends this extraConfig after the whole plugin list. + set -g status-left-length 100 + set -g status-right-length 100 + set -g status-left "" + set -g status-right "#{E:@catppuccin_status_application}" + set -ag status-right "#{E:@catppuccin_status_session}" ''; }; + + # Add the key to the agent on first use, so the passphrase is typed once per + # login session rather than per commit/push (commit signing uses this agent). + # The work box keeps its own ssh config (see work/default.nix), so this only + # manages ~/.ssh/config on the personal hosts. + programs.ssh = { + enable = true; + # The module's built-in default "*" block is being deprecated; opt out and + # carry the defaults we want ourselves under settings."*". + enableDefaultConfig = false; + settings = { + # Global defaults (rendered last, as ssh_config wants). AddKeysToAgent + # adds the key on first use so the passphrase is typed once per session. + "*" = { + AddKeysToAgent = "yes"; + ForwardAgent = false; + Compression = false; + ServerAliveInterval = 0; + ServerAliveCountMax = 3; + HashKnownHosts = false; + UserKnownHostsFile = "~/.ssh/known_hosts"; + ControlMaster = "no"; + ControlPath = "~/.ssh/master-%r@%n:%p"; + ControlPersist = "no"; + } + # macOS: also cache the passphrase in the login keychain. UseKeychain + # exists only in Apple's ssh; nixpkgs' openssh (which may be the `ssh` on + # PATH) rejects it as "Bad configuration option". IgnoreUnknown (emitted + # first by the module) makes any non-Apple ssh skip it instead of erroring, + # while Apple's ssh still honours it. Darwin-only. + // lib.optionalAttrs pkgs.stdenv.hostPlatform.isDarwin { + IgnoreUnknown = "UseKeychain"; + UseKeychain = "yes"; + }; + # Gitea remote (the flake's origin) -- required on every host. HostName + # pins the IP so it resolves without DNS. Port 30009 is non-default; pin + # the dedicated key (identitiesOnly avoids "too many authentication + # failures" when the agent holds several keys). + "code.emmathe.dev" = { + HostName = "10.187.1.76"; + User = "git"; + Port = 30009; + IdentityFile = "~/.ssh/code.emmathe.dev"; + IdentitiesOnly = true; + }; + }; + }; + + # Run a user ssh-agent on Linux (macOS provides one via launchd). EDaaS also + # enables this in the work module; both being true merges cleanly. + services.ssh-agent.enable = lib.mkIf pkgs.stdenv.hostPlatform.isLinux true; + + # Drop the zsh completion dump on every activation. A stale ~/.zcompdump + # caches /nix/store paths to completion functions; once a rebuild or a manual + # GC removes them, compinit fails with "_git: function definition file not + # found" for every completion. Deleting it forces a fresh rebuild from the + # current fpath on the next shell. + home.activation.resetZcompdump = lib.hm.dag.entryAfter [ "writeBoundary" ] '' + $DRY_RUN_CMD rm -f "$HOME"/.zcompdump* "''${XDG_CACHE_HOME:-$HOME/.cache}"/zsh/.zcompdump* 2>/dev/null || true + ''; } diff --git a/lyrathorpe/home/sway.nix b/lyrathorpe/home/sway.nix index 118a65f..b5d2623 100644 --- a/lyrathorpe/home/sway.nix +++ b/lyrathorpe/home/sway.nix @@ -237,6 +237,9 @@ in # text). Only colors-dark is needed; we never set initial-color-theme=light. settings = { main = { + # Nerd Font: monospace plus the powerline/Nerd glyphs the tmux + # statusline uses (otherwise they render as blank/"?"). + font = "JetBrainsMono Nerd Font:size=11"; # Advertise as xterm-256color so remote hosts without foot's terminfo # still behave (tmux re-adds foot's RGB/sync/etc. features -- see # shell.nix). The [main] section is the unheadered top of foot.ini. diff --git a/system/machine/Darwin/configuration.nix b/system/machine/Darwin/configuration.nix index 4f54c4e..e894e08 100644 --- a/system/machine/Darwin/configuration.nix +++ b/system/machine/Darwin/configuration.nix @@ -6,6 +6,11 @@ { programs.zsh.enable = true; + # Install the Nerd Font into /Library/Fonts so iTerm2 can use it (set it in + # iTerm2 -> Settings -> Profiles -> Text -> Font: "JetBrainsMono Nerd Font"). + # Provides the powerline/Nerd glyphs the tmux statusline draws. + fonts.packages = [ pkgs.nerd-fonts.jetbrains-mono ]; + # CLI tooling sourced from nixpkgs instead of Homebrew formulae. Pure library # dependencies are omitted; nix pulls them into closures automatically. environment.systemPackages = with pkgs; [ diff --git a/system/modules/common-nixos.nix b/system/modules/common-nixos.nix index 5c4a78d..476aa1e 100644 --- a/system/modules/common-nixos.nix +++ b/system/modules/common-nixos.nix @@ -12,4 +12,10 @@ git fastfetch ]; + + # Terminal font with powerline/Nerd glyphs. Installed on every host because + # the tmux statusline (which uses these glyphs) runs everywhere, not just on + # the Sway/graphical hosts. foot names it explicitly (home/sway.nix); the Mac + # installs it via the Darwin config. + fonts.packages = [ pkgs.nerd-fonts.jetbrains-mono ]; } diff --git a/system/modules/work/default.nix b/system/modules/work/default.nix index 936468e..854ee9c 100644 --- a/system/modules/work/default.nix +++ b/system/modules/work/default.nix @@ -1,6 +1,10 @@ -{ pkgs, ... }: +{ pkgs, lib, ... }: { + # The work box keeps its own (corporate) ~/.ssh/config; don't let the personal + # programs.ssh (shell.nix) take it over. The ssh-agent below still runs. + programs.ssh.enable = lib.mkForce false; + programs.git = { settings = { commit.gpgsign = true;