diff --git a/flake.lock b/flake.lock index 04b09cd..e775ef1 100644 --- a/flake.lock +++ b/flake.lock @@ -1,5 +1,59 @@ { "nodes": { + "alacritty-theme": { + "inputs": { + "alacritty-theme": "alacritty-theme_2", + "flake-parts": "flake-parts", + "nixpkgs": "nixpkgs" + }, + "locked": { + "lastModified": 1733731622, + "narHash": "sha256-SSdVAmG5W+x97EgSMwfO9yIqkNkMZmfdVUI/zll6OYU=", + "owner": "alexghr", + "repo": "alacritty-theme.nix", + "rev": "0e69ef549d4672c9066264d448ea5ea8b214a4f9", + "type": "github" + }, + "original": { + "owner": "alexghr", + "repo": "alacritty-theme.nix", + "type": "github" + } + }, + "alacritty-theme_2": { + "flake": false, + "locked": { + "lastModified": 1733116860, + "narHash": "sha256-D37MQtNS20ESny5UhW1u6ELo9czP4l+q0S8neH7Wdbc=", + "owner": "alacritty", + "repo": "alacritty-theme", + "rev": "95a7d695605863ede5b7430eb80d9e80f5f504bc", + "type": "github" + }, + "original": { + "owner": "alacritty", + "repo": "alacritty-theme", + "type": "github" + } + }, + "flake-parts": { + "inputs": { + "nixpkgs-lib": "nixpkgs-lib" + }, + "locked": { + "lastModified": 1683560683, + "narHash": "sha256-XAygPMN5Xnk/W2c1aW0jyEa6lfMDZWlQgiNtmHXytPc=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "006c75898cf814ef9497252b022e91c946ba8e17", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, "flake-utils": { "inputs": { "systems": "systems" @@ -91,16 +145,34 @@ }, "nixpkgs": { "locked": { - "lastModified": 1735141468, - "narHash": "sha256-VIAjBr1qGcEbmhLwQJD6TABppPMggzOvqFsqkDoMsAY=", - "owner": "nixos", + "lastModified": 1703961334, + "narHash": "sha256-M1mV/Cq+pgjk0rt6VxoyyD+O8cOUiai8t9Q6Yyq4noY=", + "owner": "NixOS", "repo": "nixpkgs", - "rev": "4005c3ff7505313cbc21081776ad0ce5dfd7a3ce", + "rev": "b0d36bd0a420ecee3bc916c91886caca87c894e9", "type": "github" }, "original": { - "owner": "nixos", - "ref": "nixos-24.11", + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-lib": { + "locked": { + "dir": "lib", + "lastModified": 1682879489, + "narHash": "sha256-sASwo8gBt7JDnOOstnps90K1wxmVfyhsTPPNTGBPjjg=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "da45bf6ec7bbcc5d1e14d3795c025199f28e0de0", + "type": "github" + }, + "original": { + "dir": "lib", + "owner": "NixOS", + "ref": "nixos-unstable", "repo": "nixpkgs", "type": "github" } @@ -121,11 +193,28 @@ "type": "github" } }, + "nixpkgs_2": { + "locked": { + "lastModified": 1735141468, + "narHash": "sha256-VIAjBr1qGcEbmhLwQJD6TABppPMggzOvqFsqkDoMsAY=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "4005c3ff7505313cbc21081776ad0ce5dfd7a3ce", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-24.11", + "repo": "nixpkgs", + "type": "github" + } + }, "root": { "inputs": { + "alacritty-theme": "alacritty-theme", "home-manager": "home-manager", "lix-module": "lix-module", - "nixpkgs": "nixpkgs", + "nixpkgs": "nixpkgs_2", "nixpkgs-unstable": "nixpkgs-unstable" } }, diff --git a/flake.nix b/flake.nix index 47a288c..4437479 100644 --- a/flake.nix +++ b/flake.nix @@ -18,11 +18,15 @@ # Home manager home-manager.url = "github:nix-community/home-manager/release-24.11"; home-manager.inputs.nixpkgs.follows = "nixpkgs"; + + # Alacritty Theme + alacritty-theme.url = "github:alexghr/alacritty-theme.nix"; }; outputs = { self, nixpkgs, + alacritty-theme, lix-module, home-manager, ... @@ -68,19 +72,5 @@ ]; }; }; - - # Standalone home-manager configuration entrypoint - # Available through 'home-manager --flake .#your-username@your-hostname' - homeConfigurations = { - # FIXME replace with your username@hostname - "chloe@xenia" = home-manager.lib.homeManagerConfiguration { - pkgs = nixpkgs.legacyPackages.x86_64-linux; # Home-manager requires 'pkgs' instance - extraSpecialArgs = {inherit inputs outputs;}; - modules = [ - # > Our main home-manager configuration file < - ./home-manager/home.nix - ]; - }; - }; }; } diff --git a/home-manager/home.nix b/home-manager/home.nix index 07eb68c..c766002 100644 --- a/home-manager/home.nix +++ b/home-manager/home.nix @@ -48,15 +48,44 @@ home = { username = "chloe"; homeDirectory = "/home/chloe"; + packages = with pkgs; [ + alacritty + alacritty-theme + zsh-powerlevel10k + cozette + yt-dlp + celluloid + hyfetch + (nerdfonts.override { fonts = [ "FiraCode" "JetBrainsMono" ]; }) + ]; }; - # Add stuff for your user as you see fit: - # programs.neovim.enable = true; - # home.packages = with pkgs; [ steam ]; + programs = { + # Alacritty Config + alacritty = { + enable = true; + settings = { + font.normal.family = "CozetteVector"; + font.bold.family = "CozetteVector"; + font.bold.style = "bold"; + font.size = 12.0; + }; + }; - # Enable home-manager and git - programs.home-manager.enable = true; - programs.git.enable = true; + # ZSH Config + zsh = { + enable = true; + initExtra = "source ${pkgs.zsh-powerlevel10k}/share/zsh-powerlevel10k/powerlevel10k.zsh-theme"; + }; + + # Add stuff for your user as you see fit: + firefox.enable = true; + home-manager.enable = true; + git.enable = true; + }; + + # Allow home-manager to manage fonts + fonts.fontconfig.enable = true; # Nicely reload system units when changing configs systemd.user.startServices = "sd-switch"; diff --git a/modules/home-manager/default.nix b/modules/home-manager/default.nix index 45aae31..03160ce 100644 --- a/modules/home-manager/default.nix +++ b/modules/home-manager/default.nix @@ -1,6 +1,2 @@ # Add your reusable home-manager modules to this directory, on their own file (https://nixos.wiki/wiki/Module). # These should be stuff you would like to share with others, not your personal configurations. -{ - # List your module files here - # my-module = import ./my-module.nix; -} diff --git a/modules/home-manager/fontconfig.nix b/modules/home-manager/fontconfig.nix new file mode 100644 index 0000000..9bc6ac4 --- /dev/null +++ b/modules/home-manager/fontconfig.nix @@ -0,0 +1,171 @@ +# This module is heavily inspired by the corresponding NixOS module. See +# +# https://github.com/NixOS/nixpkgs/blob/23.11/nixos/modules/config/fonts/fontconfig.nix + +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.fonts.fontconfig; + + profileDirectory = config.home.profileDirectory; + +in { + meta.maintainers = [ maintainers.rycee ]; + + imports = [ + (mkRenamedOptionModule [ "fonts" "fontconfig" "enableProfileFonts" ] [ + "fonts" + "fontconfig" + "enable" + ]) + ]; + + options = { + fonts.fontconfig = { + enable = mkOption { + type = types.bool; + default = false; + description = '' + Whether to enable fontconfig configuration. This will, for + example, allow fontconfig to discover fonts and + configurations installed through + {var}`home.packages` and + {command}`nix-env`. + ''; + }; + + defaultFonts = { + monospace = mkOption { + type = with types; listOf str; + default = [ ]; + description = '' + Per-user default monospace font(s). Multiple fonts may be listed in + case multiple languages must be supported. + ''; + }; + + sansSerif = mkOption { + type = with types; listOf str; + default = [ ]; + description = '' + Per-user default sans serif font(s). Multiple fonts may be listed + in case multiple languages must be supported. + ''; + }; + + serif = mkOption { + type = with types; listOf str; + default = [ ]; + description = '' + Per-user default serif font(s). Multiple fonts may be listed in + case multiple languages must be supported. + ''; + }; + + emoji = mkOption { + type = with types; listOf str; + default = [ ]; + description = '' + Per-user default emoji font(s). Multiple fonts may be listed in + case a font does not support all emoji. + + Note that fontconfig matches color emoji fonts preferentially, + so if you want to use a black and white font while having + a color font installed (eg. Noto Color Emoji installed alongside + Noto Emoji), fontconfig will still choose the color font even + when it is later in the list. + ''; + }; + }; + }; + }; + + config = mkIf cfg.enable { + home.packages = [ + # Make sure that buildEnv creates a real directory path so that we avoid + # trying to write to a read-only location. + (pkgs.runCommandLocal "dummy-fc-dir1" { } "mkdir -p $out/lib/fontconfig") + (pkgs.runCommandLocal "dummy-fc-dir2" { } "mkdir -p $out/lib/fontconfig") + ]; + + home.extraProfileCommands = '' + if [[ -d $out/lib/X11/fonts || -d $out/share/fonts ]]; then + export FONTCONFIG_FILE="$(pwd)/fonts.conf" + + cat > $FONTCONFIG_FILE << EOF + + + + $out/lib/X11/fonts + $out/share/fonts + $out/lib/fontconfig/cache + + EOF + + ${getBin pkgs.fontconfig}/bin/fc-cache -f + rm -f $out/lib/fontconfig/cache/CACHEDIR.TAG + rmdir --ignore-fail-on-non-empty -p $out/lib/fontconfig/cache + + rm "$FONTCONFIG_FILE" + unset FONTCONFIG_FILE + fi + + # Remove the fontconfig directory if no files were available. + if [[ -d $out/lib/fontconfig ]] ; then + rmdir --ignore-fail-on-non-empty -p $out/lib/fontconfig + fi + ''; + + xdg.configFile = let + mkFontconfigConf = conf: '' + + + + + + + ${conf} + + ''; + in { + "fontconfig/conf.d/10-hm-fonts.conf".text = mkFontconfigConf '' + Add fonts in the Nix user profile + + ${config.home.path}/etc/fonts/conf.d + ${config.home.path}/etc/fonts/fonts.conf + + ${config.home.path}/lib/X11/fonts + ${config.home.path}/share/fonts + ${profileDirectory}/lib/X11/fonts + ${profileDirectory}/share/fonts + + ${config.home.path}/lib/fontconfig/cache + ''; + + "fontconfig/conf.d/52-hm-default-fonts.conf".text = let + genDefault = fonts: name: + optionalString (fonts != [ ]) '' + + ${name} + + ${ + concatStringsSep "" (map (font: '' + ${font} + '') fonts) + } + + + ''; + in mkFontconfigConf '' + + ${genDefault cfg.defaultFonts.sansSerif "sans-serif"} + ${genDefault cfg.defaultFonts.serif "serif"} + ${genDefault cfg.defaultFonts.monospace "monospace"} + ${genDefault cfg.defaultFonts.emoji "emoji"} + ''; + }; + }; +} diff --git a/modules/home-manager/zsh.nix b/modules/home-manager/zsh.nix new file mode 100644 index 0000000..50f8055 --- /dev/null +++ b/modules/home-manager/zsh.nix @@ -0,0 +1,771 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.programs.zsh; + + relToDotDir = file: (optionalString (cfg.dotDir != null) (cfg.dotDir + "/")) + file; + + pluginsDir = if cfg.dotDir != null then + relToDotDir "plugins" else ".zsh/plugins"; + + envVarsStr = config.lib.zsh.exportAll cfg.sessionVariables; + localVarsStr = config.lib.zsh.defineAll cfg.localVariables; + + aliasesStr = concatStringsSep "\n" ( + mapAttrsToList (k: v: "alias -- ${lib.escapeShellArg k}=${lib.escapeShellArg v}") cfg.shellAliases + ); + + dirHashesStr = concatStringsSep "\n" ( + mapAttrsToList (k: v: ''hash -d ${k}="${v}"'') cfg.dirHashes + ); + + zdotdir = "$HOME/" + lib.escapeShellArg cfg.dotDir; + + bindkeyCommands = { + emacs = "bindkey -e"; + viins = "bindkey -v"; + vicmd = "bindkey -a"; + }; + + stateVersion = config.home.stateVersion; + + historyModule = types.submodule ({ config, ... }: { + options = { + append = mkOption { + type = types.bool; + default = false; + description = '' + If set, zsh sessions will append their history list to the history + file, rather than replace it. Thus, multiple parallel zsh sessions + will all have the new entries from their history lists added to the + history file, in the order that they exit. + + This file will still be periodically re-written to trim it when the + number of lines grows 20% beyond the value specified by + `programs.zsh.history.save`. + ''; + }; + + size = mkOption { + type = types.int; + default = 10000; + description = "Number of history lines to keep."; + }; + + save = mkOption { + type = types.int; + defaultText = 10000; + default = config.size; + description = "Number of history lines to save."; + }; + + path = mkOption { + type = types.str; + default = if versionAtLeast stateVersion "20.03" + then "$HOME/.zsh_history" + else relToDotDir ".zsh_history"; + defaultText = literalExpression '' + "$HOME/.zsh_history" if state version ≥ 20.03, + "$ZDOTDIR/.zsh_history" otherwise + ''; + example = literalExpression ''"''${config.xdg.dataHome}/zsh/zsh_history"''; + description = "History file location"; + }; + + ignorePatterns = mkOption { + type = types.listOf types.str; + default = []; + example = literalExpression ''[ "rm *" "pkill *" ]''; + description = '' + Do not enter command lines into the history list + if they match any one of the given shell patterns. + ''; + }; + + ignoreDups = mkOption { + type = types.bool; + default = true; + description = '' + Do not enter command lines into the history list + if they are duplicates of the previous event. + ''; + }; + + ignoreAllDups = mkOption { + type = types.bool; + default = false; + description = '' + If a new command line being added to the history list + duplicates an older one, the older command is removed + from the list (even if it is not the previous event). + ''; + }; + + ignoreSpace = mkOption { + type = types.bool; + default = true; + description = '' + Do not enter command lines into the history list + if the first character is a space. + ''; + }; + + expireDuplicatesFirst = mkOption { + type = types.bool; + default = false; + description = "Expire duplicates first."; + }; + + extended = mkOption { + type = types.bool; + default = false; + description = "Save timestamp into the history file."; + }; + + share = mkOption { + type = types.bool; + default = true; + description = "Share command history between zsh sessions."; + }; + }; + }); + + pluginModule = types.submodule ({ config, ... }: { + options = { + src = mkOption { + type = types.path; + description = '' + Path to the plugin folder. + + Will be added to {env}`fpath` and {env}`PATH`. + ''; + }; + + name = mkOption { + type = types.str; + description = '' + The name of the plugin. + + Don't forget to add {option}`file` + if the script name does not follow convention. + ''; + }; + + file = mkOption { + type = types.str; + description = "The plugin script to source."; + }; + }; + + config.file = mkDefault "${config.name}.plugin.zsh"; + }); + + ohMyZshModule = types.submodule { + options = { + enable = mkEnableOption "oh-my-zsh"; + + package = mkPackageOption pkgs "oh-my-zsh" { }; + + plugins = mkOption { + default = []; + example = [ "git" "sudo" ]; + type = types.listOf types.str; + description = '' + List of oh-my-zsh plugins + ''; + }; + + custom = mkOption { + default = ""; + type = types.str; + example = "$HOME/my_customizations"; + description = '' + Path to a custom oh-my-zsh package to override config of + oh-my-zsh. See + for more information. + ''; + }; + + theme = mkOption { + default = ""; + example = "robbyrussell"; + type = types.str; + description = '' + Name of the theme to be used by oh-my-zsh. + ''; + }; + + extraConfig = mkOption { + default = ""; + example = '' + zstyle :omz:plugins:ssh-agent identities id_rsa id_rsa2 id_github + ''; + type = types.lines; + description = '' + Extra settings for plugins. + ''; + }; + }; + }; + + historySubstringSearchModule = types.submodule { + options = { + enable = mkEnableOption "history substring search"; + searchUpKey = mkOption { + type = with types; either (listOf str) str ; + default = [ "^[[A" ]; + description = '' + The key codes to be used when searching up. + The default of `^[[A` may correspond to the UP key -- if not, try + `$terminfo[kcuu1]`. + ''; + }; + searchDownKey = mkOption { + type = with types; either (listOf str) str ; + default = [ "^[[B" ]; + description = '' + The key codes to be used when searching down. + The default of `^[[B` may correspond to the DOWN key -- if not, try + `$terminfo[kcud1]`. + ''; + }; + }; + }; + + syntaxHighlightingModule = types.submodule { + options = { + enable = mkEnableOption "zsh syntax highlighting"; + + package = mkPackageOption pkgs "zsh-syntax-highlighting" { }; + + highlighters = mkOption { + type = types.listOf types.str; + default = [ ]; + example = [ "brackets" ]; + description = '' + Highlighters to enable + See the list of highlighters: + ''; + }; + + patterns = mkOption { + type = types.attrsOf types.str; + default = {}; + example = { "rm -rf *" = "fg=white,bold,bg=red"; }; + description = '' + Custom syntax highlighting for user-defined patterns. + Reference: + ''; + }; + + styles = mkOption { + type = types.attrsOf types.str; + default = {}; + example = { comment = "fg=black,bold"; }; + description = '' + Custom styles for syntax highlighting. + See each highlighter style option: + ''; + }; + }; + }; + +in + +{ + imports = [ + (mkRenamedOptionModule [ "programs" "zsh" "enableAutosuggestions" ] [ "programs" "zsh" "autosuggestion" "enable" ]) + (mkRenamedOptionModule [ "programs" "zsh" "enableSyntaxHighlighting" ] [ "programs" "zsh" "syntaxHighlighting" "enable" ]) + (mkRenamedOptionModule [ "programs" "zsh" "zproof" ] [ "programs" "zsh" "zprof" ]) + ]; + + options = { + programs.zsh = { + enable = mkEnableOption "Z shell (Zsh)"; + + package = mkPackageOption pkgs "zsh" { }; + + autocd = mkOption { + default = null; + description = '' + Automatically enter into a directory if typed directly into shell. + ''; + type = types.nullOr types.bool; + }; + + cdpath = mkOption { + default = []; + description = '' + List of paths to autocomplete calls to {command}`cd`. + ''; + type = types.listOf types.str; + }; + + dotDir = mkOption { + default = null; + example = ".config/zsh"; + description = '' + Directory where the zsh configuration and more should be located, + relative to the users home directory. The default is the home + directory. + ''; + type = types.nullOr types.str; + }; + + shellAliases = mkOption { + default = {}; + example = literalExpression '' + { + ll = "ls -l"; + ".." = "cd .."; + } + ''; + description = '' + An attribute set that maps aliases (the top level attribute names in + this option) to command strings or directly to build outputs. + ''; + type = types.attrsOf types.str; + }; + + shellGlobalAliases = mkOption { + default = {}; + example = literalExpression '' + { + UUID = "$(uuidgen | tr -d \\n)"; + G = "| grep"; + } + ''; + description = '' + Similar to [](#opt-programs.zsh.shellAliases), + but are substituted anywhere on a line. + ''; + type = types.attrsOf types.str; + }; + + dirHashes = mkOption { + default = {}; + example = literalExpression '' + { + docs = "$HOME/Documents"; + vids = "$HOME/Videos"; + dl = "$HOME/Downloads"; + } + ''; + description = '' + An attribute set that adds to named directory hash table. + ''; + type = types.attrsOf types.str; + }; + + enableCompletion = mkOption { + default = true; + description = '' + Enable zsh completion. Don't forget to add + ```nix + environment.pathsToLink = [ "/share/zsh" ]; + ``` + to your system configuration to get completion for system packages (e.g. systemd). + ''; + type = types.bool; + }; + + completionInit = mkOption { + default = "autoload -U compinit && compinit"; + description = "Initialization commands to run when completion is enabled."; + type = types.lines; + }; + + zprof.enable = mkOption { + default = false; + description = '' + Enable zprof in your zshrc. + ''; + }; + + syntaxHighlighting = mkOption { + type = syntaxHighlightingModule; + default = {}; + description = "Options related to zsh-syntax-highlighting."; + }; + + historySubstringSearch = mkOption { + type = historySubstringSearchModule; + default = {}; + description = "Options related to zsh-history-substring-search."; + }; + + autosuggestion = { + enable = mkOption { + type = types.bool; + default = false; + description = "Enable zsh autosuggestions"; + }; + + highlight = mkOption { + type = types.nullOr types.str; + default = null; + example = "fg=#ff00ff,bg=cyan,bold,underline"; + description = '' + Custom styles for autosuggestion highlighting. See + {manpage}`zshzle(1)` for syntax. + ''; + }; + + strategy = mkOption { + type = types.listOf (types.enum [ "history" "completion" "match_prev_cmd" ]); + default = [ "history" ]; + description = '' + `ZSH_AUTOSUGGEST_STRATEGY` is an array that specifies how suggestions should be generated. + The strategies in the array are tried successively until a suggestion is found. + There are currently three built-in strategies to choose from: + + - `history`: Chooses the most recent match from history. + - `completion`: Chooses a suggestion based on what tab-completion would suggest. (requires `zpty` module) + - `match_prev_cmd`: Like `history`, but chooses the most recent match whose preceding history item matches + the most recently executed command. Note that this strategy won't work as expected with ZSH options that + don't preserve the history order such as `HIST_IGNORE_ALL_DUPS` or `HIST_EXPIRE_DUPS_FIRST`. + + Setting the option to an empty list `[]` will make ZSH_AUTOSUGGESTION_STRATEGY not be set automatically, + allowing the variable to be declared in {option}`programs.zsh.localVariables` or {option}`programs.zsh.sessionVariables` + ''; + }; + }; + + history = mkOption { + type = historyModule; + default = {}; + description = "Options related to commands history configuration."; + }; + + defaultKeymap = mkOption { + type = types.nullOr (types.enum (attrNames bindkeyCommands)); + default = null; + example = "emacs"; + description = "The default base keymap to use."; + }; + + sessionVariables = mkOption { + default = {}; + type = types.attrs; + example = { MAILCHECK = 30; }; + description = "Environment variables that will be set for zsh session."; + }; + + initExtraBeforeCompInit = mkOption { + default = ""; + type = types.lines; + description = "Extra commands that should be added to {file}`.zshrc` before compinit."; + }; + + initExtra = mkOption { + default = ""; + type = types.lines; + description = "Extra commands that should be added to {file}`.zshrc`."; + }; + + initExtraFirst = mkOption { + default = ""; + type = types.lines; + description = "Commands that should be added to top of {file}`.zshrc`."; + }; + + envExtra = mkOption { + default = ""; + type = types.lines; + description = "Extra commands that should be added to {file}`.zshenv`."; + }; + + profileExtra = mkOption { + default = ""; + type = types.lines; + description = "Extra commands that should be added to {file}`.zprofile`."; + }; + + loginExtra = mkOption { + default = ""; + type = types.lines; + description = "Extra commands that should be added to {file}`.zlogin`."; + }; + + logoutExtra = mkOption { + default = ""; + type = types.lines; + description = "Extra commands that should be added to {file}`.zlogout`."; + }; + + plugins = mkOption { + type = types.listOf pluginModule; + default = []; + example = literalExpression '' + [ + { + # will source zsh-autosuggestions.plugin.zsh + name = "zsh-autosuggestions"; + src = pkgs.fetchFromGitHub { + owner = "zsh-users"; + repo = "zsh-autosuggestions"; + rev = "v0.4.0"; + sha256 = "0z6i9wjjklb4lvr7zjhbphibsyx51psv50gm07mbb0kj9058j6kc"; + }; + } + { + name = "enhancd"; + file = "init.sh"; + src = pkgs.fetchFromGitHub { + owner = "b4b4r07"; + repo = "enhancd"; + rev = "v2.2.1"; + sha256 = "0iqa9j09fwm6nj5rpip87x3hnvbbz9w9ajgm6wkrd5fls8fn8i5g"; + }; + } + ] + ''; + description = "Plugins to source in {file}`.zshrc`."; + }; + + oh-my-zsh = mkOption { + type = ohMyZshModule; + default = {}; + description = "Options to configure oh-my-zsh."; + }; + + localVariables = mkOption { + type = types.attrs; + default = {}; + example = { POWERLEVEL9K_LEFT_PROMPT_ELEMENTS=["dir" "vcs"]; }; + description = '' + Extra local variables defined at the top of {file}`.zshrc`. + ''; + }; + }; + }; + + config = mkIf cfg.enable (mkMerge [ + (mkIf (cfg.envExtra != "") { + home.file."${relToDotDir ".zshenv"}".text = cfg.envExtra; + }) + + (mkIf (cfg.profileExtra != "") { + home.file."${relToDotDir ".zprofile"}".text = cfg.profileExtra; + }) + + (mkIf (cfg.loginExtra != "") { + home.file."${relToDotDir ".zlogin"}".text = cfg.loginExtra; + }) + + (mkIf (cfg.logoutExtra != "") { + home.file."${relToDotDir ".zlogout"}".text = cfg.logoutExtra; + }) + + (mkIf cfg.oh-my-zsh.enable { + home.file."${relToDotDir ".zshenv"}".text = '' + ZSH="${cfg.oh-my-zsh.package}/share/oh-my-zsh"; + ZSH_CACHE_DIR="${config.xdg.cacheHome}/oh-my-zsh"; + ''; + }) + + (mkIf (cfg.dotDir != null) { + home.file."${relToDotDir ".zshenv"}".text = '' + export ZDOTDIR=${zdotdir} + ''; + + # When dotDir is set, only use ~/.zshenv to source ZDOTDIR/.zshenv, + # This is so that if ZDOTDIR happens to be + # already set correctly (by e.g. spawning a zsh inside a zsh), all env + # vars still get exported + home.file.".zshenv".text = '' + source ${zdotdir}/.zshenv + ''; + }) + + { + home.file."${relToDotDir ".zshenv"}".text = '' + # Environment variables + . "${config.home.profileDirectory}/etc/profile.d/hm-session-vars.sh" + + # Only source this once + if [[ -z "$__HM_ZSH_SESS_VARS_SOURCED" ]]; then + export __HM_ZSH_SESS_VARS_SOURCED=1 + ${envVarsStr} + fi + ''; + } + + { + home.packages = [ cfg.package ] + ++ optional cfg.enableCompletion pkgs.nix-zsh-completions + ++ optional cfg.oh-my-zsh.enable cfg.oh-my-zsh.package; + + home.file."${relToDotDir ".zshrc"}".text = concatStringsSep "\n" ([ + # zprof must be loaded before everything else, since it + # benchmarks the shell initialization. + (optionalString cfg.zprof.enable '' + zmodload zsh/zprof + '') + + cfg.initExtraFirst + "typeset -U path cdpath fpath manpath" + + (optionalString (cfg.cdpath != []) '' + cdpath+=(${concatStringsSep " " cfg.cdpath}) + '') + + '' + for profile in ''${(z)NIX_PROFILES}; do + fpath+=($profile/share/zsh/site-functions $profile/share/zsh/$ZSH_VERSION/functions $profile/share/zsh/vendor-completions) + done + + HELPDIR="${cfg.package}/share/zsh/$ZSH_VERSION/help" + '' + + (optionalString (cfg.defaultKeymap != null) '' + # Use ${cfg.defaultKeymap} keymap as the default. + ${getAttr cfg.defaultKeymap bindkeyCommands} + '') + localVarsStr + + cfg.initExtraBeforeCompInit + + (concatStrings (map (plugin: '' + path+="$HOME/${pluginsDir}/${plugin.name}" + fpath+="$HOME/${pluginsDir}/${plugin.name}" + '') cfg.plugins)) + + '' + # Oh-My-Zsh/Prezto calls compinit during initialization, + # calling it twice causes slight start up slowdown + # as all $fpath entries will be traversed again. + ${optionalString (cfg.enableCompletion && !cfg.oh-my-zsh.enable && !cfg.prezto.enable) + cfg.completionInit + }'' + + (optionalString cfg.autosuggestion.enable '' + source ${pkgs.zsh-autosuggestions}/share/zsh-autosuggestions/zsh-autosuggestions.zsh + ${optionalString (cfg.autosuggestion.strategy != []) '' + ZSH_AUTOSUGGEST_STRATEGY=(${concatStringsSep " " cfg.autosuggestion.strategy}) + '' + } + '') + (optionalString (cfg.autosuggestion.enable && cfg.autosuggestion.highlight != null) '' + ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE="${cfg.autosuggestion.highlight}" + '') + + (optionalString cfg.oh-my-zsh.enable '' + # oh-my-zsh extra settings for plugins + ${cfg.oh-my-zsh.extraConfig} + # oh-my-zsh configuration generated by NixOS + ${optionalString (cfg.oh-my-zsh.plugins != []) + "plugins=(${concatStringsSep " " cfg.oh-my-zsh.plugins})" + } + ${optionalString (cfg.oh-my-zsh.custom != "") + "ZSH_CUSTOM=\"${cfg.oh-my-zsh.custom}\"" + } + ${optionalString (cfg.oh-my-zsh.theme != "") + "ZSH_THEME=\"${cfg.oh-my-zsh.theme}\"" + } + source $ZSH/oh-my-zsh.sh + '') + + '' + ${optionalString cfg.prezto.enable + (builtins.readFile "${pkgs.zsh-prezto}/share/zsh-prezto/runcoms/zshrc")} + + ${concatStrings (map (plugin: '' + if [[ -f "$HOME/${pluginsDir}/${plugin.name}/${plugin.file}" ]]; then + source "$HOME/${pluginsDir}/${plugin.name}/${plugin.file}" + fi + '') cfg.plugins)} + + # History options should be set in .zshrc and after oh-my-zsh sourcing. + # See https://github.com/nix-community/home-manager/issues/177. + HISTSIZE="${toString cfg.history.size}" + SAVEHIST="${toString cfg.history.save}" + ${optionalString (cfg.history.ignorePatterns != []) "HISTORY_IGNORE=${lib.escapeShellArg "(${lib.concatStringsSep "|" cfg.history.ignorePatterns})"}"} + ${if versionAtLeast config.home.stateVersion "20.03" + then ''HISTFILE="${cfg.history.path}"'' + else ''HISTFILE="$HOME/${cfg.history.path}"''} + mkdir -p "$(dirname "$HISTFILE")" + + setopt HIST_FCNTL_LOCK + ${if cfg.history.append then "setopt" else "unsetopt"} APPEND_HISTORY + ${if cfg.history.ignoreDups then "setopt" else "unsetopt"} HIST_IGNORE_DUPS + ${if cfg.history.ignoreAllDups then "setopt" else "unsetopt"} HIST_IGNORE_ALL_DUPS + ${if cfg.history.ignoreSpace then "setopt" else "unsetopt"} HIST_IGNORE_SPACE + ${if cfg.history.expireDuplicatesFirst then "setopt" else "unsetopt"} HIST_EXPIRE_DUPS_FIRST + ${if cfg.history.share then "setopt" else "unsetopt"} SHARE_HISTORY + ${if cfg.history.extended then "setopt" else "unsetopt"} EXTENDED_HISTORY + ${if cfg.autocd != null then "${if cfg.autocd then "setopt" else "unsetopt"} autocd" else ""} + + ${cfg.initExtra} + + # Aliases + ${aliasesStr} + '' + ] + ++ (mapAttrsToList (k: v: "alias -g -- ${lib.escapeShellArg k}=${lib.escapeShellArg v}") cfg.shellGlobalAliases) + ++ [ ('' + # Named Directory Hashes + ${dirHashesStr} + '') + + (optionalString cfg.syntaxHighlighting.enable + # Load zsh-syntax-highlighting after all custom widgets have been created + # https://github.com/zsh-users/zsh-syntax-highlighting#faq + '' + source ${cfg.syntaxHighlighting.package}/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh + ZSH_HIGHLIGHT_HIGHLIGHTERS+=(${lib.concatStringsSep " " (map lib.escapeShellArg cfg.syntaxHighlighting.highlighters)}) + ${lib.concatStringsSep "\n" ( + lib.mapAttrsToList + (name: value: "ZSH_HIGHLIGHT_STYLES+=(${lib.escapeShellArg name} ${lib.escapeShellArg value})") + cfg.syntaxHighlighting.styles + )} + ${lib.concatStringsSep "\n" ( + lib.mapAttrsToList + (name: value: "ZSH_HIGHLIGHT_PATTERNS+=(${lib.escapeShellArg name} ${lib.escapeShellArg value})") + cfg.syntaxHighlighting.patterns + )} + '') + + (optionalString (cfg.historySubstringSearch.enable or false) + # Load zsh-history-substring-search after zsh-syntax-highlighting + # https://github.com/zsh-users/zsh-history-substring-search#usage + '' + source ${pkgs.zsh-history-substring-search}/share/zsh-history-substring-search/zsh-history-substring-search.zsh + ${lib.concatMapStringsSep "\n" + (upKey: "bindkey \"${upKey}\" history-substring-search-up") + (lib.toList cfg.historySubstringSearch.searchUpKey) + } + ${lib.concatMapStringsSep "\n" + (downKey: "bindkey \"${downKey}\" history-substring-search-down") + (lib.toList cfg.historySubstringSearch.searchDownKey) + } + '') + + (optionalString cfg.zprof.enable + '' + zprof + '') + ]); + } + + (mkIf cfg.oh-my-zsh.enable { + # Make sure we create a cache directory since some plugins expect it to exist + # See: https://github.com/nix-community/home-manager/issues/761 + home.file."${config.xdg.cacheHome}/oh-my-zsh/.keep".text = ""; + }) + + (mkIf (cfg.plugins != []) { + # Many plugins require compinit to be called + # but allow the user to opt out. + programs.zsh.enableCompletion = mkDefault true; + + home.file = + foldl' (a: b: a // b) {} + (map (plugin: { "${pluginsDir}/${plugin.name}".source = plugin.src; }) + cfg.plugins); + }) + ]); +} diff --git a/nixos/configuration.nix b/nixos/configuration.nix index b3251ed..3a92e3f 100644 --- a/nixos/configuration.nix +++ b/nixos/configuration.nix @@ -24,10 +24,21 @@ # Import your generated (nixos-generate-config) hardware configuration ./hardware-configuration.nix + # Import home-manager's NixOS module + inputs.home-manager.nixosModules.home-manager + # Import system packages ./pkgs.nix ]; + home-manager = { + extraSpecialArgs = { inherit inputs outputs; }; + users = { + # Import your home-manager configuration + chloe = import ../home-manager/home.nix; + }; + }; + nixpkgs = { # You can add overlays here overlays = [ @@ -121,6 +132,7 @@ users.users = { chloe = { isNormalUser = true; + shell = pkgs.zsh; openssh.authorizedKeys.keys = [ # TODO: Add your SSH public key(s) here, if you plan on using SSH to connect ]; @@ -128,6 +140,9 @@ }; }; + programs.zsh.enable = true; + + # This setups a SSH server. Very important if you're setting up a headless system. # Feel free to remove if you don't need it. services.openssh = { diff --git a/nixos/pkgs.nix b/nixos/pkgs.nix index 23d0bfe..fcc3998 100644 --- a/nixos/pkgs.nix +++ b/nixos/pkgs.nix @@ -1,5 +1,5 @@ { pkgs, ... } : { environment.systemPackages = with pkgs; [ - home-manager zsh refind python314 unzip zip git gnumake apostrophe gnome-tweaks gnomeExtensions.user-themes dissent + home-manager zsh refind python314 unzip zip git gnumake apostrophe gnome-tweaks gnomeExtensions.user-themes dissent tuba ]; } diff --git a/overlays/default.nix b/overlays/default.nix index 7bfcb4c..c1f2aff 100644 --- a/overlays/default.nix +++ b/overlays/default.nix @@ -7,9 +7,6 @@ # You can change versions, add patches, set compilation flags, anything really. # https://nixos.wiki/wiki/Overlays modifications = final: prev: { - # example = prev.example.overrideAttrs (oldAttrs: rec { - # ... - # }); }; # When applied, the unstable nixpkgs set (declared in the flake inputs) will