From a5d6c3eb7727ac2a2b23f19346535a9d59b1857f Mon Sep 17 00:00:00 2001 From: nevaforget <> Date: Thu, 20 Aug 2026 14:35:55 +0200 Subject: [PATCH] fix(zsh): defend the sourced zshrc against the /etc/zshrc defaults /etc/zshrc renders promptInit and environment.shellAliases after interactiveShellInit, so both overrode the shared zshrc: the prompt became `prompt suse` and ls/ll/l fell back to coreutils. The plugin sourcing in the zshrc points at the Arch path /usr/share/zsh/plugins and silently found nothing. Clear promptInit, drop the three aliases with null, and enable the syntax-highlighting and autosuggestions modules. --- DECISIONS.md | 47 +++++++++++++++++++++++++++++++++++++++++++++ modules/desktop.nix | 26 +++++++++++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/DECISIONS.md b/DECISIONS.md index 7e15722..4f7ef67 100644 --- a/DECISIONS.md +++ b/DECISIONS.md @@ -1,5 +1,52 @@ # Decisions +## 2026-08-20 – The sourced zshrc is defended against the /etc/zshrc defaults + +- **Who**: Dominik, ClaudeCode +- **Why**: `programs.zsh.interactiveShellInit` sources the shared + `defaults/shell/zshrc`, but the shell on the test VM did not look like the one + on Arch. The file is not at fault — the pinned `moonarch` input is the same + revision as the working tree and the file is byte-identical. The generated + `/etc/zshrc` is: `nixos/modules/programs/zsh/zsh.nix` places + `interactiveShellInit` at line 277, then `environment.shellAliases` at 285, + then `promptInit` at 288. Three defaults therefore land after our file and + win. (1) `promptInit` defaults to `autoload -U promptinit && promptinit && + prompt suse`, and `prompt suse` assigns `PS1` — the same parameter as + `PROMPT` — so the Catppuccin prompt was replaced by the SUSE one. (2) + `environment.shellAliases` carries `ls`, `ll` and `l` as `mkDefault` + (`nixos/modules/config/shells-environment.nix:235`), shadowing the eza + aliases. (3) Unrelated to ordering: the zshrc sources zsh-syntax-highlighting + and zsh-autosuggestions from `/usr/share/zsh/plugins`, the path of the Arch + packages. The lookups are `[[ -f ]]`-guarded, so both plugins were silently + absent. +- **Tradeoffs**: (1) **Where the prompt is owned** — moving the prompt into + `promptInit` would place it in the slot NixOS intends for it, at the price of + splitting one shared file across two options and diverging from Arch. Setting + `promptInit = ""` keeps the zshrc the single owner. (2) **Alias removal** — + redefining `ls`/`ll`/`l` in Nix would duplicate the eza commands in a second + place, where they can drift from the zshrc. `null` removes the alias + (`zsh.nix:20` filters null values out) and leaves the definition in one file. + Scoped to `programs.zsh.shellAliases` rather than `environment.shellAliases`, + so bash keeps the coreutils `ls` — it has no eza aliases to fall back on. (3) + **Plugins** — a `/usr/share/zsh/plugins` symlink farm via tmpfiles would make + the existing lookups succeed and need no Nix-side option, but it rebuilds an + FHS path for a file that the NixOS modules already know how to source. The + modules were chosen, as with the polkit exception the other way around + (2026-08-07). +- **How**: `modules/desktop.nix` — `programs.zsh.promptInit = ""`, + `programs.zsh.shellAliases` with `ls`/`ll`/`l` set to `null`, + `programs.zsh.syntaxHighlighting.enable` and + `programs.zsh.autosuggestions.enable` with `strategy = [ "history" + "completion" ]`, the value the zshrc sets on Arch. Verified by evaluating + `environment.etc.zshrc.text` for the `testvm` host before and after: the + prompt and alias blocks are now empty, and both plugins are sourced from the + store. +- **Remaining exception**: the zshrc's `orphans` and `uninstall` aliases call + `pacman`. They are dead on NixOS but harmless, and rewriting them per distro + would fork the shared file. +- **Not changed**: `compinit` runs twice — once from `enableGlobalCompInit` + (`zsh.nix:266`), once in the zshrc. Duplicated work, no defect, left alone. + ## 2026-08-20 – Installing from an own ISO, one command - **Who**: Maintainer, ClaudeCode diff --git a/modules/desktop.nix b/modules/desktop.nix index f319ad5..a30d1b1 100644 --- a/modules/desktop.nix +++ b/modules/desktop.nix @@ -129,6 +129,32 @@ in source ${moonarchSrc}/defaults/shell/zshrc ''; + # /etc/zshrc places promptInit after interactiveShellInit, and its default + # ends in `prompt suse`, which assigns PS1 — the same parameter as PROMPT. + # Left at the default it overwrites the prompt the sourced zshrc just set. + # The zshrc owns the prompt, so nothing else has to run here. + programs.zsh.promptInit = ""; + + # The zshrc sources both plugins from /usr/share/zsh/plugins, the path the + # Arch packages use; the lookups are guarded and silently find nothing here. + # These modules source the same plugins from the store instead. The strategy + # is the one the zshrc sets on Arch. + programs.zsh.syntaxHighlighting.enable = true; + programs.zsh.autosuggestions = { + enable = true; + strategy = [ "history" "completion" ]; + }; + + # environment.shellAliases carries ls, ll and l as defaults, and /etc/zshrc + # renders them after interactiveShellInit, so they shadow the eza aliases of + # the sourced zshrc. null drops an alias. Scoped to zsh: bash keeps the + # coreutils ls, which is the only thing it has. + programs.zsh.shellAliases = { + ls = null; + ll = null; + l = null; + }; + # --- File manager --- # # Counterpart to thunar, thunar-volman, thunar-archive-plugin, tumbler and